PR #23320 opened by yuyong05
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23320
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23320.patch

      This would otherwise cause the DTS timeline counter to overshoot the edit
      list segment duration, producing Time-To-Sample (TTS / STTS) table entries
      with incorrect durations.

      This didn't cause any issues previously for standard framerates where the
      overshoot was negligible, but for low-framerate videos, the discrepancy
      became large enough to disrupt audio/video sync and fail transcoding
      duration validation.

      To generate test file:
        ffmpeg -f lavfi -i color=c=blue:s=854x480 -frames:v 1 pixel.png -y
        ffmpeg -loop 1 -r 1/15 -i pixel.png -f lavfi -i 
anullsrc=r=44100:cl=stereo \
          -t 200 -c:v libx264 -c:a pcm_s16le -pix_fmt yuv420p raw_200s.mov -y
        ffmpeg -ss 0 -t 15 -i raw_200s.mov -i raw_200s.mov -map 0:v -map 1:a \
          -c copy output.mov -y

      To verify (Before Fix):
        1. Remux output using unfixed ffmpeg:
           unfixed_ffmpeg -i output.mov -c copy remuxed_unfixed.mov -y
        2. Inspect the video stream duration:
           unfixed_ffprobe -v error -show_entries 
format=duration:stream=duration \
             -of default=noprint_wrappers=1 remuxed_unfixed.mov

      To verify (After Fix):
        1. Remux output using fixed ffmpeg:
           fixed_ffmpeg -i output.mov -c copy remuxed_fixed.mov -y
        2. Inspect the video stream duration:
           fixed_ffprobe -v error -show_entries format=duration:stream=duration 
\
             -of default=noprint_wrappers=1 remuxed_fixed.mov

      Verification results summary:
        
+--------------------+-----------------------+---------------------------+-----------------------+
        | Version            | Video Stream Duration | Last Packet 
duration_time | Remux Completion Time |
        
+--------------------+-----------------------+---------------------------+-----------------------+
        | Unfixed (Reverted) | 45.000000 seconds     | 15.000000 seconds        
 | time=00:00:15.00      |
        | Fixed              | 75.000000 seconds     | 45.000000 seconds        
 | time=00:00:45.00      |
        
+--------------------+-----------------------+---------------------------+-----------------------+

# Summary of changes

Briefly describe what this PR does and why.

<!--
If this PR requires new FATE test samples, attach them to the PR and
list their target paths below (relative to the fate-suite root).

Attached filenames must match the sample's filename:

```fate-samples
# e.g. vorbis/new-sample.ogg
```
-->



>From 14a4643e49b5b03f2b7a66aeeec393f20ede464c Mon Sep 17 00:00:00 2001
From: Yong Yu <[email protected]>
Date: Wed, 3 Jun 2026 15:57:02 +0000
Subject: [PATCH]   avformat/mov: fix DTS overshoot and TTS duration mismatches

      This would otherwise cause the DTS timeline counter to overshoot the edit
      list segment duration, producing Time-To-Sample (TTS / STTS) table entries
      with incorrect durations.

      This didn't cause any issues previously for standard framerates where the
      overshoot was negligible, but for low-framerate videos, the discrepancy
      became large enough to disrupt audio/video sync and fail transcoding
      duration validation.

      To generate test file:
        ffmpeg -f lavfi -i color=c=blue:s=854x480 -frames:v 1 pixel.png -y
        ffmpeg -loop 1 -r 1/15 -i pixel.png -f lavfi -i 
anullsrc=r=44100:cl=stereo \
          -t 200 -c:v libx264 -c:a pcm_s16le -pix_fmt yuv420p raw_200s.mov -y
        ffmpeg -ss 0 -t 15 -i raw_200s.mov -i raw_200s.mov -map 0:v -map 1:a \
          -c copy output.mov -y

      To verify (Before Fix):
        1. Remux output using unfixed ffmpeg:
           unfixed_ffmpeg -i output.mov -c copy remuxed_unfixed.mov -y
        2. Inspect the video stream duration:
           unfixed_ffprobe -v error -show_entries 
format=duration:stream=duration \
             -of default=noprint_wrappers=1 remuxed_unfixed.mov

      To verify (After Fix):
        1. Remux output using fixed ffmpeg:
           fixed_ffmpeg -i output.mov -c copy remuxed_fixed.mov -y
        2. Inspect the video stream duration:
           fixed_ffprobe -v error -show_entries format=duration:stream=duration 
\
             -of default=noprint_wrappers=1 remuxed_fixed.mov

      Verification results summary:
        
+--------------------+-----------------------+---------------------------+-----------------------+
        | Version            | Video Stream Duration | Last Packet 
duration_time | Remux Completion Time |
        
+--------------------+-----------------------+---------------------------+-----------------------+
        | Unfixed (Reverted) | 45.000000 seconds     | 15.000000 seconds        
 | time=00:00:15.00      |
        | Fixed              | 75.000000 seconds     | 45.000000 seconds        
 | time=00:00:45.00      |
        
+--------------------+-----------------------+---------------------------+-----------------------+
---
 libavformat/mov.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libavformat/mov.c b/libavformat/mov.c
index 46dac965a2..89126b6b53 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4385,6 +4385,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
             // check  if frame outside edit list mark it for discard
             frame_duration = (current + 1 <  e_old_end) ?
                              ((current + 1)->timestamp - current->timestamp) : 
edit_list_duration;
+            frame_duration = FFMIN(frame_duration, FFMAX(0, 
edit_list_dts_entry_end - edit_list_dts_counter));
 
             flags = current->flags;
 
@@ -4402,7 +4403,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
                     if (add_tts_entry(&msc->tts_data, &msc->tts_count,
                                        &msc->tts_allocated_size,
                                        tts_data_old[tts_index_old].count - 
edit_list_start_tts_sample,
-                                       tts_data_old[tts_index_old].offset, 
tts_data_old[tts_index_old].duration) == -1) {
+                                       tts_data_old[tts_index_old].offset, 
frame_duration) == -1) {
                         av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To 
Sample entry %"PRId64" - {%"PRId64", %d}\n",
                                tts_index_old,
                                tts_data_old[tts_index_old].count - 
edit_list_start_tts_sample,
@@ -4509,7 +4510,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
                         if (add_tts_entry(&msc->tts_data, &msc->tts_count,
                                            &msc->tts_allocated_size,
                                            tts_sample_old - 
edit_list_start_tts_sample,
-                                           tts_data_old[tts_index_old].offset, 
tts_data_old[tts_index_old].duration) == -1) {
+                                           tts_data_old[tts_index_old].offset, 
frame_duration) == -1) {
                             av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To 
Sample entry %"PRId64" - {%"PRId64", %d}\n",
                                    tts_index_old, tts_sample_old - 
edit_list_start_tts_sample,
                                    tts_data_old[tts_index_old].offset);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to