History

avformat/mov: merge stts and ctts arrays into one

Should reduce memory usage as well as remove code duplication.

James Almer committed 1 year ago

Commit 292c1df1 parent d7180a32 files · +249 −344Browse files

Unified · Split

2 files
  1. libavformat/isom.h +11 −4
  2. libavformat/mov.c +238 −340
libavformat/isom.h+11−4
@@ -54,6 +54,12 @@ struct AVAESCTR; · 53 unmodified lines
5454 * Here we just use what is needed to read the chunks
5555 */
5656
57+typedef struct MOVTimeToSample {
58+ unsigned int count;
59+ unsigned int duration;
60+ int offset;
61+} MOVTimeToSample;
62+
5763 typedef struct MOVStts {
5864 unsigned int count;
5965 unsigned int duration;
@@ -173,6 +179,9 @@ typedef struct MOVStreamContext { · 113 unmodified lines
173179 int next_chunk;
174180 unsigned int chunk_count;
175181 int64_t *chunk_offsets;
182+ unsigned int tts_count;
183+ unsigned int tts_allocated_size;
184+ MOVTimeToSample *tts_data;
176185 unsigned int stts_count;
177186 unsigned int stts_allocated_size;
178187 MOVStts *stts_data;
@@ -189,10 +198,8 @@ typedef struct MOVStreamContext { · 10 unmodified lines
189198 unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
190199 MOVElst *elst_data;
191200 unsigned int elst_count;
192− int stts_index;
193− int stts_sample;
194− int ctts_index;
195− int ctts_sample;
201+ int tts_index;
202+ int tts_sample;
196203 unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
197204 unsigned int stsz_sample_size; ///< always contains sample size from stsz atom
198205 unsigned int sample_count;
libavformat/mov.c+238−340
@@ -87,8 +87,6 @@ typedef struct MOVParseTableEntry { · 86 unmodified lines
8787 static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom);
8888 static int mov_read_mfra(MOVContext *c, AVIOContext *f);
8989 static void mov_free_stream_context(AVFormatContext *s, AVStream *st);
90−static int64_t add_ctts_entry(MOVCtts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size,
91− int count, int duration);
9290
9391 static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
9492 unsigned len, const char *key)
@@ -3666,6 +3664,12 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 3571 unmodified lines
36663664 return AVERROR(ENOMEM);
36673665
36683666 for (i = 0; i < entries && !pb->eof_reached; i++) {
3667+ MOVCtts *ctts_data;
3668+ const size_t min_size_needed = (ctts_count + 1) * sizeof(MOVCtts);
3669+ const size_t requested_size =
3670+ min_size_needed > sc->ctts_allocated_size ?
3671+ FFMAX(min_size_needed, 2 * sc->ctts_allocated_size) :
3672+ min_size_needed;
36693673 int count = avio_rb32(pb);
36703674 int duration = avio_rb32(pb);
36713675
@@ -3676,8 +3680,19 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 4 unmodified lines
36763680 continue;
36773681 }
36783682
3679− add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size,
3680− count, duration);
3683+ if (ctts_count >= UINT_MAX / sizeof(MOVCtts) - 1)
3684+ return AVERROR(ENOMEM);
3685+
3686+ ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, requested_size);
3687+
3688+ if (!ctts_data)
3689+ return AVERROR(ENOMEM);
3690+
3691+ sc->ctts_data = ctts_data;
3692+
3693+ ctts_data[ctts_count].count = count;
3694+ ctts_data[ctts_count].offset = duration;
3695+ ctts_count++;
36813696
36823697 av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n",
36833698 count, duration);
@@ -3871,24 +3886,19 @@ static int get_edit_list_entry(MOVContext *mov, · 187 unmodified lines
38713886 static int find_prev_closest_index(AVStream *st,
38723887 AVIndexEntry *e_old,
38733888 int nb_old,
3874− MOVStts* stts_data,
3875− int64_t stts_count,
3876− MOVCtts* ctts_data,
3877− int64_t ctts_count,
3889+ MOVTimeToSample *tts_data,
3890+ int64_t tts_count,
38783891 int64_t timestamp_pts,
38793892 int flag,
38803893 int64_t* index,
3881− int64_t* stts_index,
3882− int64_t* stts_sample,
3883− int64_t* ctts_index,
3884− int64_t* ctts_sample)
3894+ int64_t* tts_index,
3895+ int64_t* tts_sample)
38853896 {
38863897 MOVStreamContext *msc = st->priv_data;
38873898 FFStream *const sti = ffstream(st);
38883899 AVIndexEntry *e_keep = sti->index_entries;
38893900 int nb_keep = sti->nb_index_entries;
38903901 int64_t i = 0;
3891− int64_t index_ctts_count;
38923902
38933903 av_assert0(index);
38943904
@@ -3916,64 +3926,38 @@ static int find_prev_closest_index(AVStream *st, · 21 unmodified lines
39163926
39173927 // If we have CTTS then refine the search, by searching backwards over PTS
39183928 // computed by adding corresponding CTTS durations to index timestamps.
3919− if (ctts_data && *index >= 0) {
3920− av_assert0(ctts_index);
3921− av_assert0(ctts_sample);
3929+ if (msc->ctts_count && *index >= 0) {
3930+ av_assert0(tts_index);
3931+ av_assert0(tts_sample);
39223932 // Find out the ctts_index for the found frame.
3923− *ctts_index = 0;
3924− *ctts_sample = 0;
3925−
3926− if (stts_data) {
3927− av_assert0(stts_index);
3928− av_assert0(stts_sample);
3929−
3930− *stts_index = 0;
3931− *stts_sample = 0;
3932− }
3933−
3934− for (index_ctts_count = 0; index_ctts_count < *index; index_ctts_count++) {
3935− if (*ctts_index < ctts_count) {
3936− (*ctts_sample)++;
3937− if (ctts_data[*ctts_index].count == *ctts_sample) {
3938− (*ctts_index)++;
3939− *ctts_sample = 0;
3940− }
3941− }
3942− if (stts_data && *stts_index < stts_count) {
3943− (*stts_sample)++;
3944− if (stts_data[*stts_index].count == *stts_sample) {
3945− (*stts_index)++;
3946− *stts_sample = 0;
3933+ *tts_index = 0;
3934+ *tts_sample = 0;
3935+ for (int64_t index_tts_count = 0; index_tts_count < *index; index_tts_count++) {
3936+ if (*tts_index < tts_count) {
3937+ (*tts_sample)++;
3938+ if (tts_data[*tts_index].count == *tts_sample) {
3939+ (*tts_index)++;
3940+ *tts_sample = 0;
39473941 }
39483942 }
39493943 }
39503944
3951− while (*index >= 0 && (*ctts_index) >= 0 && (*ctts_index) < ctts_count) {
3945+ while (*index >= 0 && (*tts_index) >= 0 && (*tts_index) < tts_count) {
39523946 // Find a "key frame" with PTS <= timestamp_pts (So that we can decode B-frames correctly).
39533947 // No need to add dts_shift to the timestamp here becase timestamp_pts has already been
39543948 // compensated by dts_shift above.
3955− if ((e_old[*index].timestamp + ctts_data[*ctts_index].offset) <= timestamp_pts &&
3949+ if ((e_old[*index].timestamp + tts_data[*tts_index].offset) <= timestamp_pts &&
39563950 (e_old[*index].flags & AVINDEX_KEYFRAME)) {
39573951 break;
39583952 }
39593953
39603954 (*index)--;
3961− if (*ctts_sample == 0) {
3962− (*ctts_index)--;
3963− if (*ctts_index >= 0)
3964− *ctts_sample = ctts_data[*ctts_index].count - 1;
3955+ if (*tts_sample == 0) {
3956+ (*tts_index)--;
3957+ if (*tts_index >= 0)
3958+ *tts_sample = tts_data[*tts_index].count - 1;
39653959 } else {
3966− (*ctts_sample)--;
3967− }
3968− if (stts_data) {
3969− if (*stts_sample == 0) {
3970− (*stts_index)--;
3971− if (*stts_index >= 0) {
3972− *stts_sample = stts_data[*stts_index].count - 1;
3973− }
3974− } else {
3975− (*stts_sample)--;
3976− }
3960+ (*tts_sample)--;
39773961 }
39783962 }
39793963 }
@@ -4048,62 +4032,32 @@ static void fix_index_entry_timestamps(AVStream* st, int end_index, int64_t end_ · 68 unmodified lines
40484032 }
40494033 }
40504034
4051−static int64_t add_stts_entry(MOVStts** stts_data, unsigned int* stts_count, unsigned int* allocated_size,
4052− int count, int duration)
4053−{
4054− MOVStts *stts_buf_new;
4055− const size_t min_size_needed = (*stts_count + 1) * sizeof(MOVStts);
4056− const size_t requested_size =
4057− min_size_needed > *allocated_size ?
4058− FFMAX(min_size_needed, 2 * (*allocated_size)) :
4059− min_size_needed;
4060−
4061− if ((unsigned)(*stts_count) >= UINT_MAX / sizeof(MOVStts) - 1)
4062− return -1;
4063−
4064− stts_buf_new = av_fast_realloc(*stts_data, allocated_size, requested_size);
4065−
4066− if (!stts_buf_new)
4067− return -1;
4068−
4069− *stts_data = stts_buf_new;
4070−
4071− stts_buf_new[*stts_count].count = count;
4072− stts_buf_new[*stts_count].duration = duration;
4073−
4074− *stts_count = (*stts_count) + 1;
4075− return *stts_count;
4076−}
4077−
4078−/**
4079− * Append a new ctts entry to ctts_data.
4080− * Returns the new ctts_count if successful, else returns -1.
4081− */
4082−static int64_t add_ctts_entry(MOVCtts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size,
4083− int count, int offset)
4035+static int add_tts_entry(MOVTimeToSample **tts_data, unsigned int *tts_count, unsigned int *allocated_size,
4036+ int count, int offset, unsigned int duration)
40844037 {
4085− MOVCtts *ctts_buf_new;
4086− const size_t min_size_needed = (*ctts_count + 1) * sizeof(MOVCtts);
4038+ MOVTimeToSample *tts_buf_new;
4039+ const size_t min_size_needed = (*tts_count + 1) * sizeof(MOVTimeToSample);
40874040 const size_t requested_size =
40884041 min_size_needed > *allocated_size ?
40894042 FFMAX(min_size_needed, 2 * (*allocated_size)) :
40904043 min_size_needed;
40914044
4092− if ((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVCtts) - 1)
4045+ if ((unsigned)(*tts_count) >= UINT_MAX / sizeof(MOVTimeToSample) - 1)
40934046 return -1;
40944047
4095− ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size);
4048+ tts_buf_new = av_fast_realloc(*tts_data, allocated_size, requested_size);
40964049
4097− if (!ctts_buf_new)
4050+ if (!tts_buf_new)
40984051 return -1;
40994052
4100− *ctts_data = ctts_buf_new;
4053+ *tts_data = tts_buf_new;
41014054
4102− ctts_buf_new[*ctts_count].count = count;
4103− ctts_buf_new[*ctts_count].offset = offset;
4055+ tts_buf_new[*tts_count].count = count;
4056+ tts_buf_new[*tts_count].offset = offset;
4057+ tts_buf_new[*tts_count].duration = duration;
41044058
4105− *ctts_count = (*ctts_count) + 1;
4106− return *ctts_count;
4059+ *tts_count = (*tts_count) + 1;
4060+ return 0;
41074061 }
41084062
41094063 #define MAX_REORDER_DELAY 16
@@ -4120,17 +4074,17 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st) · 10 unmodified lines
41204074 for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
41214075 pts_buf[j] = INT64_MIN;
41224076
4123− if (st->codecpar->video_delay <= 0 && msc->ctts_data &&
4077+ if (st->codecpar->video_delay <= 0 && msc->ctts_count &&
41244078 st->codecpar->codec_id == AV_CODEC_ID_H264) {
41254079 st->codecpar->video_delay = 0;
4126− for (int ind = 0; ind < sti->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) {
4080+ for (int ind = 0; ind < sti->nb_index_entries && ctts_ind < msc->tts_count; ++ind) {
41274081 // Point j to the last elem of the buffer and insert the current pts there.
41284082 j = buf_start;
41294083 buf_start = (buf_start + 1);
41304084 if (buf_start == MAX_REORDER_DELAY + 1)
41314085 buf_start = 0;
41324086
4133− pts_buf[j] = sti->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].offset;
4087+ pts_buf[j] = sti->index_entries[ind].timestamp + msc->tts_data[ctts_ind].offset;
41344088
41354089 // The timestamps that are already in the sorted buffer, and are greater than the
41364090 // current pts, are exactly the timestamps that need to be buffered to output PTS
@@ -4153,7 +4107,7 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st) · 16 unmodified lines
41534107 st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps);
41544108
41554109 ctts_sample++;
4156− if (ctts_sample == msc->ctts_data[ctts_ind].count) {
4110+ if (ctts_sample == msc->tts_data[ctts_ind].count) {
41574111 ctts_ind++;
41584112 ctts_sample = 0;
41594113 }
@@ -4223,21 +4177,16 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 63 unmodified lines
42234177 int nb_old = sti->nb_index_entries;
42244178 const AVIndexEntry *e_old_end = e_old + nb_old;
42254179 const AVIndexEntry *current = NULL;
4226− MOVStts *stts_data_old = msc->stts_data;
4227− int64_t stts_index_old = 0;
4228− int64_t stts_sample_old = 0;
4229− int64_t stts_count_old = msc->stts_count;
4230− MOVCtts *ctts_data_old = msc->ctts_data;
4231− int64_t ctts_index_old = 0;
4232− int64_t ctts_sample_old = 0;
4233− int64_t ctts_count_old = msc->ctts_count;
4180+ MOVTimeToSample *tts_data_old = msc->tts_data;
4181+ int64_t tts_index_old = 0;
4182+ int64_t tts_sample_old = 0;
4183+ int64_t tts_count_old = msc->tts_count;
42344184 int64_t edit_list_media_time = 0;
42354185 int64_t edit_list_duration = 0;
42364186 int64_t frame_duration = 0;
42374187 int64_t edit_list_dts_counter = 0;
42384188 int64_t edit_list_dts_entry_end = 0;
4239− int64_t edit_list_start_stts_sample = 0;
4240− int64_t edit_list_start_ctts_sample = 0;
4189+ int64_t edit_list_start_tts_sample = 0;
42414190 int64_t curr_cts;
42424191 int64_t curr_ctts = 0;
42434192 int64_t empty_edits_sum_duration = 0;
@@ -4274,16 +4223,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 30 unmodified lines
42744223 sti->nb_index_entries = 0;
42754224
42764225 // Clean time to sample fields of MOVStreamContext
4277− msc->stts_data = NULL;
4278− msc->stts_count = 0;
4279− msc->stts_index = 0;
4280− msc->stts_sample = 0;
4281− msc->stts_allocated_size = 0;
4282− msc->ctts_data = NULL;
4283− msc->ctts_count = 0;
4284− msc->ctts_index = 0;
4285− msc->ctts_sample = 0;
4286− msc->ctts_allocated_size = 0;
4226+ msc->tts_data = NULL;
4227+ msc->tts_count = 0;
4228+ msc->tts_index = 0;
4229+ msc->tts_sample = 0;
4230+ msc->tts_allocated_size = 0;
42874231
42884232 // Reinitialize min_corrected_pts so that it can be computed again.
42894233 msc->min_corrected_pts = -1;
@@ -4336,26 +4280,23 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 46 unmodified lines
43364280 search_timestamp = FFMAX(search_timestamp - msc->time_scale, e_old[0].timestamp);
43374281 }
43384282
4339− if (find_prev_closest_index(st, e_old, nb_old, stts_data_old, stts_count_old, ctts_data_old, ctts_count_old, search_timestamp, 0,
4340− &index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
4283+ if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, tts_count_old, search_timestamp, 0,
4284+ &index, &tts_index_old, &tts_sample_old) < 0) {
43414285 av_log(mov->fc, AV_LOG_WARNING,
43424286 "st: %d edit list: %"PRId64" Missing key frame while searching for timestamp: %"PRId64"\n",
43434287 st->index, edit_list_index, search_timestamp);
4344− if (find_prev_closest_index(st, e_old, nb_old, stts_data_old, stts_count_old, ctts_data_old, ctts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
4345− &index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
4288+ if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, tts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
4289+ &index, &tts_index_old, &tts_sample_old) < 0) {
43464290 av_log(mov->fc, AV_LOG_WARNING,
43474291 "st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n",
43484292 st->index, edit_list_index, search_timestamp);
43494293 index = 0;
4350− stts_index_old = 0;
4351− stts_sample_old = 0;
4352− ctts_index_old = 0;
4353− ctts_sample_old = 0;
4294+ tts_index_old = 0;
4295+ tts_sample_old = 0;
43544296 }
43554297 }
43564298 current = e_old + index;
4357− edit_list_start_ctts_sample = ctts_sample_old;
4358− edit_list_start_stts_sample = stts_sample_old;
4299+ edit_list_start_tts_sample = tts_sample_old;
43594300
43604301 // Iterate over index and arrange it according to edit list
43614302 edit_list_start_encountered = 0;
@@ -4371,44 +4312,26 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 9 unmodified lines
43714312 curr_cts = current->timestamp + msc->dts_shift;
43724313 curr_ctts = 0;
43734314
4374− if (stts_data_old && stts_index_old < stts_count_old) {
4375− stts_sample_old++;
4376− if (stts_sample_old == stts_data_old[stts_index_old].count) {
4377− if (add_stts_entry(&msc->stts_data, &msc->stts_count,
4378− &msc->stts_allocated_size,
4379− stts_data_old[stts_index_old].count - edit_list_start_stts_sample,
4380− stts_data_old[stts_index_old].duration) == -1) {
4381− av_log(mov->fc, AV_LOG_ERROR, "Cannot add STTS entry %"PRId64" - {%"PRId64", %d}\n",
4382− stts_index_old,
4383− stts_data_old[stts_index_old].count - edit_list_start_stts_sample,
4384− stts_data_old[stts_index_old].duration);
4385− break;
4386− }
4387− stts_index_old++;
4388− stts_sample_old = 0;
4389− edit_list_start_stts_sample = 0;
4390− }
4391− }
4392− if (ctts_data_old && ctts_index_old < ctts_count_old) {
4393− curr_ctts = ctts_data_old[ctts_index_old].offset;
4394− av_log(mov->fc, AV_LOG_TRACE, "stts: %"PRId64" ctts: %"PRId64", ctts_index: %"PRId64", ctts_count: %"PRId64"\n",
4395− curr_cts, curr_ctts, ctts_index_old, ctts_count_old);
4315+ if (tts_data_old && tts_index_old < tts_count_old) {
4316+ curr_ctts = tts_data_old[tts_index_old].offset;
4317+ av_log(mov->fc, AV_LOG_TRACE, "stts: %"PRId64" ctts: %"PRId64", tts_index: %"PRId64", tts_count: %"PRId64"\n",
4318+ curr_cts, curr_ctts, tts_index_old, tts_count_old);
43964319 curr_cts += curr_ctts;
4397− ctts_sample_old++;
4398− if (ctts_sample_old == ctts_data_old[ctts_index_old].count) {
4399− if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count,
4400− &msc->ctts_allocated_size,
4401− ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
4402− ctts_data_old[ctts_index_old].offset) == -1) {
4403− av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n",
4404− ctts_index_old,
4405− ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
4406− ctts_data_old[ctts_index_old].offset);
4320+ tts_sample_old++;
4321+ if (tts_sample_old == tts_data_old[tts_index_old].count) {
4322+ if (add_tts_entry(&msc->tts_data, &msc->tts_count,
4323+ &msc->tts_allocated_size,
4324+ tts_data_old[tts_index_old].count - edit_list_start_tts_sample,
4325+ tts_data_old[tts_index_old].offset, tts_data_old[tts_index_old].duration) == -1) {
4326+ av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To Sample entry %"PRId64" - {%"PRId64", %d}\n",
4327+ tts_index_old,
4328+ tts_data_old[tts_index_old].count - edit_list_start_tts_sample,
4329+ tts_data_old[tts_index_old].offset);
44074330 break;
44084331 }
4409− ctts_index_old++;
4410− ctts_sample_old = 0;
4411− edit_list_start_ctts_sample = 0;
4332+ tts_index_old++;
4333+ tts_sample_old = 0;
4334+ edit_list_start_tts_sample = 0;
44124335 }
44134336 }
44144337
@@ -4494,7 +4417,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 79 unmodified lines
44944417 // Break when found first key frame after edit entry completion
44954418 if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) &&
44964419 ((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) {
4497− if (ctts_data_old) {
4420+ if (msc->ctts_count) {
44984421 // If we have CTTS and this is the first keyframe after edit elist,
44994422 // wait for one more, because there might be trailing B-frames after this I-frame
45004423 // that do belong to the edit.
@@ -4502,24 +4425,14 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 1 unmodified line
45024425 found_keyframe_after_edit = 1;
45034426 continue;
45044427 }
4505− if (ctts_sample_old != 0) {
4506− if (stts_data_old &&
4507− add_stts_entry(&msc->stts_data, &msc->stts_count,
4508− &msc->stts_allocated_size,
4509− stts_sample_old - edit_list_start_stts_sample,
4510− stts_data_old[stts_index_old].duration) == -1) {
4511− av_log(mov->fc, AV_LOG_ERROR, "Cannot add STTS entry %"PRId64" - {%"PRId64", %d}\n",
4512− stts_index_old, stts_sample_old - edit_list_start_stts_sample,
4513− stts_data_old[stts_index_old].duration);
4514− break;
4515− }
4516− if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count,
4517− &msc->ctts_allocated_size,
4518− ctts_sample_old - edit_list_start_ctts_sample,
4519− ctts_data_old[ctts_index_old].offset) == -1) {
4520− av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n",
4521− ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample,
4522− ctts_data_old[ctts_index_old].offset);
4428+ if (tts_sample_old != 0) {
4429+ if (add_tts_entry(&msc->tts_data, &msc->tts_count,
4430+ &msc->tts_allocated_size,
4431+ tts_sample_old - edit_list_start_tts_sample,
4432+ tts_data_old[tts_index_old].offset, tts_data_old[tts_index_old].duration) == -1) {
4433+ av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To Sample entry %"PRId64" - {%"PRId64", %d}\n",
4434+ tts_index_old, tts_sample_old - edit_list_start_tts_sample,
4435+ tts_data_old[tts_index_old].offset);
45234436 break;
45244437 }
45254438 }
@@ -4550,8 +4463,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) · 24 unmodified lines
45504463
45514464 // Free the old index and the old CTTS structures
45524465 av_free(e_old);
4553− av_free(stts_data_old);
4554− av_free(ctts_data_old);
4466+ av_free(tts_data_old);
45554467 av_freep(&frame_duration_buffer);
45564468
45574469 // Null terminate the index ranges array
@@ -4633,6 +4545,76 @@ static int build_open_gop_key_points(AVStream *st) · 75 unmodified lines
46334545 return 0;
46344546 }
46354547
4548+#define MOV_MERGE_CTTS 1
4549+#define MOV_MERGE_STTS 2
4550+/*
4551+ * Merge stts and ctts arrays into a new combined array.
4552+ * stts_count and ctts_count may be left untouched as they will be
4553+ * used to check for the presence of either of them.
4554+ */
4555+static int mov_merge_tts_data(MOVContext *mov, AVStream *st, int flags)
4556+{
4557+ MOVStreamContext *sc = st->priv_data;
4558+ int ctts = sc->ctts_data && (flags & MOV_MERGE_CTTS);
4559+ int stts = sc->stts_data && (flags & MOV_MERGE_STTS);
4560+ int idx = 0;
4561+
4562+ if (!sc->ctts_data && !sc->stts_data)
4563+ return 0;
4564+ // Expand time to sample entries such that we have a 1-1 mapping with samples
4565+ if (!sc->sample_count || sc->sample_count >= UINT_MAX / sizeof(*sc->tts_data))
4566+ return -1;
4567+
4568+ if (ctts) {
4569+ sc->tts_data = av_fast_realloc(NULL, &sc->tts_allocated_size,
4570+ sc->sample_count * sizeof(*sc->tts_data));
4571+ if (!sc->tts_data)
4572+ return -1;
4573+
4574+ memset(sc->tts_data, 0, sc->tts_allocated_size);
4575+
4576+ for (int i = 0; i < sc->ctts_count &&
4577+ idx < sc->sample_count; i++)
4578+ for (int j = 0; j < sc->ctts_data[i].count &&
4579+ idx < sc->sample_count; j++) {
4580+ sc->tts_data[idx].offset = sc->ctts_data[i].offset;
4581+ sc->tts_data[idx++].count = 1;
4582+ }
4583+
4584+ sc->tts_count = idx;
4585+ } else
4586+ sc->ctts_count = 0;
4587+ av_freep(&sc->ctts_data);
4588+ sc->ctts_allocated_size = 0;
4589+
4590+ idx = 0;
4591+ if (stts) {
4592+ MOVTimeToSample *tts_data = av_fast_realloc(sc->tts_data, &sc->tts_allocated_size,
4593+ sc->sample_count * sizeof(*sc->tts_data));
4594+ if (!tts_data)
4595+ return -1;
4596+
4597+ if (!sc->tts_data)
4598+ memset(tts_data, 0, sc->tts_allocated_size);
4599+ sc->tts_data = tts_data;
4600+
4601+ for (int i = 0; i < sc->stts_count &&
4602+ idx < sc->sample_count; i++)
4603+ for (int j = 0; j < sc->stts_data[i].count &&
4604+ idx < sc->sample_count; j++) {
4605+ sc->tts_data[idx].duration = sc->stts_data[i].duration;
4606+ sc->tts_data[idx++].count = 1;
4607+ }
4608+
4609+ sc->tts_count = FFMAX(sc->tts_count, idx);
4610+ } else
4611+ sc->stts_count = 0;
4612+ av_freep(&sc->stts_data);
4613+ sc->stts_allocated_size = 0;
4614+
4615+ return 0;
4616+}
4617+
46364618 static void mov_build_index(MOVContext *mov, AVStream *st)
46374619 {
46384620 MOVStreamContext *sc = st->priv_data;
@@ -4645,10 +4627,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st) · 6 unmodified lines
46454627 unsigned int stps_index = 0;
46464628 unsigned int i, j;
46474629 uint64_t stream_size = 0;
4648− MOVStts *stts_data_old = sc->stts_data;
4649− MOVCtts *ctts_data_old = sc->ctts_data;
4650− unsigned int stts_count_old = sc->stts_count;
4651− unsigned int ctts_count_old = sc->ctts_count;
46524630
46534631 int ret = build_open_gop_key_points(st);
46544632 if (ret < 0)
@@ -4728,54 +4706,9 @@ static void mov_build_index(MOVContext *mov, AVStream *st) · 73 unmodified lines
47284706 }
47294707 sti->index_entries_allocated_size = (sti->nb_index_entries + sc->sample_count) * sizeof(*sti->index_entries);
47304708
4731− if (ctts_data_old) {
4732− // Expand ctts entries such that we have a 1-1 mapping with samples
4733− if (sc->sample_count >= UINT_MAX / sizeof(*sc->ctts_data))
4734− return;
4735− sc->ctts_count = 0;
4736− sc->ctts_allocated_size = 0;
4737− sc->ctts_data = av_fast_realloc(NULL, &sc->ctts_allocated_size,
4738− sc->sample_count * sizeof(*sc->ctts_data));
4739− if (!sc->ctts_data) {
4740− av_free(ctts_data_old);
4741− return;
4742− }
4743−
4744− memset((uint8_t*)(sc->ctts_data), 0, sc->ctts_allocated_size);
4745−
4746− for (i = 0; i < ctts_count_old &&
4747− sc->ctts_count < sc->sample_count; i++)
4748− for (j = 0; j < ctts_data_old[i].count &&
4749− sc->ctts_count < sc->sample_count; j++)
4750− add_ctts_entry(&sc->ctts_data, &sc->ctts_count,
4751− &sc->ctts_allocated_size, 1,
4752− ctts_data_old[i].offset);
4753− av_free(ctts_data_old);
4754− }
4755− if (stts_data_old) {
4756− // Expand stts entries such that we have a 1-1 mapping with samples
4757− if (sc->sample_count >= UINT_MAX / sizeof(*sc->stts_data))
4758− return;
4759− sc->stts_count = 0;
4760− sc->stts_allocated_size = 0;
4761− sc->stts_data = av_fast_realloc(NULL, &sc->stts_allocated_size,
4762− sc->sample_count * sizeof(*sc->stts_data));
4763− if (!sc->stts_data) {
4764− av_free(stts_data_old);
4765− return;
4766− }
4767−
4768− memset((uint8_t*)(sc->stts_data), 0, sc->stts_allocated_size);
4769−
4770− for (i = 0; i < stts_count_old &&
4771− sc->stts_count < sc->sample_count; i++)
4772− for (j = 0; j < stts_data_old[i].count &&
4773− sc->stts_count < sc->sample_count; j++)
4774− add_stts_entry(&sc->stts_data, &sc->stts_count,
4775− &sc->stts_allocated_size, 1,
4776− stts_data_old[i].duration);
4777− av_free(stts_data_old);
4778− }
4709+ ret = mov_merge_tts_data(mov, st, MOV_MERGE_CTTS | MOV_MERGE_STTS);
4710+ if (ret < 0)
4711+ return;
47794712
47804713 for (i = 0; i < sc->chunk_count; i++) {
47814714 int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX;
@@ -4856,12 +4789,12 @@ static void mov_build_index(MOVContext *mov, AVStream *st) · 74 unmodified lines
48564789 current_offset += sample_size;
48574790 stream_size += sample_size;
48584791
4859− current_dts += sc->stts_data[stts_index].duration;
4792+ current_dts += sc->tts_data[stts_index].duration;
48604793
48614794 distance++;
48624795 stts_sample++;
48634796 current_sample++;
4864− if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) {
4797+ if (stts_index + 1 < sc->tts_count && stts_sample == sc->tts_data[stts_index].count) {
48654798 stts_sample = 0;
48664799 stts_index++;
48674800 }
@@ -4872,6 +4805,10 @@ static void mov_build_index(MOVContext *mov, AVStream *st) · 4 unmodified lines
48724805 } else {
48734806 unsigned chunk_samples, total = 0;
48744807
4808+ ret = mov_merge_tts_data(mov, st, MOV_MERGE_CTTS);
4809+ if (ret < 0)
4810+ return;
4811+
48754812 if (!sc->chunk_count)
48764813 return;
48774814
@@ -4979,8 +4916,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) · 101 unmodified lines
49794916 // Update start time of the stream.
49804917 if (st->start_time == AV_NOPTS_VALUE && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && sti->nb_index_entries > 0) {
49814918 st->start_time = sti->index_entries[0].timestamp + sc->dts_shift;
4982− if (sc->ctts_data) {
4983− st->start_time += sc->ctts_data[0].offset;
4919+ if (sc->tts_data) {
4920+ st->start_time += sc->tts_data[0].offset;
49844921 }
49854922 }
49864923
@@ -5254,14 +5191,14 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 267 unmodified lines
52545191 }
52555192
52565193 #if FF_API_R_FRAME_RATE
5257− for (int i = 1; sc->stts_count && i < sc->stts_count - 1; i++) {
5258− if (sc->stts_data[i].duration == sc->stts_data[0].duration)
5194+ for (int i = 1; sc->stts_count && i < sc->tts_count - 1; i++) {
5195+ if (sc->tts_data[i].duration == sc->tts_data[0].duration)
52595196 continue;
52605197 stts_constant = 0;
52615198 }
52625199 if (stts_constant)
52635200 av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,
5264− sc->time_scale, sc->stts_data[0].duration, INT_MAX);
5201+ sc->time_scale, sc->tts_data[0].duration, INT_MAX);
52655202 #endif
52665203 }
52675204
@@ -5292,8 +5229,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 24 unmodified lines
52925229 if (st->codecpar->codec_id == AV_CODEC_ID_MP3
52935230 && sc->time_scale == st->codecpar->sample_rate) {
52945231 int stts_constant = 1;
5295− for (int i = 1; i < sc->stts_count; i++) {
5296− if (sc->stts_data[i].duration == sc->stts_data[0].duration)
5232+ for (int i = 1; sc->stts_count && i < sc->tts_count; i++) {
5233+ if (sc->tts_data[i].duration == sc->tts_data[0].duration)
52975234 continue;
52985235 stts_constant = 0;
52995236 }
@@ -5776,8 +5713,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 476 unmodified lines
57765713 AVStream *st = NULL;
57775714 FFStream *sti = NULL;
57785715 MOVStreamContext *sc;
5779− MOVStts *stts_data;
5780− MOVCtts *ctts_data;
5716+ MOVTimeToSample *tts_data;
57815717 uint64_t offset;
57825718 int64_t dts, pts = AV_NOPTS_VALUE;
57835719 int data_offset = 0;
@@ -5833,7 +5769,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 49 unmodified lines
58335769 entries = avio_rb32(pb);
58345770 av_log(c->fc, AV_LOG_TRACE, "flags 0x%x entries %u\n", flags, entries);
58355771
5836− if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data))
5772+ if ((uint64_t)entries+sc->tts_count >= UINT_MAX/sizeof(*sc->tts_data))
58375773 return AVERROR_INVALIDDATA;
58385774 if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
58395775 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
@@ -5906,52 +5842,39 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 66 unmodified lines
59065842 return AVERROR(ENOMEM);
59075843 sti->index_entries= new_entries;
59085844
5909− requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->ctts_data);
5910− old_allocated_size = sc->ctts_allocated_size;
5911− ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size,
5845+ requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->tts_data);
5846+ old_allocated_size = sc->tts_allocated_size;
5847+ tts_data = av_fast_realloc(sc->tts_data, &sc->tts_allocated_size,
59125848 requested_size);
5913− if (!ctts_data)
5849+ if (!tts_data)
59145850 return AVERROR(ENOMEM);
5915− sc->ctts_data = ctts_data;
5851+ sc->tts_data = tts_data;
59165852
5917− // In case there were samples without ctts entries, ensure they get
5853+ // In case there were samples without time to sample entries, ensure they get
59185854 // zero valued entries. This ensures clips which mix boxes with and
5919− // without ctts entries don't pickup uninitialized data.
5920− memset((uint8_t*)(sc->ctts_data) + old_allocated_size, 0,
5921− sc->ctts_allocated_size - old_allocated_size);
5922−
5923− requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->stts_data);
5924− old_allocated_size = sc->stts_allocated_size;
5925− stts_data = av_fast_realloc(sc->stts_data, &sc->stts_allocated_size,
5926− requested_size);
5927− if (!stts_data)
5928− return AVERROR(ENOMEM);
5929− sc->stts_data = stts_data;
5930−
5931− // See the comment for ctts above.
5932− memset((uint8_t*)(sc->stts_data) + old_allocated_size, 0,
5933− sc->stts_allocated_size - old_allocated_size);
5855+ // without time to sample entries don't pickup uninitialized data.
5856+ memset((uint8_t*)(sc->tts_data) + old_allocated_size, 0,
5857+ sc->tts_allocated_size - old_allocated_size);
59345858
59355859 if (index_entry_pos < sti->nb_index_entries) {
5936− // Make hole in index_entries and ctts_data for new samples
5860+ // Make hole in index_entries and tts_data for new samples
59375861 memmove(sti->index_entries + index_entry_pos + entries,
59385862 sti->index_entries + index_entry_pos,
59395863 sizeof(*sti->index_entries) *
59405864 (sti->nb_index_entries - index_entry_pos));
5941− memmove(sc->ctts_data + index_entry_pos + entries,
5942− sc->ctts_data + index_entry_pos,
5943− sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos));
5944− memmove(sc->stts_data + index_entry_pos + entries,
5945− sc->stts_data + index_entry_pos,
5946− sizeof(*sc->stts_data) * (sc->stts_count - index_entry_pos));
5865+ memmove(sc->tts_data + index_entry_pos + entries,
5866+ sc->tts_data + index_entry_pos,
5867+ sizeof(*sc->tts_data) * (sc->tts_count - index_entry_pos));
59475868 if (index_entry_pos < sc->current_sample) {
59485869 sc->current_sample += entries;
59495870 }
59505871 }
59515872
59525873 sti->nb_index_entries += entries;
5953− sc->ctts_count = sti->nb_index_entries;
5874+ sc->tts_count = sti->nb_index_entries;
59545875 sc->stts_count = sti->nb_index_entries;
5876+ if (flags & MOV_TRUN_SAMPLE_CTS)
5877+ sc->ctts_count = sti->nb_index_entries;
59555878
59565879 // Record the index_entry position in frag_index of this fragment
59575880 if (frag_stream_info) {
@@ -6013,10 +5936,9 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 55 unmodified lines
60135936 sti->index_entries[index_entry_pos].min_distance = distance;
60145937 sti->index_entries[index_entry_pos].flags = index_entry_flags;
60155938
6016− sc->ctts_data[index_entry_pos].count = 1;
6017− sc->ctts_data[index_entry_pos].offset = ctts_duration;
6018− sc->stts_data[index_entry_pos].count = 1;
6019− sc->stts_data[index_entry_pos].duration = sample_duration;
5939+ sc->tts_data[index_entry_pos].count = 1;
5940+ sc->tts_data[index_entry_pos].offset = ctts_duration;
5941+ sc->tts_data[index_entry_pos].duration = sample_duration;
60205942 index_entry_pos++;
60215943
60225944 av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
@@ -6042,24 +5964,19 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 19 unmodified lines
60425964 frag_stream_info->next_trun_dts = dts + sc->time_offset;
60435965 if (i < entries) {
60445966 // EOF found before reading all entries. Fix the hole this would
6045− // leave in index_entries and ctts_data
5967+ // leave in index_entries and tts_data
60465968 int gap = entries - i;
60475969 memmove(sti->index_entries + index_entry_pos,
60485970 sti->index_entries + index_entry_pos + gap,
60495971 sizeof(*sti->index_entries) *
60505972 (sti->nb_index_entries - (index_entry_pos + gap)));
6051− memmove(sc->ctts_data + index_entry_pos,
6052− sc->ctts_data + index_entry_pos + gap,
6053− sizeof(*sc->ctts_data) *
6054− (sc->ctts_count - (index_entry_pos + gap)));
6055− memmove(sc->stts_data + index_entry_pos,
6056− sc->stts_data + index_entry_pos + gap,
6057− sizeof(*sc->stts_data) *
6058− (sc->stts_count - (index_entry_pos + gap)));
5973+ memmove(sc->tts_data + index_entry_pos,
5974+ sc->tts_data + index_entry_pos + gap,
5975+ sizeof(*sc->tts_data) *
5976+ (sc->tts_count - (index_entry_pos + gap)));
60595977
60605978 sti->nb_index_entries -= gap;
6061− sc->ctts_count -= gap;
6062− sc->stts_count -= gap;
5979+ sc->tts_count -= gap;
60635980 if (index_entry_pos < sc->current_sample) {
60645981 sc->current_sample -= gap;
60655982 }
@@ -9821,7 +9738,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st) · 3755 unmodified lines
98219738 return;
98229739 }
98239740
9824− av_freep(&sc->ctts_data);
9741+ av_freep(&sc->tts_data);
98259742 for (int i = 0; i < sc->drefs_count; i++) {
98269743 av_freep(&sc->drefs[i].path);
98279744 av_freep(&sc->drefs[i].dir);
@@ -9838,6 +9755,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st) · 10 unmodified lines
98389755 av_freep(&sc->stsc_data);
98399756 av_freep(&sc->sample_sizes);
98409757 av_freep(&sc->keyframes);
9758+ av_freep(&sc->ctts_data);
98419759 av_freep(&sc->stts_data);
98429760 av_freep(&sc->sdtp_data);
98439761 av_freep(&sc->stps_data);
@@ -10859,27 +10777,10 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s · 1015 unmodified lines
1085910777 if (sample->flags & AVINDEX_DISCARD_FRAME) {
1086010778 pkt->flags |= AV_PKT_FLAG_DISCARD;
1086110779 }
10862− if (sc->stts_data && sc->stts_index < sc->stts_count) {
10863− pkt->duration = sc->stts_data[sc->stts_index].duration;
10864−
10865− /* update stts context */
10866− sc->stts_sample++;
10867− if (sc->stts_index < sc->stts_count &&
10868− sc->stts_data[sc->stts_index].count == sc->stts_sample) {
10869− sc->stts_index++;
10870− sc->stts_sample = 0;
10871− }
10872− }
10873− if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
10874− pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, sc->ctts_data[sc->ctts_index].offset));
10875−
10876− /* update ctts context */
10877− sc->ctts_sample++;
10878− if (sc->ctts_index < sc->ctts_count &&
10879− sc->ctts_data[sc->ctts_index].count == sc->ctts_sample) {
10880− sc->ctts_index++;
10881− sc->ctts_sample = 0;
10882− }
10780+ if (sc->stts_count && sc->tts_index < sc->tts_count)
10781+ pkt->duration = sc->tts_data[sc->tts_index].duration;
10782+ if (sc->ctts_count && sc->tts_index < sc->tts_count) {
10783+ pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, sc->tts_data[sc->tts_index].offset));
1088310784 } else {
1088410785 if (pkt->duration == 0) {
1088510786 int64_t next_dts = (sc->current_sample < ffstream(st)->nb_index_entries) ?
@@ -10890,6 +10791,16 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s · 4 unmodified lines
1089010791 pkt->pts = pkt->dts;
1089110792 }
1089210793
10794+ if (sc->tts_data && sc->tts_index < sc->tts_count) {
10795+ /* update tts context */
10796+ sc->tts_sample++;
10797+ if (sc->tts_index < sc->tts_count &&
10798+ sc->tts_data[sc->tts_index].count == sc->tts_sample) {
10799+ sc->tts_index++;
10800+ sc->tts_sample = 0;
10801+ }
10802+ }
10803+
1089310804 if (sc->sdtp_data && sc->current_sample <= sc->sdtp_count) {
1089410805 uint8_t sample_flags = sc->sdtp_data[sc->current_sample - 1];
1089510806 uint8_t sample_is_depended_on = (sample_flags >> 2) & 0x3;
@@ -10952,7 +10863,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) · 56 unmodified lines
1095210863
1095310864 // Clear current sample
1095410865 mov_current_sample_set(msc, 0);
10955− msc->ctts_index = 0;
10866+ msc->tts_index = 0;
1095610867
1095710868 // Discard current index entries
1095810869 avsti = ffstream(avst);
@@ -11185,27 +11096,14 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, · 226 unmodified lines
1118511096
1118611097 mov_current_sample_set(sc, sample);
1118711098 av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, sc->current_sample);
11188− /* adjust stts index */
11189− if (sc->stts_data) {
11190− time_sample = 0;
11191− for (i = 0; i < sc->stts_count; i++) {
11192− int next = time_sample + sc->stts_data[i].count;
11193− if (next > sc->current_sample) {
11194− sc->stts_index = i;
11195− sc->stts_sample = sc->current_sample - time_sample;
11196− break;
11197− }
11198− time_sample = next;
11199− }
11200− }
11201− /* adjust ctts index */
11202− if (sc->ctts_data) {
11099+ /* adjust time to sample index */
11100+ if (sc->tts_data) {
1120311101 time_sample = 0;
11204− for (i = 0; i < sc->ctts_count; i++) {
11205− int next = time_sample + sc->ctts_data[i].count;
11102+ for (i = 0; i < sc->tts_count; i++) {
11103+ int next = time_sample + sc->tts_data[i].count;
1120611104 if (next > sc->current_sample) {
11207− sc->ctts_index = i;
11208− sc->ctts_sample = sc->current_sample - time_sample;
11105+ sc->tts_index = i;
11106+ sc->tts_sample = sc->current_sample - time_sample;
1120911107 break;
1121011108 }
1121111109 time_sample = next;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t