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]
