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

# Summary of changes

The MOVTimeToSample* tts_data member variable in struct MOVContext has two 
problems. First, its 12-byte size means that the mov.c (de)muxer cannot support 
audio clips with more than approximately 319 million samples, which is just 
over 2 hours at 48khz. Also, it contains storage space for a 'count' member and 
there is business logic in mov.c to handle tts_data sample entries supporting 
groups with count greater than 1, but this is unnecessary because in the table 
creation logic, all entries have a count equal to 1. To improve the audio 
sample count limit by a factor of 3, this change removes the tts_data struct 
table and replaces it with two int-sized tables, one called 
tts_offset_by_sample and another called tts_duration_by_sample. The business 
logic in mov.c is also refactored to simplify for the removed count variable, 
which is implictly always 1.


>From 4788d5242ba8ea591a96bcf42d69fbe43e5f0a88 Mon Sep 17 00:00:00 2001
From: Richard Goedeken <[email protected]>
Date: Wed, 14 Oct 2026 13:52:06 -0700
Subject: [PATCH] avformat/mov: use two integer arrays instead of
 MOVTimeToSample structure

---
 libavformat/isom.h |  13 +-
 libavformat/mov.c  | 319 ++++++++++++++++++++-------------------------
 2 files changed, 146 insertions(+), 186 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 42a124edb3..7475a059a9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -55,12 +55,6 @@ struct AVAESCTR;
  * Here we just use what is needed to read the chunks
  */
 
