[FFmpeg-devel] [PATCH] avformat/mov: merge stts and ctts arrays into one
James Almer
jamrial at gmail.com
Wed Nov 27 16:10:09 EET 2024
Should reduce memory usage as well as remove code duplication.
Signed-off-by: James Almer <jamrial at gmail.com>
---
libavformat/isom.h | 15 +-
libavformat/mov.c | 544 +++++++++++++++++----------------------------
2 files changed, 221 insertions(+), 338 deletions(-)
diff --git a/libavformat/isom.h b/libavformat/isom.h
index f18b15bbff..08c41a24a9 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -54,6 +54,12 @@ 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;
@@ -173,6 +179,9 @@ typedef struct MOVStreamContext {
int next_chunk;
unsigned int chunk_count;
int64_t *chunk_offsets;
+ unsigned int tts_count;
+ unsigned int tts_allocated_size;
+ MOVTimeToSample *tts_data;
unsigned int stts_count;
unsigned int stts_allocated_size;
MOVStts *stts_data;
@@ -189,10 +198,8 @@ typedef struct MOVStreamContext {
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
MOVElst *elst_data;
unsigned int elst_count;
- int stts_index;
- int stts_sample;
- int ctts_index;
- int ctts_sample;
+ 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 24feadb95b..2e34a6349d 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -86,8 +86,6 @@ typedef struct MOVParseTableEntry {
static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom);
static int mov_read_mfra(MOVContext *c, AVIOContext *f);
static void mov_free_stream_context(AVFormatContext *s, AVStream *st);
-static int64_t add_ctts_entry(MOVCtts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size,
- int count, int duration);
static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
unsigned len, const char *key)
@@ -3711,6 +3709,12 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR(ENOMEM);
for (i = 0; i < entries && !pb->eof_reached; i++) {
+ MOVCtts *ctts_data;
+ const size_t min_size_needed = (ctts_count + 1) * sizeof(MOVCtts);
+ const size_t requested_size =
+ min_size_needed > sc->ctts_allocated_size ?
+ FFMAX(min_size_needed, 2 * sc->ctts_allocated_size) :
+ min_size_needed;
int count = avio_rb32(pb);
int duration = avio_rb32(pb);
@@ -3721,8 +3725,19 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
continue;
}
- add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size,
- count, duration);
+ if (ctts_count >= UINT_MAX / sizeof(MOVCtts) - 1)
+ return AVERROR(ENOMEM);
+
+ ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, requested_size);
+
+ if (!ctts_data)
+ return AVERROR(ENOMEM);
+
+ sc->ctts_data = ctts_data;
+
+ ctts_data[ctts_count].count = count;
+ ctts_data[ctts_count].offset = duration;
+ ctts_count++;
av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n",
count, duration);
@@ -3916,24 +3931,19 @@ static int get_edit_list_entry(MOVContext *mov,
static int find_prev_closest_index(AVStream *st,
AVIndexEntry *e_old,
int nb_old,
- MOVStts* stts_data,
- int64_t stts_count,
- MOVCtts* ctts_data,
- int64_t ctts_count,
+ MOVTimeToSample *tts_data,
+ int64_t tts_count,
int64_t timestamp_pts,
int flag,
int64_t* index,
- int64_t* stts_index,
- int64_t* stts_sample,
- int64_t* ctts_index,
- int64_t* ctts_sample)
+ int64_t* tts_index,
+ int64_t* tts_sample)
{
MOVStreamContext *msc = st->priv_data;
FFStream *const sti = ffstream(st);
AVIndexEntry *e_keep = sti->index_entries;
int nb_keep = sti->nb_index_entries;
int64_t i = 0;
- int64_t index_ctts_count;
av_assert0(index);
@@ -3961,64 +3971,39 @@ static int find_prev_closest_index(AVStream *st,
// If we have CTTS then refine the search, by searching backwards over PTS
// computed by adding corresponding CTTS durations to index timestamps.
- if (ctts_data && *index >= 0) {
- av_assert0(ctts_index);
- av_assert0(ctts_sample);
+ if (tts_data && *index >= 0) {
+ av_assert0(tts_index);
+ av_assert0(tts_sample);
// Find out the ctts_index for the found frame.
- *ctts_index = 0;
- *ctts_sample = 0;
-
- if (stts_data) {
- av_assert0(stts_index);
- av_assert0(stts_sample);
-
- *stts_index = 0;
- *stts_sample = 0;
- }
-
- for (index_ctts_count = 0; index_ctts_count < *index; index_ctts_count++) {
- if (*ctts_index < ctts_count) {
- (*ctts_sample)++;
- if (ctts_data[*ctts_index].count == *ctts_sample) {
- (*ctts_index)++;
- *ctts_sample = 0;
- }
- }
- if (stts_data && *stts_index < stts_count) {
- (*stts_sample)++;
- if (stts_data[*stts_index].count == *stts_sample) {
- (*stts_index)++;
- *stts_sample = 0;
+ *tts_index = 0;
+ *tts_sample = 0;
+
+ for (int64_t index_tts_count = 0; index_tts_count < *index; index_tts_count++) {
+ if (*tts_index < tts_count) {
+ (*tts_sample)++;
+ if (tts_data[*tts_index].count == *tts_sample) {
+ (*tts_index)++;
+ *tts_sample = 0;
}
}
}
- while (*index >= 0 && (*ctts_index) >= 0 && (*ctts_index) < ctts_count) {
+ 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 becase timestamp_pts has already been
// compensated by dts_shift above.
- if ((e_old[*index].timestamp + ctts_data[*ctts_index].offset) <= timestamp_pts &&
+ if ((e_old[*index].timestamp + tts_data[*tts_index].offset) <= timestamp_pts &&
(e_old[*index].flags & AVINDEX_KEYFRAME)) {
break;
}
(*index)--;
- if (*ctts_sample == 0) {
- (*ctts_index)--;
- if (*ctts_index >= 0)
- *ctts_sample = ctts_data[*ctts_index].count - 1;
+ if (*tts_sample == 0) {
+ (*tts_index)--;
+ if (*tts_index >= 0)
+ *tts_sample = tts_data[*tts_index].count - 1;
} else {
- (*ctts_sample)--;
- }
- if (stts_data) {
- if (*stts_sample == 0) {
- (*stts_index)--;
- if (*stts_index >= 0) {
- *stts_sample = stts_data[*stts_index].count - 1;
- }
- } else {
- (*stts_sample)--;
- }
+ (*tts_sample)--;
}
}
}
@@ -4093,62 +4078,32 @@ static void fix_index_entry_timestamps(AVStream* st, int end_index, int64_t end_
}
}
-static int64_t add_stts_entry(MOVStts** stts_data, unsigned int* stts_count, unsigned int* allocated_size,
- int count, int duration)
+static int add_tts_entry(MOVTimeToSample **tts_data, unsigned int *tts_count, unsigned int *allocated_size,
+ int count, int offset, unsigned int duration)
{
- MOVStts *stts_buf_new;
- const size_t min_size_needed = (*stts_count + 1) * sizeof(MOVStts);
+ 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;
- if ((unsigned)(*stts_count) >= UINT_MAX / sizeof(MOVStts) - 1)
+ if ((unsigned)(*tts_count) >= UINT_MAX / sizeof(MOVTimeToSample) - 1)
return -1;
- stts_buf_new = av_fast_realloc(*stts_data, allocated_size, requested_size);
+ tts_buf_new = av_fast_realloc(*tts_data, allocated_size, requested_size);
- if (!stts_buf_new)
+ if (!tts_buf_new)
return -1;
- *stts_data = stts_buf_new;
-
- stts_buf_new[*stts_count].count = count;
- stts_buf_new[*stts_count].duration = duration;
+ *tts_data = tts_buf_new;
- *stts_count = (*stts_count) + 1;
- return *stts_count;
-}
+ tts_buf_new[*tts_count].count = count;
+ tts_buf_new[*tts_count].offset = offset;
+ tts_buf_new[*tts_count].duration = duration;
-/**
- * Append a new ctts entry to ctts_data.
- * Returns the new ctts_count if successful, else returns -1.
- */
-static int64_t add_ctts_entry(MOVCtts** ctts_data, unsigned int* ctts_count, unsigned int* allocated_size,
- int count, int offset)
-{
- MOVCtts *ctts_buf_new;
- const size_t min_size_needed = (*ctts_count + 1) * sizeof(MOVCtts);
- const size_t requested_size =
- min_size_needed > *allocated_size ?
- FFMAX(min_size_needed, 2 * (*allocated_size)) :
- min_size_needed;
-
- if ((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVCtts) - 1)
- return -1;
-
- ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size);
-
- if (!ctts_buf_new)
- return -1;
-
- *ctts_data = ctts_buf_new;
-
- ctts_buf_new[*ctts_count].count = count;
- ctts_buf_new[*ctts_count].offset = offset;
-
- *ctts_count = (*ctts_count) + 1;
- return *ctts_count;
+ *tts_count = (*tts_count) + 1;
+ return 0;
}
#define MAX_REORDER_DELAY 16
@@ -4165,17 +4120,17 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st)
for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
pts_buf[j] = INT64_MIN;
- if (st->codecpar->video_delay <= 0 && msc->ctts_data &&
+ if (st->codecpar->video_delay <= 0 && msc->ctts_count &&
st->codecpar->codec_id == AV_CODEC_ID_H264) {
st->codecpar->video_delay = 0;
- for (int ind = 0; ind < sti->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) {
+ for (int ind = 0; ind < sti->nb_index_entries && ctts_ind < msc->tts_count; ++ind) {
// Point j to the last elem of the buffer and insert the current pts there.
j = buf_start;
buf_start = (buf_start + 1);
if (buf_start == MAX_REORDER_DELAY + 1)
buf_start = 0;
- pts_buf[j] = sti->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].offset;
+ pts_buf[j] = sti->index_entries[ind].timestamp + msc->tts_data[ctts_ind].offset;
// 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
@@ -4198,7 +4153,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->ctts_data[ctts_ind].count) {
+ if (ctts_sample == msc->tts_data[ctts_ind].count) {
ctts_ind++;
ctts_sample = 0;
}
@@ -4268,21 +4223,16 @@ 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;
- MOVStts *stts_data_old = msc->stts_data;
- int64_t stts_index_old = 0;
- int64_t stts_sample_old = 0;
- int64_t stts_count_old = msc->stts_count;
- MOVCtts *ctts_data_old = msc->ctts_data;
- int64_t ctts_index_old = 0;
- int64_t ctts_sample_old = 0;
- int64_t ctts_count_old = msc->ctts_count;
+ MOVTimeToSample *tts_data_old = msc->tts_data;
+ 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_stts_sample = 0;
- int64_t edit_list_start_ctts_sample = 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;
@@ -4319,16 +4269,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
sti->nb_index_entries = 0;
// Clean time to sample fields of MOVStreamContext
- msc->stts_data = NULL;
- msc->stts_count = 0;
- msc->stts_index = 0;
- msc->stts_sample = 0;
- msc->stts_allocated_size = 0;
- msc->ctts_data = NULL;
- msc->ctts_count = 0;
- msc->ctts_index = 0;
- msc->ctts_sample = 0;
- msc->ctts_allocated_size = 0;
+ msc->tts_data = NULL;
+ msc->tts_count = 0;
+ msc->tts_index = 0;
+ msc->tts_sample = 0;
+ msc->tts_allocated_size = 0;
// Reinitialize min_corrected_pts so that it can be computed again.
msc->min_corrected_pts = -1;
@@ -4381,26 +4326,23 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
search_timestamp = FFMAX(search_timestamp - msc->time_scale, e_old[0].timestamp);
}
- 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,
- &index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
+ 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) {
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, stts_data_old, stts_count_old, ctts_data_old, ctts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
- &index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
+ 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) {
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;
- stts_index_old = 0;
- stts_sample_old = 0;
- ctts_index_old = 0;
- ctts_sample_old = 0;
+ tts_index_old = 0;
+ tts_sample_old = 0;
}
}
current = e_old + index;
- edit_list_start_ctts_sample = ctts_sample_old;
- edit_list_start_stts_sample = stts_sample_old;
+ edit_list_start_tts_sample = tts_sample_old;
// Iterate over index and arrange it according to edit list
edit_list_start_encountered = 0;
@@ -4416,44 +4358,26 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
curr_cts = current->timestamp + msc->dts_shift;
curr_ctts = 0;
- if (stts_data_old && stts_index_old < stts_count_old) {
- stts_sample_old++;
- if (stts_sample_old == stts_data_old[stts_index_old].count) {
- if (add_stts_entry(&msc->stts_data, &msc->stts_count,
- &msc->stts_allocated_size,
- stts_data_old[stts_index_old].count - edit_list_start_stts_sample,
- stts_data_old[stts_index_old].duration) == -1) {
- av_log(mov->fc, AV_LOG_ERROR, "Cannot add STTS entry %"PRId64" - {%"PRId64", %d}\n",
- stts_index_old,
- stts_data_old[stts_index_old].count - edit_list_start_stts_sample,
- stts_data_old[stts_index_old].duration);
- break;
- }
- stts_index_old++;
- stts_sample_old = 0;
- edit_list_start_stts_sample = 0;
- }
- }
- if (ctts_data_old && ctts_index_old < ctts_count_old) {
- curr_ctts = ctts_data_old[ctts_index_old].offset;
+ if (tts_data_old && tts_index_old < tts_count_old) {
+ curr_ctts = tts_data_old[tts_index_old].offset;
av_log(mov->fc, AV_LOG_TRACE, "stts: %"PRId64" ctts: %"PRId64", ctts_index: %"PRId64", ctts_count: %"PRId64"\n",
- curr_cts, curr_ctts, ctts_index_old, ctts_count_old);
+ curr_cts, curr_ctts, tts_index_old, tts_count_old);
curr_cts += curr_ctts;
- ctts_sample_old++;
- if (ctts_sample_old == ctts_data_old[ctts_index_old].count) {
- if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count,
- &msc->ctts_allocated_size,
- ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
- ctts_data_old[ctts_index_old].offset) == -1) {
+ 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 CTTS entry %"PRId64" - {%"PRId64", %d}\n",
- ctts_index_old,
- ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
- ctts_data_old[ctts_index_old].offset);
+ tts_index_old,
+ tts_data_old[tts_index_old].count - edit_list_start_tts_sample,
+ tts_data_old[tts_index_old].offset);
break;
}
- ctts_index_old++;
- ctts_sample_old = 0;
- edit_list_start_ctts_sample = 0;
+ tts_index_old++;
+ tts_sample_old = 0;
+ edit_list_start_tts_sample = 0;
}
}
@@ -4539,7 +4463,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
// Break when found first key frame after edit entry completion
if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) &&
((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) {
- if (ctts_data_old) {
+ if (tts_data_old) {
// If we have CTTS and this is the first keyframe after edit elist,
// wait for one more, because there might be trailing B-frames after this I-frame
// that do belong to the edit.
@@ -4547,24 +4471,14 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
found_keyframe_after_edit = 1;
continue;
}
- if (ctts_sample_old != 0) {
- if (stts_data_old &&
- add_stts_entry(&msc->stts_data, &msc->stts_count,
- &msc->stts_allocated_size,
- stts_sample_old - edit_list_start_stts_sample,
- stts_data_old[stts_index_old].duration) == -1) {
- av_log(mov->fc, AV_LOG_ERROR, "Cannot add STTS entry %"PRId64" - {%"PRId64", %d}\n",
- stts_index_old, stts_sample_old - edit_list_start_stts_sample,
- stts_data_old[stts_index_old].duration);
- break;
- }
- if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count,
- &msc->ctts_allocated_size,
- ctts_sample_old - edit_list_start_ctts_sample,
- ctts_data_old[ctts_index_old].offset) == -1) {
+ 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 CTTS entry %"PRId64" - {%"PRId64", %d}\n",
- ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample,
- ctts_data_old[ctts_index_old].offset);
+ tts_index_old, tts_sample_old - edit_list_start_tts_sample,
+ tts_data_old[tts_index_old].offset);
break;
}
}
@@ -4595,8 +4509,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
// Free the old index and the old CTTS structures
av_free(e_old);
- av_free(stts_data_old);
- av_free(ctts_data_old);
+ av_free(tts_data_old);
av_freep(&frame_duration_buffer);
// Null terminate the index ranges array
@@ -4678,6 +4591,55 @@ static int build_open_gop_key_points(AVStream *st)
return 0;
}
+static int mov_merge_tts_arrays(MOVContext *mov, AVStream *st)
+{
+ MOVStreamContext *sc = st->priv_data;
+ unsigned int stts_count;
+ int ret = 0, idx = 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))
+ return -1;
+ sc->tts_data = av_fast_realloc(NULL, &sc->tts_allocated_size,
+ sc->sample_count * sizeof(*sc->tts_data));
+ if (!sc->tts_data)
+ return -1;
+
+ memset(sc->tts_data, 0, sc->tts_allocated_size);
+
+ for (int i = 0; i < sc->ctts_count &&
+ sc->tts_count < sc->sample_count; i++)
+ for (int j = 0; j < sc->ctts_data[i].count &&
+ sc->tts_count < sc->sample_count; j++) {
+ ret = add_tts_entry(&sc->tts_data, &sc->tts_count,
+ &sc->tts_allocated_size, 1,
+ sc->ctts_data[i].offset, 0);
+ if (ret < 0)
+ return ret;
+ }
+ av_freep(&sc->ctts_data);
+ sc->ctts_allocated_size = 0;
+
+ stts_count = FFMIN(sc->tts_count, sc->stts_count);
+ for (int i = 0; i < sc->stts_count &&
+ stts_count < sc->sample_count; i++)
+ for (int j = 0; j < sc->stts_data[i].count &&
+ stts_count < sc->sample_count; j++) {
+ if (sc->ctts_count)
+ sc->tts_data[idx++].duration = sc->stts_data[i].duration;
+ else
+ ret = add_tts_entry(&sc->tts_data, &sc->tts_count,
+ &sc->tts_allocated_size, 1,
+ 0, sc->stts_data[i].duration);
+ if (ret < 0)
+ return ret;
+ }
+ av_freep(&sc->stts_data);
+ sc->stts_allocated_size = 0;
+
+ return 0;
+}
+
static void mov_build_index(MOVContext *mov, AVStream *st)
{
MOVStreamContext *sc = st->priv_data;
@@ -4690,10 +4652,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
unsigned int stps_index = 0;
unsigned int i, j;
uint64_t stream_size = 0;
- MOVStts *stts_data_old = sc->stts_data;
- MOVCtts *ctts_data_old = sc->ctts_data;
- unsigned int stts_count_old = sc->stts_count;
- unsigned int ctts_count_old = sc->ctts_count;
int ret = build_open_gop_key_points(st);
if (ret < 0)
@@ -4773,53 +4731,10 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
}
sti->index_entries_allocated_size = (sti->nb_index_entries + sc->sample_count) * sizeof(*sti->index_entries);
- if (ctts_data_old) {
- // Expand ctts entries such that we have a 1-1 mapping with samples
- if (sc->sample_count >= UINT_MAX / sizeof(*sc->ctts_data))
- return;
- sc->ctts_count = 0;
- sc->ctts_allocated_size = 0;
- sc->ctts_data = av_fast_realloc(NULL, &sc->ctts_allocated_size,
- sc->sample_count * sizeof(*sc->ctts_data));
- if (!sc->ctts_data) {
- av_free(ctts_data_old);
- return;
- }
-
- memset((uint8_t*)(sc->ctts_data), 0, sc->ctts_allocated_size);
-
- for (i = 0; i < ctts_count_old &&
- sc->ctts_count < sc->sample_count; i++)
- for (j = 0; j < ctts_data_old[i].count &&
- sc->ctts_count < sc->sample_count; j++)
- add_ctts_entry(&sc->ctts_data, &sc->ctts_count,
- &sc->ctts_allocated_size, 1,
- ctts_data_old[i].offset);
- av_free(ctts_data_old);
- }
- if (stts_data_old) {
- // Expand stts entries such that we have a 1-1 mapping with samples
- if (sc->sample_count >= UINT_MAX / sizeof(*sc->stts_data))
- return;
- sc->stts_count = 0;
- sc->stts_allocated_size = 0;
- sc->stts_data = av_fast_realloc(NULL, &sc->stts_allocated_size,
- sc->sample_count * sizeof(*sc->stts_data));
- if (!sc->stts_data) {
- av_free(stts_data_old);
+ if (sc->ctts_data || sc->stts_data) {
+ ret = mov_merge_tts_arrays(mov, st);
+ if (ret < 0)
return;
- }
-
- memset((uint8_t*)(sc->stts_data), 0, sc->stts_allocated_size);
-
- for (i = 0; i < stts_count_old &&
- sc->stts_count < sc->sample_count; i++)
- for (j = 0; j < stts_data_old[i].count &&
- sc->stts_count < sc->sample_count; j++)
- add_stts_entry(&sc->stts_data, &sc->stts_count,
- &sc->stts_allocated_size, 1,
- stts_data_old[i].duration);
- av_free(stts_data_old);
}
for (i = 0; i < sc->chunk_count; i++) {
@@ -4901,12 +4816,12 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
current_offset += sample_size;
stream_size += sample_size;
- current_dts += sc->stts_data[stts_index].duration;
+ current_dts += sc->tts_data[stts_index].duration;
distance++;
stts_sample++;
current_sample++;
- if (stts_index + 1 < sc->stts_count && stts_sample == sc->stts_data[stts_index].count) {
+ if (stts_index + 1 < sc->tts_count && stts_sample == sc->tts_data[stts_index].count) {
stts_sample = 0;
stts_index++;
}
@@ -4917,6 +4832,12 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
} else {
unsigned chunk_samples, total = 0;
+ if (sc->ctts_data || sc->stts_data) {
+ ret = mov_merge_tts_arrays(mov, st);
+ if (ret < 0)
+ return;
+ }
+
if (!sc->chunk_count)
return;
@@ -5024,8 +4945,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 = sti->index_entries[0].timestamp + sc->dts_shift;
- if (sc->ctts_data) {
- st->start_time += sc->ctts_data[0].offset;
+ if (sc->tts_data) {
+ st->start_time += sc->tts_data[0].offset;
}
}
@@ -5299,14 +5220,14 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
#if FF_API_R_FRAME_RATE
- for (int i = 1; sc->stts_count && i < sc->stts_count - 1; i++) {
- if (sc->stts_data[i].duration == sc->stts_data[0].duration)
+ for (int i = 1; sc->tts_count && i < sc->tts_count - 1; i++) {
+ if (sc->tts_data[i].duration == sc->tts_data[0].duration)
continue;
stts_constant = 0;
}
if (stts_constant)
av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,
- sc->time_scale, sc->stts_data[0].duration, INT_MAX);
+ sc->time_scale, sc->tts_data[0].duration, INT_MAX);
#endif
}
@@ -5337,8 +5258,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (st->codecpar->codec_id == AV_CODEC_ID_MP3
&& sc->time_scale == st->codecpar->sample_rate) {
int stts_constant = 1;
- for (int i = 1; i < sc->stts_count; i++) {
- if (sc->stts_data[i].duration == sc->stts_data[0].duration)
+ for (int i = 1; i < sc->tts_count; i++) {
+ if (sc->tts_data[i].duration == sc->tts_data[0].duration)
continue;
stts_constant = 0;
}
@@ -5821,8 +5742,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *st = NULL;
FFStream *sti = NULL;
MOVStreamContext *sc;
- MOVStts *stts_data;
- MOVCtts *ctts_data;
+ MOVTimeToSample *tts_data;
uint64_t offset;
int64_t dts, pts = AV_NOPTS_VALUE;
int data_offset = 0;
@@ -5878,7 +5798,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
entries = avio_rb32(pb);
av_log(c->fc, AV_LOG_TRACE, "flags 0x%x entries %u\n", flags, entries);
- if ((uint64_t)entries+sc->ctts_count >= UINT_MAX/sizeof(*sc->ctts_data))
+ if ((uint64_t)entries+sc->tts_count >= UINT_MAX/sizeof(*sc->tts_data))
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);
@@ -5951,52 +5871,36 @@ 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->ctts_data);
- old_allocated_size = sc->ctts_allocated_size;
- ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size,
+ requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->tts_data);
+ old_allocated_size = sc->tts_allocated_size;
+ tts_data = av_fast_realloc(sc->tts_data, &sc->tts_allocated_size,
requested_size);
- if (!ctts_data)
+ if (!tts_data)
return AVERROR(ENOMEM);
- sc->ctts_data = ctts_data;
+ sc->tts_data = tts_data;
- // In case there were samples without ctts entries, ensure they get
+ // 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 ctts entries don't pickup uninitialized data.
- memset((uint8_t*)(sc->ctts_data) + old_allocated_size, 0,
- sc->ctts_allocated_size - old_allocated_size);
-
- requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->stts_data);
- old_allocated_size = sc->stts_allocated_size;
- stts_data = av_fast_realloc(sc->stts_data, &sc->stts_allocated_size,
- requested_size);
- if (!stts_data)
- return AVERROR(ENOMEM);
- sc->stts_data = stts_data;
-
- // See the comment for ctts above.
- memset((uint8_t*)(sc->stts_data) + old_allocated_size, 0,
- sc->stts_allocated_size - old_allocated_size);
+ // without time to sample entries don't pickup uninitialized data.
+ memset((uint8_t*)(sc->tts_data) + old_allocated_size, 0,
+ sc->tts_allocated_size - old_allocated_size);
if (index_entry_pos < sti->nb_index_entries) {
- // Make hole in index_entries and ctts_data for new samples
+ // Make hole in index_entries and tts_data for new samples
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->ctts_data + index_entry_pos + entries,
- sc->ctts_data + index_entry_pos,
- sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos));
- memmove(sc->stts_data + index_entry_pos + entries,
- sc->stts_data + index_entry_pos,
- sizeof(*sc->stts_data) * (sc->stts_count - index_entry_pos));
+ memmove(sc->tts_data + index_entry_pos + entries,
+ sc->tts_data + index_entry_pos,
+ sizeof(*sc->tts_data) * (sc->tts_count - index_entry_pos));
if (index_entry_pos < sc->current_sample) {
sc->current_sample += entries;
}
}
sti->nb_index_entries += entries;
- sc->ctts_count = sti->nb_index_entries;
- sc->stts_count = sti->nb_index_entries;
+ sc->tts_count = sti->nb_index_entries;
// Record the index_entry position in frag_index of this fragment
if (frag_stream_info) {
@@ -6058,10 +5962,9 @@ 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->ctts_data[index_entry_pos].count = 1;
- sc->ctts_data[index_entry_pos].offset = ctts_duration;
- sc->stts_data[index_entry_pos].count = 1;
- sc->stts_data[index_entry_pos].duration = sample_duration;
+ 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;
index_entry_pos++;
av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
@@ -6087,24 +5990,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 ctts_data
+ // leave in index_entries and tts_data
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->ctts_data + index_entry_pos,
- sc->ctts_data + index_entry_pos + gap,
- sizeof(*sc->ctts_data) *
- (sc->ctts_count - (index_entry_pos + gap)));
- memmove(sc->stts_data + index_entry_pos,
- sc->stts_data + index_entry_pos + gap,
- sizeof(*sc->stts_data) *
- (sc->stts_count - (index_entry_pos + gap)));
+ memmove(sc->tts_data + index_entry_pos,
+ sc->tts_data + index_entry_pos + gap,
+ sizeof(*sc->tts_data) *
+ (sc->tts_count - (index_entry_pos + gap)));
sti->nb_index_entries -= gap;
- sc->ctts_count -= gap;
- sc->stts_count -= gap;
+ sc->tts_count -= gap;
if (index_entry_pos < sc->current_sample) {
sc->current_sample -= gap;
}
@@ -9865,7 +9763,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
return;
}
- av_freep(&sc->ctts_data);
+ av_freep(&sc->tts_data);
for (int i = 0; i < sc->drefs_count; i++) {
av_freep(&sc->drefs[i].path);
av_freep(&sc->drefs[i].dir);
@@ -9882,6 +9780,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
av_freep(&sc->stsc_data);
av_freep(&sc->sample_sizes);
av_freep(&sc->keyframes);
+ av_freep(&sc->ctts_data);
av_freep(&sc->stts_data);
av_freep(&sc->sdtp_data);
av_freep(&sc->stps_data);
@@ -10876,26 +10775,16 @@ 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_data && sc->stts_index < sc->stts_count) {
- pkt->duration = sc->stts_data[sc->stts_index].duration;
-
- /* update stts context */
- sc->stts_sample++;
- if (sc->stts_index < sc->stts_count &&
- sc->stts_data[sc->stts_index].count == sc->stts_sample) {
- sc->stts_index++;
- sc->stts_sample = 0;
- }
- }
- if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
- pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, sc->ctts_data[sc->ctts_index].offset));
+ if (sc->tts_data && sc->tts_index < sc->tts_count) {
+ pkt->duration = sc->tts_data[sc->tts_index].duration;
+ pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, sc->tts_data[sc->tts_index].offset));
- /* update ctts context */
- sc->ctts_sample++;
- if (sc->ctts_index < sc->ctts_count &&
- sc->ctts_data[sc->ctts_index].count == sc->ctts_sample) {
- sc->ctts_index++;
- sc->ctts_sample = 0;
+ /* 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;
}
} else {
if (pkt->duration == 0) {
@@ -10966,7 +10855,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
// Clear current sample
mov_current_sample_set(msc, 0);
- msc->ctts_index = 0;
+ msc->tts_index = 0;
// Discard current index entries
avsti = ffstream(avst);
@@ -11199,27 +11088,14 @@ 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 stts index */
- if (sc->stts_data) {
- time_sample = 0;
- for (i = 0; i < sc->stts_count; i++) {
- int next = time_sample + sc->stts_data[i].count;
- if (next > sc->current_sample) {
- sc->stts_index = i;
- sc->stts_sample = sc->current_sample - time_sample;
- break;
- }
- time_sample = next;
- }
- }
- /* adjust ctts index */
- if (sc->ctts_data) {
+ /* adjust time to sample index */
+ if (sc->tts_data) {
time_sample = 0;
- for (i = 0; i < sc->ctts_count; i++) {
- int next = time_sample + sc->ctts_data[i].count;
+ for (i = 0; i < sc->tts_count; i++) {
+ int next = time_sample + sc->tts_data[i].count;
if (next > sc->current_sample) {
- sc->ctts_index = i;
- sc->ctts_sample = sc->current_sample - time_sample;
+ sc->tts_index = i;
+ sc->tts_sample = sc->current_sample - time_sample;
break;
}
time_sample = next;
--
2.47.0
More information about the ffmpeg-devel
mailing list