-typedef struct MOVTimeToSample {
-    unsigned int count;
-    unsigned int duration;
-    int offset;
-} MOVTimeToSample;
-
 typedef struct MOVStts {
     unsigned int count;
     unsigned int duration;
@@ -187,8 +181,10 @@ typedef struct MOVStreamContext {
     unsigned int chunk_count;
     int64_t *chunk_offsets;
     unsigned int tts_count;
-    unsigned int tts_allocated_size;
-    MOVTimeToSample *tts_data;
+    unsigned int tts_offset_allocated_size;
+    int *tts_offset_by_sample;
+    unsigned int tts_duration_allocated_size;
+    unsigned int *tts_duration_by_sample;
     unsigned int stts_count;
     unsigned int stts_allocated_size;
     MOVStts *stts_data;
@@ -206,7 +202,6 @@ typedef struct MOVStreamContext {
     MOVElst *elst_data;
     unsigned int elst_count;
     int tts_index;
-    int tts_sample;
     unsigned int sample_size; ///< may contain value calculated from stsd or 
value from stsz atom
     unsigned int stsz_sample_size; ///< always contains sample size from stsz 
atom
     unsigned int sample_count;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index a89747666b..e4d3a56483 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4215,7 +4215,7 @@ static int get_edit_list_entry(MOVContext *mov,
  * Find the closest previous frame to the timestamp_pts, in e_old index
  * entries. Searching for just any frame / just key frames can be controlled by
  * last argument 'flag'.
- * Note that if ctts_data is not NULL, we will always search for a key frame
+ * Note that if composition offsets are present, we will always search for a 
key frame
  * irrespective of the value of 'flag'. If we don't find any keyframe, we will
  * return the first frame of the video.
  *
@@ -4225,21 +4225,20 @@ static int get_edit_list_entry(MOVContext *mov,
  * Returns 0 if successful in finding a frame, else returns -1.
  * Places the found index corresponding output arg.
  *
- * If ctts_old is not NULL, then refines the searched entry by searching
+ * If composition offsets are present, then refines the searched entry by 
searching
  * backwards from the found timestamp, to find the frame with correct PTS.
  *
- * Places the found ctts_index and ctts_sample in corresponding output args.
+ * Places the found tts index in the corresponding output arg.
  */
 static int find_prev_closest_index(AVStream *st,
                                    AVIndexEntry *e_old,
                                    int nb_old,
-                                   MOVTimeToSample *tts_data,
+                                   const int *tts_offset_by_sample,
                                    int64_t tts_count,
                                    int64_t timestamp_pts,
                                    int flag,
                                    int64_t* index,
-                                   int64_t* tts_index,
-                                   int64_t* tts_sample)
+                                   int64_t* tts_index)
 {
     MOVStreamContext *msc = st->priv_data;
     FFStream *const sti = ffstream(st);
@@ -4275,28 +4274,20 @@ static int find_prev_closest_index(AVStream *st,
     // computed by adding corresponding CTTS durations to index timestamps.
     if (msc->ctts_count && *index >= 0) {
         av_assert0(tts_index);
-        av_assert0(tts_sample);
         // Find out the ctts_index for the found frame.
         *tts_index = FFMIN(*index, tts_count);
-        *tts_sample = 0;
 
         while (*index >= 0 && (*tts_index) >= 0 && (*tts_index) < tts_count) {
             // Find a "key frame" with PTS <= timestamp_pts (So that we can 
decode B-frames correctly).
             // No need to add dts_shift to the timestamp here because 
timestamp_pts has already been
             // compensated by dts_shift above.
-            if ((e_old[*index].timestamp + tts_data[*tts_index].offset) <= 
timestamp_pts &&
+            if ((e_old[*index].timestamp + tts_offset_by_sample[*tts_index]) 
<= timestamp_pts &&
                 (e_old[*index].flags & AVINDEX_KEYFRAME)) {
                 break;
             }
 
             (*index)--;
-            if (*tts_sample == 0) {
-                (*tts_index)--;
-                if (*tts_index >= 0)
-                  *tts_sample = tts_data[*tts_index].count - 1;
-            } else {
-                (*tts_sample)--;
-            }
+            (*tts_index)--;
         }
     }
 
@@ -4370,31 +4361,30 @@ static void fix_index_entry_timestamps(AVStream* st, 
int end_index, int64_t end_
     }
 }
 
-static int add_tts_entry(MOVTimeToSample **tts_data, unsigned int *tts_count, 
unsigned int *allocated_size,
-                         int count, int offset, unsigned int duration)
+static int add_tts_entry(MOVStreamContext *sc, int offset, unsigned int 
duration)
 {
-    MOVTimeToSample *tts_buf_new;
-    const size_t min_size_needed = (*tts_count + 1) * sizeof(MOVTimeToSample);
-    const size_t requested_size =
-        min_size_needed > *allocated_size ?
-        FFMAX(min_size_needed, 2 * (*allocated_size)) :
-        min_size_needed;
+    const size_t min_size_needed = ((size_t)sc->tts_count + 1) * 
sizeof(*sc->tts_offset_by_sample);
+    int *offsets;
+    unsigned int *durations;
 
-    if ((unsigned)(*tts_count) >= UINT_MAX / sizeof(MOVTimeToSample) - 1)
+    if (sc->tts_count >= UINT_MAX / sizeof(*sc->tts_offset_by_sample) - 1)
         return -1;
 
-    tts_buf_new = av_fast_realloc(*tts_data, allocated_size, requested_size);
-
-    if (!tts_buf_new)
+    offsets = av_fast_realloc(sc->tts_offset_by_sample, 
&sc->tts_offset_allocated_size,
+                              min_size_needed);
+    if (!offsets)
         return -1;
+    sc->tts_offset_by_sample = offsets;
 
-    *tts_data = tts_buf_new;
+    durations = av_fast_realloc(sc->tts_duration_by_sample, 
&sc->tts_duration_allocated_size,
+                                 min_size_needed);
+    if (!durations)
+        return -1;
+    sc->tts_duration_by_sample = durations;
 
-    tts_buf_new[*tts_count].count = count;
-    tts_buf_new[*tts_count].offset = offset;
-    tts_buf_new[*tts_count].duration = duration;
-
-    *tts_count = (*tts_count) + 1;
+    sc->tts_offset_by_sample[sc->tts_count] = offset;
+    sc->tts_duration_by_sample[sc->tts_count] = duration;
+    sc->tts_count++;
     return 0;
 }
 
@@ -4404,7 +4394,6 @@ static void mov_estimate_video_delay(MOVContext *c, 
AVStream* st)
     MOVStreamContext *msc = st->priv_data;
     FFStream *const sti = ffstream(st);
     int ctts_ind = 0;
-    int ctts_sample = 0;
     int64_t pts_buf[MAX_REORDER_DELAY + 1]; // Circular buffer to sort pts.
     int buf_start = 0;
     int j, r, num_swaps;
@@ -4422,7 +4411,7 @@ static void mov_estimate_video_delay(MOVContext *c, 
AVStream* st)
             if (buf_start == MAX_REORDER_DELAY + 1)
                 buf_start = 0;
 
-            pts_buf[j] = sti->index_entries[ind].timestamp + 
msc->tts_data[ctts_ind].offset;
+            pts_buf[j] = sti->index_entries[ind].timestamp + 
msc->tts_offset_by_sample[ctts_ind];
 
             // The timestamps that are already in the sorted buffer, and are 
greater than the
             // current pts, are exactly the timestamps that need to be 
buffered to output PTS
@@ -4444,11 +4433,7 @@ static void mov_estimate_video_delay(MOVContext *c, 
AVStream* st)
             }
             st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, 
num_swaps);
 
-            ctts_sample++;
-            if (ctts_sample == msc->tts_data[ctts_ind].count) {
-                ctts_ind++;
-                ctts_sample = 0;
-            }
+            ctts_ind++;
         }
         av_log(c->fc, AV_LOG_DEBUG, "Setting codecpar->delay to %d for stream 
st: %d\n",
                st->codecpar->video_delay, st->index);
@@ -4515,16 +4500,15 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
     int nb_old = sti->nb_index_entries;
     const AVIndexEntry *e_old_end = e_old + nb_old;
     const AVIndexEntry *current = NULL;
-    MOVTimeToSample *tts_data_old = msc->tts_data;
+    int *tts_offset_old = msc->tts_offset_by_sample;
+    unsigned int *tts_duration_old = msc->tts_duration_by_sample;
     int64_t tts_index_old = 0;
-    int64_t tts_sample_old = 0;
     int64_t tts_count_old = msc->tts_count;
     int64_t edit_list_media_time = 0;
     int64_t edit_list_duration = 0;
     int64_t frame_duration = 0;
     int64_t edit_list_dts_counter = 0;
     int64_t edit_list_dts_entry_end = 0;
-    int64_t edit_list_start_tts_sample = 0;
     int64_t curr_cts;
     int64_t curr_ctts = 0;
     int64_t empty_edits_sum_duration = 0;
@@ -4563,11 +4547,12 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
     sti->nb_index_entries = 0;
 
     // Clean time to sample fields of MOVStreamContext
-    msc->tts_data = NULL;
+    msc->tts_offset_by_sample = NULL;
+    msc->tts_duration_by_sample = NULL;
     msc->tts_count = 0;
     msc->tts_index = 0;
-    msc->tts_sample = 0;
-    msc->tts_allocated_size = 0;
+    msc->tts_offset_allocated_size = 0;
+    msc->tts_duration_allocated_size = 0;
 
     // Reinitialize min_corrected_pts so that it can be computed again.
     msc->min_corrected_pts = -1;
@@ -4626,23 +4611,21 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
             search_timestamp = FFMAX(av_sat_sub64(search_timestamp, 
msc->time_scale), e_old[0].timestamp);
         }
 
-        if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, 
tts_count_old, search_timestamp, 0,
-                                    &index, &tts_index_old, &tts_sample_old) < 
0) {
+        if (find_prev_closest_index(st, e_old, nb_old, tts_offset_old, 
tts_count_old, search_timestamp, 0,
+                                    &index, &tts_index_old) < 0) {
             av_log(mov->fc, AV_LOG_WARNING,
                    "st: %d edit list: %"PRId64" Missing key frame while 
searching for timestamp: %"PRId64"\n",
                    st->index, edit_list_index, search_timestamp);
-            if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, 
tts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
-                                        &index, &tts_index_old, 
&tts_sample_old) < 0) {
+            if (find_prev_closest_index(st, e_old, nb_old, tts_offset_old, 
tts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
+                                        &index, &tts_index_old) < 0) {
                 av_log(mov->fc, AV_LOG_WARNING,
                        "st: %d edit list %"PRId64" Cannot find an index entry 
before timestamp: %"PRId64".\n",
                        st->index, edit_list_index, search_timestamp);
                 index = 0;
                 tts_index_old = 0;
-                tts_sample_old = 0;
             }
         }
         current = e_old + index;
-        edit_list_start_tts_sample = tts_sample_old;
 
         // Iterate over index and arrange it according to edit list
         edit_list_start_encountered = 0;
@@ -4663,27 +4646,18 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
             curr_cts = current->timestamp + msc->dts_shift;
             curr_ctts = 0;
 
-            if (tts_data_old && tts_index_old < tts_count_old) {
-                curr_ctts = tts_data_old[tts_index_old].offset;
+            if ((tts_offset_old || tts_duration_old) && tts_index_old < 
tts_count_old) {
+                curr_ctts = tts_offset_old ? tts_offset_old[tts_index_old] : 0;
                 av_log(mov->fc, AV_LOG_TRACE, "stts: %"PRId64" ctts: 
%"PRId64", tts_index: %"PRId64", tts_count: %"PRId64"\n",
                        curr_cts, curr_ctts, tts_index_old, tts_count_old);
                 curr_cts += curr_ctts;
-                tts_sample_old++;
-                if (tts_sample_old == tts_data_old[tts_index_old].count) {
-                    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) {
-                        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,
-                               tts_data_old[tts_index_old].offset);
-                        break;
-                    }
-                    tts_index_old++;
-                    tts_sample_old = 0;
-                    edit_list_start_tts_sample = 0;
+                if (add_tts_entry(msc, curr_ctts,
+                                  tts_duration_old ? 
tts_duration_old[tts_index_old] : 0) < 0) {
+                    av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To Sample 
entry %"PRId64" - {%d}\n",
+                           tts_index_old, (int)curr_ctts);
+                    break;
                 }
+                tts_index_old++;
             }
 
             if (curr_cts < edit_list_media_time || curr_cts >= 
(edit_list_duration + edit_list_media_time)) {
@@ -4775,17 +4749,6 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
                         found_keyframe_after_edit = 1;
                         continue;
                     }
-                    if (tts_sample_old != 0) {
-                        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) {
-                            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);
-                            break;
-                        }
-                    }
                 }
                 break;
             }
@@ -4814,7 +4777,8 @@ truncated:
 
     // Free the old index and the old CTTS structures
     av_free(e_old);
-    av_free(tts_data_old);
+    av_free(tts_offset_old);
+    av_free(tts_duration_old);
     av_freep(&frame_duration_buffer);
 
     // Null terminate the index ranges array
@@ -4899,7 +4863,7 @@ static int build_open_gop_key_points(AVStream *st)
 #define MOV_MERGE_CTTS 1
 #define MOV_MERGE_STTS 2
 /*
- * Merge stts and ctts arrays into a new combined array.
+ * Expand stts and ctts entries into per-sample arrays.
  * stts_count and ctts_count may be left untouched as they will be
  * used to check for the presence of either of them.
  */
@@ -4913,23 +4877,22 @@ static int mov_merge_tts_data(MOVContext *mov, AVStream 
*st, int flags)
     if (!sc->ctts_data && !sc->stts_data)
         return 0;
     // Expand time to sample entries such that we have a 1-1 mapping with 
samples
-    if (!sc->sample_count || sc->sample_count >= UINT_MAX / 
sizeof(*sc->tts_data))
+    if (!sc->sample_count || sc->sample_count >= UINT_MAX / 
sizeof(*sc->tts_offset_by_sample))
         return -1;
 
     if (ctts) {
-        sc->tts_data = av_fast_realloc(NULL, &sc->tts_allocated_size,
-                                       sc->sample_count * 
sizeof(*sc->tts_data));
-        if (!sc->tts_data)
+        sc->tts_offset_by_sample = av_fast_realloc(NULL, 
&sc->tts_offset_allocated_size,
+                                                   sc->sample_count * 
sizeof(*sc->tts_offset_by_sample));
+        if (!sc->tts_offset_by_sample)
             return -1;
 
-        memset(sc->tts_data, 0, sc->tts_allocated_size);
+        memset(sc->tts_offset_by_sample, 0, sc->tts_offset_allocated_size);
 
         for (int i = 0; i < sc->ctts_count &&
                     idx < sc->sample_count; i++)
             for (int j = 0; j < sc->ctts_data[i].count &&
                         idx < sc->sample_count; j++) {
-                sc->tts_data[idx].offset = sc->ctts_data[i].offset;
-                sc->tts_data[idx++].count = 1;
+                sc->tts_offset_by_sample[idx++] = sc->ctts_data[i].offset;
             }
 
         sc->tts_count = idx;
@@ -4940,21 +4903,19 @@ static int mov_merge_tts_data(MOVContext *mov, AVStream 
*st, int flags)
 
     idx = 0;
     if (stts) {
-        MOVTimeToSample *tts_data = av_fast_realloc(sc->tts_data, 
&sc->tts_allocated_size,
-                                                    sc->sample_count * 
sizeof(*sc->tts_data));
-        if (!tts_data)
+        unsigned int *durations = av_fast_realloc(NULL, 
&sc->tts_duration_allocated_size,
+                                                  sc->sample_count * 
sizeof(*sc->tts_duration_by_sample));
+        if (!durations)
             return -1;
 
-        if (!sc->tts_data)
-            memset(tts_data, 0, sc->tts_allocated_size);
-        sc->tts_data = tts_data;
+        memset(durations, 0, sc->tts_duration_allocated_size);
+        sc->tts_duration_by_sample = durations;
 
         for (int i = 0; i < sc->stts_count &&
                     idx < sc->sample_count; i++)
             for (int j = 0; j < sc->stts_data[i].count &&
                         idx < sc->sample_count; j++) {
-                sc->tts_data[idx].duration = sc->stts_data[i].duration;
-                sc->tts_data[idx++].count = 1;
+                sc->tts_duration_by_sample[idx++] = sc->stts_data[i].duration;
             }
 
         sc->tts_count = FFMAX(sc->tts_count, idx);
@@ -5036,7 +4997,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
     if (!(st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
           sc->stts_count == 1 && sc->stts_data && sc->stts_data[0].duration == 
1)) {
         unsigned int current_sample = 0;
-        unsigned int stts_sample = 0;
         unsigned int sample_size;
         unsigned int distance = 0;
         unsigned int rap_group_index = 0;
@@ -5143,17 +5103,14 @@ static void mov_build_index(MOVContext *mov, AVStream 
*st)
                 current_offset += sample_size;
                 stream_size += sample_size;
 
-                if (current_dts > INT64_MAX - 
sc->tts_data[stts_index].duration)
+                if (current_dts > INT64_MAX - 
sc->tts_duration_by_sample[stts_index])
                     return;
-                current_dts += sc->tts_data[stts_index].duration;
+                current_dts += sc->tts_duration_by_sample[stts_index];
 
                 distance++;
-                stts_sample++;
                 current_sample++;
-                if (stts_index + 1 < sc->tts_count && stts_sample == 
sc->tts_data[stts_index].count) {
-                    stts_sample = 0;
-                    stts_index++;
-                }
+                if (stts_index + 1 < sc->tts_count)
+                        stts_index++;
             }
         }
         if (st->duration > 0)
@@ -5274,8 +5231,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
     // Update start time of the stream.
     if (st->start_time == AV_NOPTS_VALUE && st->codecpar->codec_type == 
AVMEDIA_TYPE_VIDEO && sti->nb_index_entries > 0) {
         st->start_time = av_sat_add64(sti->index_entries[0].timestamp, 
sc->dts_shift);
-        if (sc->tts_data) {
-            st->start_time = av_sat_add64(st->start_time, 
sc->tts_data[0].offset);
+        if (sc->tts_offset_by_sample) {
+            st->start_time += sc->tts_offset_by_sample[0];
         }
     }
 
@@ -5305,33 +5262,35 @@ static void mov_update_sample_durations(MOVContext 
*mov, AVStream *st)
     MOVStreamContext *sc = st->priv_data;
     FFStream *const sti = ffstream(st);
     MOVPresentationSample *samples = NULL;
-    MOVTimeToSample *tts_data = NULL;
-    unsigned int tts_index = 0, tts_sample = 0;
+    int *tts_offset_by_sample = NULL;
+    unsigned int *tts_duration_by_sample = NULL;
+    unsigned int tts_index = 0;
     int count = sti->nb_index_entries;
 
     /* A single STTS entry describes a fixed sample delta. */
     if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
         !sc->ctts_count || sc->stts_count < 2 ||
-        !sc->tts_data || count < 2 ||
-        count >= UINT_MAX / sizeof(*tts_data))
+        !sc->tts_offset_by_sample || !sc->tts_duration_by_sample || count < 2 
||
+        count >= UINT_MAX / sizeof(int))
         return;
 
-    samples   = av_malloc_array(count, sizeof(*samples));
-    tts_data  = av_malloc_array(count, sizeof(*tts_data));
-    if (!samples || !tts_data)
+    samples                = av_malloc_array(count, sizeof(*samples));
+    tts_offset_by_sample   = av_malloc_array(count, sizeof(int));
+    tts_duration_by_sample = av_malloc_array(count, sizeof(unsigned int));
+    if (!samples || !tts_offset_by_sample || !tts_duration_by_sample)
         goto fail;
 
     for (int i = 0; i < count; i++) {
         int64_t dts, offset;
 
-        if (tts_index >= sc->tts_count || !sc->tts_data[tts_index].count)
+        if (tts_index >= sc->tts_count)
             goto fail;
 
-        tts_data[i] = sc->tts_data[tts_index];
-        tts_data[i].count = 1;
+        tts_offset_by_sample[i] = sc->tts_offset_by_sample[tts_index];
+        tts_duration_by_sample[i] = sc->tts_duration_by_sample[tts_index];
 
         dts = sti->index_entries[i].timestamp;
-        offset = (int64_t)sc->dts_shift + tts_data[i].offset;
+        offset = (int64_t)sc->dts_shift + tts_offset_by_sample[i];
         if (dts == AV_NOPTS_VALUE ||
             (offset > 0 && dts > INT64_MAX - offset) ||
             (offset < 0 && dts < INT64_MIN - offset))
@@ -5340,12 +5299,9 @@ static void mov_update_sample_durations(MOVContext *mov, 
AVStream *st)
         samples[i].index = i;
         samples[i].pts = dts + offset;
 
-        if (++tts_sample == sc->tts_data[tts_index].count) {
-            tts_index++;
-            tts_sample = 0;
-        }
+        tts_index++;
     }
-    if (tts_index != sc->tts_count || tts_sample)
+    if (tts_index != sc->tts_count)
         goto fail;
 
     qsort(samples, count, sizeof(*samples), mov_compare_presentation_samples);
@@ -5367,22 +5323,27 @@ static void mov_update_sample_durations(MOVContext 
*mov, AVStream *st)
         if (!duration || duration > UINT_MAX)
             goto fail;
 
-        tts_data[samples[i].index].duration = (unsigned int)duration;
+        tts_duration_by_sample[samples[i].index] = (unsigned int)duration;
     }
 
     av_log(mov->fc, AV_LOG_DEBUG,
            "Updated sample durations in presentation order for stream %d\n",
            st->index);
 
-    av_freep(&sc->tts_data);
-    sc->tts_data = tts_data;
+    av_freep(&sc->tts_offset_by_sample);
+    av_freep(&sc->tts_duration_by_sample);
+    sc->tts_offset_by_sample = tts_offset_by_sample;
+    sc->tts_duration_by_sample = tts_duration_by_sample;
     sc->tts_count = count;
-    sc->tts_allocated_size = count * sizeof(*tts_data);
-    tts_data = NULL;
+    sc->tts_offset_allocated_size = count * sizeof(int);
+    sc->tts_duration_allocated_size = count * sizeof(unsigned int);
+    tts_offset_by_sample = NULL;
+    tts_duration_by_sample = NULL;
 
 fail:
     av_free(samples);
-    av_free(tts_data);
+    av_free(tts_offset_by_sample);
+    av_free(tts_duration_by_sample);
 }
 
 static int test_same_origin(const char *src, const char *ref) {
@@ -5665,13 +5626,13 @@ static int mov_read_trak(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
 
 #if FF_API_R_FRAME_RATE
         for (unsigned int i = 1; sc->stts_count && i + 1 < sc->tts_count; i++) 
{
-            if (sc->tts_data[i].duration == sc->tts_data[0].duration)
+            if (sc->tts_duration_by_sample[i] == sc->tts_duration_by_sample[0])
                 continue;
             stts_constant = 0;
         }
         if (stts_constant)
             av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,
-                      sc->time_scale, sc->tts_data[0].duration, INT_MAX);
+                      sc->time_scale, sc->tts_duration_by_sample[0], INT_MAX);
 #endif
     }
 
@@ -5697,7 +5658,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
         && sc->time_scale == st->codecpar->sample_rate) {
         int stts_constant = 1;
         for (int i = 1; sc->stts_count && i < sc->tts_count; i++) {
-            if (sc->tts_data[i].duration == sc->tts_data[0].duration)
+            if (sc->tts_duration_by_sample[i] == sc->tts_duration_by_sample[0])
                 continue;
             stts_constant = 0;
         }
@@ -6208,7 +6169,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
     AVStream *st = NULL;
     FFStream *sti = NULL;
     MOVStreamContext *sc;
-    MOVTimeToSample *tts_data;
+    int *tts_offsets;
+    unsigned int *tts_durations;
     uint64_t offset;
     int64_t dts, pts = AV_NOPTS_VALUE;
     int data_offset = 0;
@@ -6217,6 +6179,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
     int64_t prev_dts = AV_NOPTS_VALUE;
     int next_frag_index = -1, index_entry_pos;
     size_t requested_size;
+    size_t old_offset_allocated_size;
+    size_t old_duration_allocated_size;
     AVIndexEntry *new_entries;
     MOVFragmentStreamInfo * frag_stream_info;
 
@@ -6268,7 +6232,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
     if (entries && !frag->size && !(flags & MOV_TRUN_SAMPLE_SIZE))
         return AVERROR_INVALIDDATA;
 
-    if ((uint64_t)entries+sc->tts_count >= UINT_MAX/sizeof(*sc->tts_data))
+    if ((uint64_t)entries+sc->tts_count >= 
UINT_MAX/sizeof(*sc->tts_offset_by_sample))
         return AVERROR_INVALIDDATA;
     if (flags & MOV_TRUN_DATA_OFFSET)        data_offset        = 
avio_rb32(pb);
     if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = 
avio_rb32(pb);
@@ -6366,29 +6330,41 @@ static int mov_read_trun(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
         return AVERROR(ENOMEM);
     sti->index_entries= new_entries;
 
-    requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->tts_data);
-    tts_data = av_fast_realloc(sc->tts_data, &sc->tts_allocated_size,
-                                requested_size);
-    if (!tts_data)
+    requested_size = ((size_t)sti->nb_index_entries + entries) * 
sizeof(*sc->tts_offset_by_sample);
+    old_offset_allocated_size = sc->tts_offset_allocated_size;
+    tts_offsets = av_fast_realloc(sc->tts_offset_by_sample, 
&sc->tts_offset_allocated_size,
+                                  requested_size);
+    if (!tts_offsets)
         return AVERROR(ENOMEM);
-    sc->tts_data = tts_data;
+    sc->tts_offset_by_sample = tts_offsets;
+
+    old_duration_allocated_size = sc->tts_duration_allocated_size;
+    tts_durations = av_fast_realloc(sc->tts_duration_by_sample, 
&sc->tts_duration_allocated_size,
+                                    requested_size);
+    if (!tts_durations)
+        return AVERROR(ENOMEM);
+    sc->tts_duration_by_sample = tts_durations;
 
     // In case there were samples without time to sample entries, ensure they 
get
     // zero valued entries. This ensures clips which mix boxes with and
     // without time to sample entries don't pickup uninitialized data.
-    if (sc->tts_count < sti->nb_index_entries)
-        memset(sc->tts_data + sc->tts_count, 0,
-               sizeof(*sc->tts_data) * (sti->nb_index_entries - 
sc->tts_count));
+    memset((uint8_t*)sc->tts_offset_by_sample + old_offset_allocated_size, 0,
+           sc->tts_offset_allocated_size - old_offset_allocated_size);
+    memset((uint8_t*)sc->tts_duration_by_sample + old_duration_allocated_size, 
0,
+           sc->tts_duration_allocated_size - old_duration_allocated_size);
 
     if (index_entry_pos < sti->nb_index_entries) {
-        // Make hole in index_entries and tts_data for new samples
+        // Make hole in index_entries and per-sample timing arrays
         memmove(sti->index_entries + index_entry_pos + entries,
                 sti->index_entries + index_entry_pos,
                 sizeof(*sti->index_entries) *
                 (sti->nb_index_entries - index_entry_pos));
-        memmove(sc->tts_data + index_entry_pos + entries,
-                sc->tts_data + index_entry_pos,
-                sizeof(*sc->tts_data) * (sti->nb_index_entries - 
index_entry_pos));
+        memmove(sc->tts_offset_by_sample + index_entry_pos + entries,
+                sc->tts_offset_by_sample + index_entry_pos,
+                sizeof(*sc->tts_offset_by_sample) * (sti->nb_index_entries - 
index_entry_pos));
+        memmove(sc->tts_duration_by_sample + index_entry_pos + entries,
+                sc->tts_duration_by_sample + index_entry_pos,
+                sizeof(*sc->tts_duration_by_sample) * (sti->nb_index_entries - 
index_entry_pos));
         if (index_entry_pos < sc->current_sample) {
             sc->current_sample += entries;
         }
@@ -6467,9 +6443,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, 
MOVAtom atom)
         sti->index_entries[index_entry_pos].min_distance = distance;
         sti->index_entries[index_entry_pos].flags = index_entry_flags;
 
-        sc->tts_data[index_entry_pos].count = 1;
-        sc->tts_data[index_entry_pos].offset = ctts_duration;
-        sc->tts_data[index_entry_pos].duration = sample_duration;
+        sc->tts_offset_by_sample[index_entry_pos] = ctts_duration;
+        sc->tts_duration_by_sample[index_entry_pos] = sample_duration;
         index_entry_pos++;
 
         av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset 
%"PRIx64", dts %"PRId64", "
@@ -6493,15 +6468,19 @@ static int mov_read_trun(MOVContext *c, AVIOContext 
*pb, MOVAtom atom)
         frag_stream_info->next_trun_dts = dts + sc->time_offset;
     if (i < entries) {
         // EOF found before reading all entries.  Fix the hole this would
-        // leave in index_entries and tts_data
+        // leave in index_entries and per-sample timing arrays
         int gap = entries - i;
         memmove(sti->index_entries + index_entry_pos,
                 sti->index_entries + index_entry_pos + gap,
                 sizeof(*sti->index_entries) *
                 (sti->nb_index_entries - (index_entry_pos + gap)));
-        memmove(sc->tts_data + index_entry_pos,
-                sc->tts_data + index_entry_pos + gap,
-                sizeof(*sc->tts_data) *
+        memmove(sc->tts_offset_by_sample + index_entry_pos,
+                sc->tts_offset_by_sample + index_entry_pos + gap,
+                sizeof(*sc->tts_offset_by_sample) *
+                (sc->tts_count - (index_entry_pos + gap)));
+        memmove(sc->tts_duration_by_sample + index_entry_pos,
+                sc->tts_duration_by_sample + index_entry_pos + gap,
+                sizeof(*sc->tts_duration_by_sample) *
                 (sc->tts_count - (index_entry_pos + gap)));
 
         sti->nb_index_entries -= gap;
@@ -10816,7 +10795,8 @@ static void mov_free_stream_context(AVFormatContext *s, 
AVStream *st)
         return;
     }
 
-    av_freep(&sc->tts_data);
+    av_freep(&sc->tts_offset_by_sample);
+    av_freep(&sc->tts_duration_by_sample);
     for (int i = 0; i < sc->drefs_count; i++) {
         av_freep(&sc->drefs[i].path);
         av_freep(&sc->drefs[i].dir);
@@ -12666,10 +12646,10 @@ static int mov_finalize_packet(AVFormatContext *s, 
AVStream *st, AVIndexEntry *s
     if (sample->flags & AVINDEX_DISCARD_FRAME) {
         pkt->flags |= AV_PKT_FLAG_DISCARD;
     }
-    if (sc->stts_count && sc->tts_index < sc->tts_count)
-        pkt->duration = sc->tts_data[sc->tts_index].duration;
+    if (sc->stts_count && sc->tts_duration_by_sample && sc->tts_index < 
sc->tts_count)
+        pkt->duration = sc->tts_duration_by_sample[sc->tts_index];
     if (sc->ctts_count && sc->tts_index < sc->tts_count) {
-        pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, 
sc->tts_data[sc->tts_index].offset));
+        pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, 
sc->tts_offset_by_sample[sc->tts_index]));
     } else {
         if (pkt->duration == 0) {
             int64_t next_dts = (sc->current_sample < 
ffstream(st)->nb_index_entries) ?
@@ -12699,14 +12679,9 @@ static int mov_finalize_packet(AVFormatContext *s, 
AVStream *st, AVIndexEntry *s
             ffstream(st)->last_discard_sample  = total;
     }
 
-    if (sc->tts_data && sc->tts_index < sc->tts_count) {
+    if (sc->tts_index < sc->tts_count) {
         /* update tts context */
-        sc->tts_sample++;
-        if (sc->tts_index < sc->tts_count &&
-            sc->tts_data[sc->tts_index].count == sc->tts_sample) {
-            sc->tts_index++;
-            sc->tts_sample = 0;
-        }
+        sc->tts_index++;
     }
 
     if (sc->sdtp_data && sc->current_sample <= sc->sdtp_count) {
@@ -13027,18 +13002,8 @@ static int mov_seek_stream(AVFormatContext *s, 
AVStream *st, int64_t timestamp,
     mov_current_sample_set(sc, sample);
     av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, 
sc->current_sample);
     /* adjust time to sample index */
-    if (sc->tts_data) {
-        time_sample = 0;
-        for (i = 0; i < sc->tts_count; i++) {
-            int next = time_sample + sc->tts_data[i].count;
-            if (next > sc->current_sample) {
-                sc->tts_index = i;
-                sc->tts_sample = sc->current_sample - time_sample;
-                break;
-            }
-            time_sample = next;
-        }
-    }
+    if (sc->tts_count && sc->current_sample < sc->tts_count)
+        sc->tts_index = sc->current_sample;
 
     /* adjust stsd index */
     if (sc->chunk_count) {
-- 
2.52.0

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

Reply via email to