forked from FFmpeg/FFmpeg
avformat/mov: merge stts and ctts arrays into one
Should reduce memory usage as well as remove code duplication. Signed-off-by: James Almer <jamrial@gmail.com>
This commit is contained in:
parent
d7180a3f92
commit
292c1df7c1
2 changed files with 249 additions and 344 deletions
|
@ -54,6 +54,12 @@ struct AVAESCTR;
|
||||||
* Here we just use what is needed to read the chunks
|
* 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 {
|
typedef struct MOVStts {
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int duration;
|
unsigned int duration;
|
||||||
|
@ -173,6 +179,9 @@ typedef struct MOVStreamContext {
|
||||||
int next_chunk;
|
int next_chunk;
|
||||||
unsigned int chunk_count;
|
unsigned int chunk_count;
|
||||||
int64_t *chunk_offsets;
|
int64_t *chunk_offsets;
|
||||||
|
unsigned int tts_count;
|
||||||
|
unsigned int tts_allocated_size;
|
||||||
|
MOVTimeToSample *tts_data;
|
||||||
unsigned int stts_count;
|
unsigned int stts_count;
|
||||||
unsigned int stts_allocated_size;
|
unsigned int stts_allocated_size;
|
||||||
MOVStts *stts_data;
|
MOVStts *stts_data;
|
||||||
|
@ -189,10 +198,8 @@ typedef struct MOVStreamContext {
|
||||||
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
|
unsigned *stps_data; ///< partial sync sample for mpeg-2 open gop
|
||||||
MOVElst *elst_data;
|
MOVElst *elst_data;
|
||||||
unsigned int elst_count;
|
unsigned int elst_count;
|
||||||
int stts_index;
|
int tts_index;
|
||||||
int stts_sample;
|
int tts_sample;
|
||||||
int ctts_index;
|
|
||||||
int ctts_sample;
|
|
||||||
unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
|
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 stsz_sample_size; ///< always contains sample size from stsz atom
|
||||||
unsigned int sample_count;
|
unsigned int sample_count;
|
||||||
|
|
|
@ -87,8 +87,6 @@ typedef struct MOVParseTableEntry {
|
||||||
static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom);
|
static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom);
|
||||||
static int mov_read_mfra(MOVContext *c, AVIOContext *f);
|
static int mov_read_mfra(MOVContext *c, AVIOContext *f);
|
||||||
static void mov_free_stream_context(AVFormatContext *s, AVStream *st);
|
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,
|
static int mov_metadata_track_or_disc_number(MOVContext *c, AVIOContext *pb,
|
||||||
unsigned len, const char *key)
|
unsigned len, const char *key)
|
||||||
|
@ -3666,6 +3664,12 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
for (i = 0; i < entries && !pb->eof_reached; i++) {
|
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 count = avio_rb32(pb);
|
||||||
int duration = avio_rb32(pb);
|
int duration = avio_rb32(pb);
|
||||||
|
|
||||||
|
@ -3676,8 +3680,19 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size,
|
if (ctts_count >= UINT_MAX / sizeof(MOVCtts) - 1)
|
||||||
count, duration);
|
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",
|
av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n",
|
||||||
count, duration);
|
count, duration);
|
||||||
|
@ -3871,24 +3886,19 @@ static int get_edit_list_entry(MOVContext *mov,
|
||||||
static int find_prev_closest_index(AVStream *st,
|
static int find_prev_closest_index(AVStream *st,
|
||||||
AVIndexEntry *e_old,
|
AVIndexEntry *e_old,
|
||||||
int nb_old,
|
int nb_old,
|
||||||
MOVStts* stts_data,
|
MOVTimeToSample *tts_data,
|
||||||
int64_t stts_count,
|
int64_t tts_count,
|
||||||
MOVCtts* ctts_data,
|
|
||||||
int64_t ctts_count,
|
|
||||||
int64_t timestamp_pts,
|
int64_t timestamp_pts,
|
||||||
int flag,
|
int flag,
|
||||||
int64_t* index,
|
int64_t* index,
|
||||||
int64_t* stts_index,
|
int64_t* tts_index,
|
||||||
int64_t* stts_sample,
|
int64_t* tts_sample)
|
||||||
int64_t* ctts_index,
|
|
||||||
int64_t* ctts_sample)
|
|
||||||
{
|
{
|
||||||
MOVStreamContext *msc = st->priv_data;
|
MOVStreamContext *msc = st->priv_data;
|
||||||
FFStream *const sti = ffstream(st);
|
FFStream *const sti = ffstream(st);
|
||||||
AVIndexEntry *e_keep = sti->index_entries;
|
AVIndexEntry *e_keep = sti->index_entries;
|
||||||
int nb_keep = sti->nb_index_entries;
|
int nb_keep = sti->nb_index_entries;
|
||||||
int64_t i = 0;
|
int64_t i = 0;
|
||||||
int64_t index_ctts_count;
|
|
||||||
|
|
||||||
av_assert0(index);
|
av_assert0(index);
|
||||||
|
|
||||||
|
@ -3916,64 +3926,38 @@ static int find_prev_closest_index(AVStream *st,
|
||||||
|
|
||||||
// If we have CTTS then refine the search, by searching backwards over PTS
|
// If we have CTTS then refine the search, by searching backwards over PTS
|
||||||
// computed by adding corresponding CTTS durations to index timestamps.
|
// computed by adding corresponding CTTS durations to index timestamps.
|
||||||
if (ctts_data && *index >= 0) {
|
if (msc->ctts_count && *index >= 0) {
|
||||||
av_assert0(ctts_index);
|
av_assert0(tts_index);
|
||||||
av_assert0(ctts_sample);
|
av_assert0(tts_sample);
|
||||||
// Find out the ctts_index for the found frame.
|
// Find out the ctts_index for the found frame.
|
||||||
*ctts_index = 0;
|
*tts_index = 0;
|
||||||
*ctts_sample = 0;
|
*tts_sample = 0;
|
||||||
|
for (int64_t index_tts_count = 0; index_tts_count < *index; index_tts_count++) {
|
||||||
if (stts_data) {
|
if (*tts_index < tts_count) {
|
||||||
av_assert0(stts_index);
|
(*tts_sample)++;
|
||||||
av_assert0(stts_sample);
|
if (tts_data[*tts_index].count == *tts_sample) {
|
||||||
|
(*tts_index)++;
|
||||||
*stts_index = 0;
|
*tts_sample = 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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).
|
// 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
|
// No need to add dts_shift to the timestamp here becase timestamp_pts has already been
|
||||||
// compensated by dts_shift above.
|
// 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)) {
|
(e_old[*index].flags & AVINDEX_KEYFRAME)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*index)--;
|
(*index)--;
|
||||||
if (*ctts_sample == 0) {
|
if (*tts_sample == 0) {
|
||||||
(*ctts_index)--;
|
(*tts_index)--;
|
||||||
if (*ctts_index >= 0)
|
if (*tts_index >= 0)
|
||||||
*ctts_sample = ctts_data[*ctts_index].count - 1;
|
*tts_sample = tts_data[*tts_index].count - 1;
|
||||||
} else {
|
} else {
|
||||||
(*ctts_sample)--;
|
(*tts_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)--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4048,62 +4032,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,
|
static int add_tts_entry(MOVTimeToSample **tts_data, unsigned int *tts_count, unsigned int *allocated_size,
|
||||||
int count, int duration)
|
int count, int offset, unsigned int duration)
|
||||||
{
|
{
|
||||||
MOVStts *stts_buf_new;
|
MOVTimeToSample *tts_buf_new;
|
||||||
const size_t min_size_needed = (*stts_count + 1) * sizeof(MOVStts);
|
const size_t min_size_needed = (*tts_count + 1) * sizeof(MOVTimeToSample);
|
||||||
const size_t requested_size =
|
const size_t requested_size =
|
||||||
min_size_needed > *allocated_size ?
|
min_size_needed > *allocated_size ?
|
||||||
FFMAX(min_size_needed, 2 * (*allocated_size)) :
|
FFMAX(min_size_needed, 2 * (*allocated_size)) :
|
||||||
min_size_needed;
|
min_size_needed;
|
||||||
|
|
||||||
if ((unsigned)(*stts_count) >= UINT_MAX / sizeof(MOVStts) - 1)
|
if ((unsigned)(*tts_count) >= UINT_MAX / sizeof(MOVTimeToSample) - 1)
|
||||||
return -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;
|
return -1;
|
||||||
|
|
||||||
*stts_data = stts_buf_new;
|
*tts_data = tts_buf_new;
|
||||||
|
|
||||||
stts_buf_new[*stts_count].count = count;
|
tts_buf_new[*tts_count].count = count;
|
||||||
stts_buf_new[*stts_count].duration = duration;
|
tts_buf_new[*tts_count].offset = offset;
|
||||||
|
tts_buf_new[*tts_count].duration = duration;
|
||||||
|
|
||||||
*stts_count = (*stts_count) + 1;
|
*tts_count = (*tts_count) + 1;
|
||||||
return *stts_count;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_REORDER_DELAY 16
|
#define MAX_REORDER_DELAY 16
|
||||||
|
@ -4120,17 +4074,17 @@ static void mov_estimate_video_delay(MOVContext *c, AVStream* st)
|
||||||
for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
|
for (j = 0; j < MAX_REORDER_DELAY + 1; j++)
|
||||||
pts_buf[j] = INT64_MIN;
|
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->codec_id == AV_CODEC_ID_H264) {
|
||||||
st->codecpar->video_delay = 0;
|
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.
|
// Point j to the last elem of the buffer and insert the current pts there.
|
||||||
j = buf_start;
|
j = buf_start;
|
||||||
buf_start = (buf_start + 1);
|
buf_start = (buf_start + 1);
|
||||||
if (buf_start == MAX_REORDER_DELAY + 1)
|
if (buf_start == MAX_REORDER_DELAY + 1)
|
||||||
buf_start = 0;
|
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
|
// 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
|
// 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)
|
||||||
st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps);
|
st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps);
|
||||||
|
|
||||||
ctts_sample++;
|
ctts_sample++;
|
||||||
if (ctts_sample == msc->ctts_data[ctts_ind].count) {
|
if (ctts_sample == msc->tts_data[ctts_ind].count) {
|
||||||
ctts_ind++;
|
ctts_ind++;
|
||||||
ctts_sample = 0;
|
ctts_sample = 0;
|
||||||
}
|
}
|
||||||
|
@ -4223,21 +4177,16 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
int nb_old = sti->nb_index_entries;
|
int nb_old = sti->nb_index_entries;
|
||||||
const AVIndexEntry *e_old_end = e_old + nb_old;
|
const AVIndexEntry *e_old_end = e_old + nb_old;
|
||||||
const AVIndexEntry *current = NULL;
|
const AVIndexEntry *current = NULL;
|
||||||
MOVStts *stts_data_old = msc->stts_data;
|
MOVTimeToSample *tts_data_old = msc->tts_data;
|
||||||
int64_t stts_index_old = 0;
|
int64_t tts_index_old = 0;
|
||||||
int64_t stts_sample_old = 0;
|
int64_t tts_sample_old = 0;
|
||||||
int64_t stts_count_old = msc->stts_count;
|
int64_t tts_count_old = msc->tts_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;
|
|
||||||
int64_t edit_list_media_time = 0;
|
int64_t edit_list_media_time = 0;
|
||||||
int64_t edit_list_duration = 0;
|
int64_t edit_list_duration = 0;
|
||||||
int64_t frame_duration = 0;
|
int64_t frame_duration = 0;
|
||||||
int64_t edit_list_dts_counter = 0;
|
int64_t edit_list_dts_counter = 0;
|
||||||
int64_t edit_list_dts_entry_end = 0;
|
int64_t edit_list_dts_entry_end = 0;
|
||||||
int64_t edit_list_start_stts_sample = 0;
|
int64_t edit_list_start_tts_sample = 0;
|
||||||
int64_t edit_list_start_ctts_sample = 0;
|
|
||||||
int64_t curr_cts;
|
int64_t curr_cts;
|
||||||
int64_t curr_ctts = 0;
|
int64_t curr_ctts = 0;
|
||||||
int64_t empty_edits_sum_duration = 0;
|
int64_t empty_edits_sum_duration = 0;
|
||||||
|
@ -4274,16 +4223,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
sti->nb_index_entries = 0;
|
sti->nb_index_entries = 0;
|
||||||
|
|
||||||
// Clean time to sample fields of MOVStreamContext
|
// Clean time to sample fields of MOVStreamContext
|
||||||
msc->stts_data = NULL;
|
msc->tts_data = NULL;
|
||||||
msc->stts_count = 0;
|
msc->tts_count = 0;
|
||||||
msc->stts_index = 0;
|
msc->tts_index = 0;
|
||||||
msc->stts_sample = 0;
|
msc->tts_sample = 0;
|
||||||
msc->stts_allocated_size = 0;
|
msc->tts_allocated_size = 0;
|
||||||
msc->ctts_data = NULL;
|
|
||||||
msc->ctts_count = 0;
|
|
||||||
msc->ctts_index = 0;
|
|
||||||
msc->ctts_sample = 0;
|
|
||||||
msc->ctts_allocated_size = 0;
|
|
||||||
|
|
||||||
// Reinitialize min_corrected_pts so that it can be computed again.
|
// Reinitialize min_corrected_pts so that it can be computed again.
|
||||||
msc->min_corrected_pts = -1;
|
msc->min_corrected_pts = -1;
|
||||||
|
@ -4336,26 +4280,23 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
search_timestamp = FFMAX(search_timestamp - msc->time_scale, e_old[0].timestamp);
|
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,
|
if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, tts_count_old, search_timestamp, 0,
|
||||||
&index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
|
&index, &tts_index_old, &tts_sample_old) < 0) {
|
||||||
av_log(mov->fc, AV_LOG_WARNING,
|
av_log(mov->fc, AV_LOG_WARNING,
|
||||||
"st: %d edit list: %"PRId64" Missing key frame while searching for timestamp: %"PRId64"\n",
|
"st: %d edit list: %"PRId64" Missing key frame while searching for timestamp: %"PRId64"\n",
|
||||||
st->index, edit_list_index, search_timestamp);
|
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,
|
if (find_prev_closest_index(st, e_old, nb_old, tts_data_old, tts_count_old, search_timestamp, AVSEEK_FLAG_ANY,
|
||||||
&index, &stts_index_old, &stts_sample_old, &ctts_index_old, &ctts_sample_old) < 0) {
|
&index, &tts_index_old, &tts_sample_old) < 0) {
|
||||||
av_log(mov->fc, AV_LOG_WARNING,
|
av_log(mov->fc, AV_LOG_WARNING,
|
||||||
"st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n",
|
"st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n",
|
||||||
st->index, edit_list_index, search_timestamp);
|
st->index, edit_list_index, search_timestamp);
|
||||||
index = 0;
|
index = 0;
|
||||||
stts_index_old = 0;
|
tts_index_old = 0;
|
||||||
stts_sample_old = 0;
|
tts_sample_old = 0;
|
||||||
ctts_index_old = 0;
|
|
||||||
ctts_sample_old = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current = e_old + index;
|
current = e_old + index;
|
||||||
edit_list_start_ctts_sample = ctts_sample_old;
|
edit_list_start_tts_sample = tts_sample_old;
|
||||||
edit_list_start_stts_sample = stts_sample_old;
|
|
||||||
|
|
||||||
// Iterate over index and arrange it according to edit list
|
// Iterate over index and arrange it according to edit list
|
||||||
edit_list_start_encountered = 0;
|
edit_list_start_encountered = 0;
|
||||||
|
@ -4371,44 +4312,26 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
curr_cts = current->timestamp + msc->dts_shift;
|
curr_cts = current->timestamp + msc->dts_shift;
|
||||||
curr_ctts = 0;
|
curr_ctts = 0;
|
||||||
|
|
||||||
if (stts_data_old && stts_index_old < stts_count_old) {
|
if (tts_data_old && tts_index_old < tts_count_old) {
|
||||||
stts_sample_old++;
|
curr_ctts = tts_data_old[tts_index_old].offset;
|
||||||
if (stts_sample_old == stts_data_old[stts_index_old].count) {
|
av_log(mov->fc, AV_LOG_TRACE, "stts: %"PRId64" ctts: %"PRId64", tts_index: %"PRId64", tts_count: %"PRId64"\n",
|
||||||
if (add_stts_entry(&msc->stts_data, &msc->stts_count,
|
curr_cts, curr_ctts, tts_index_old, tts_count_old);
|
||||||
&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;
|
|
||||||
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;
|
curr_cts += curr_ctts;
|
||||||
ctts_sample_old++;
|
tts_sample_old++;
|
||||||
if (ctts_sample_old == ctts_data_old[ctts_index_old].count) {
|
if (tts_sample_old == tts_data_old[tts_index_old].count) {
|
||||||
if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count,
|
if (add_tts_entry(&msc->tts_data, &msc->tts_count,
|
||||||
&msc->ctts_allocated_size,
|
&msc->tts_allocated_size,
|
||||||
ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
|
tts_data_old[tts_index_old].count - edit_list_start_tts_sample,
|
||||||
ctts_data_old[ctts_index_old].offset) == -1) {
|
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",
|
av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To Sample entry %"PRId64" - {%"PRId64", %d}\n",
|
||||||
ctts_index_old,
|
tts_index_old,
|
||||||
ctts_data_old[ctts_index_old].count - edit_list_start_ctts_sample,
|
tts_data_old[tts_index_old].count - edit_list_start_tts_sample,
|
||||||
ctts_data_old[ctts_index_old].offset);
|
tts_data_old[tts_index_old].offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctts_index_old++;
|
tts_index_old++;
|
||||||
ctts_sample_old = 0;
|
tts_sample_old = 0;
|
||||||
edit_list_start_ctts_sample = 0;
|
edit_list_start_tts_sample = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4494,7 +4417,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
// Break when found first key frame after edit entry completion
|
// Break when found first key frame after edit entry completion
|
||||||
if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) &&
|
if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) &&
|
||||||
((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) {
|
((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) {
|
||||||
if (ctts_data_old) {
|
if (msc->ctts_count) {
|
||||||
// If we have CTTS and this is the first keyframe after edit elist,
|
// 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
|
// wait for one more, because there might be trailing B-frames after this I-frame
|
||||||
// that do belong to the edit.
|
// that do belong to the edit.
|
||||||
|
@ -4502,24 +4425,14 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
found_keyframe_after_edit = 1;
|
found_keyframe_after_edit = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ctts_sample_old != 0) {
|
if (tts_sample_old != 0) {
|
||||||
if (stts_data_old &&
|
if (add_tts_entry(&msc->tts_data, &msc->tts_count,
|
||||||
add_stts_entry(&msc->stts_data, &msc->stts_count,
|
&msc->tts_allocated_size,
|
||||||
&msc->stts_allocated_size,
|
tts_sample_old - edit_list_start_tts_sample,
|
||||||
stts_sample_old - edit_list_start_stts_sample,
|
tts_data_old[tts_index_old].offset, tts_data_old[tts_index_old].duration) == -1) {
|
||||||
stts_data_old[stts_index_old].duration) == -1) {
|
av_log(mov->fc, AV_LOG_ERROR, "Cannot add Time To Sample entry %"PRId64" - {%"PRId64", %d}\n",
|
||||||
av_log(mov->fc, AV_LOG_ERROR, "Cannot add STTS entry %"PRId64" - {%"PRId64", %d}\n",
|
tts_index_old, tts_sample_old - edit_list_start_tts_sample,
|
||||||
stts_index_old, stts_sample_old - edit_list_start_stts_sample,
|
tts_data_old[tts_index_old].offset);
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4550,8 +4463,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st)
|
||||||
|
|
||||||
// Free the old index and the old CTTS structures
|
// Free the old index and the old CTTS structures
|
||||||
av_free(e_old);
|
av_free(e_old);
|
||||||
av_free(stts_data_old);
|
av_free(tts_data_old);
|
||||||
av_free(ctts_data_old);
|
|
||||||
av_freep(&frame_duration_buffer);
|
av_freep(&frame_duration_buffer);
|
||||||
|
|
||||||
// Null terminate the index ranges array
|
// Null terminate the index ranges array
|
||||||
|
@ -4633,6 +4545,76 @@ static int build_open_gop_key_points(AVStream *st)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MOV_MERGE_CTTS 1
|
||||||
|
#define MOV_MERGE_STTS 2
|
||||||
|
/*
|
||||||
|
* Merge stts and ctts arrays into a new combined array.
|
||||||
|
* stts_count and ctts_count may be left untouched as they will be
|
||||||
|
* used to check for the presence of either of them.
|
||||||
|
*/
|
||||||
|
static int mov_merge_tts_data(MOVContext *mov, AVStream *st, int flags)
|
||||||
|
{
|
||||||
|
MOVStreamContext *sc = st->priv_data;
|
||||||
|
int ctts = sc->ctts_data && (flags & MOV_MERGE_CTTS);
|
||||||
|
int stts = sc->stts_data && (flags & MOV_MERGE_STTS);
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
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))
|
||||||
|
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)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(sc->tts_data, 0, sc->tts_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_count = idx;
|
||||||
|
} else
|
||||||
|
sc->ctts_count = 0;
|
||||||
|
av_freep(&sc->ctts_data);
|
||||||
|
sc->ctts_allocated_size = 0;
|
||||||
|
|
||||||
|
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)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!sc->tts_data)
|
||||||
|
memset(tts_data, 0, sc->tts_allocated_size);
|
||||||
|
sc->tts_data = tts_data;
|
||||||
|
|
||||||
|
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_count = FFMAX(sc->tts_count, idx);
|
||||||
|
} else
|
||||||
|
sc->stts_count = 0;
|
||||||
|
av_freep(&sc->stts_data);
|
||||||
|
sc->stts_allocated_size = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void mov_build_index(MOVContext *mov, AVStream *st)
|
static void mov_build_index(MOVContext *mov, AVStream *st)
|
||||||
{
|
{
|
||||||
MOVStreamContext *sc = st->priv_data;
|
MOVStreamContext *sc = st->priv_data;
|
||||||
|
@ -4645,10 +4627,6 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
|
||||||
unsigned int stps_index = 0;
|
unsigned int stps_index = 0;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
uint64_t stream_size = 0;
|
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);
|
int ret = build_open_gop_key_points(st);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -4728,54 +4706,9 @@ 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);
|
sti->index_entries_allocated_size = (sti->nb_index_entries + sc->sample_count) * sizeof(*sti->index_entries);
|
||||||
|
|
||||||
if (ctts_data_old) {
|
ret = mov_merge_tts_data(mov, st, MOV_MERGE_CTTS | MOV_MERGE_STTS);
|
||||||
// Expand ctts entries such that we have a 1-1 mapping with samples
|
if (ret < 0)
|
||||||
if (sc->sample_count >= UINT_MAX / sizeof(*sc->ctts_data))
|
return;
|
||||||
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);
|
|
||||||
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++) {
|
for (i = 0; i < sc->chunk_count; i++) {
|
||||||
int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX;
|
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)
|
||||||
current_offset += sample_size;
|
current_offset += sample_size;
|
||||||
stream_size += sample_size;
|
stream_size += sample_size;
|
||||||
|
|
||||||
current_dts += sc->stts_data[stts_index].duration;
|
current_dts += sc->tts_data[stts_index].duration;
|
||||||
|
|
||||||
distance++;
|
distance++;
|
||||||
stts_sample++;
|
stts_sample++;
|
||||||
current_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_sample = 0;
|
||||||
stts_index++;
|
stts_index++;
|
||||||
}
|
}
|
||||||
|
@ -4872,6 +4805,10 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
|
||||||
} else {
|
} else {
|
||||||
unsigned chunk_samples, total = 0;
|
unsigned chunk_samples, total = 0;
|
||||||
|
|
||||||
|
ret = mov_merge_tts_data(mov, st, MOV_MERGE_CTTS);
|
||||||
|
if (ret < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!sc->chunk_count)
|
if (!sc->chunk_count)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -4979,8 +4916,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
|
||||||
// Update start time of the stream.
|
// 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) {
|
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;
|
st->start_time = sti->index_entries[0].timestamp + sc->dts_shift;
|
||||||
if (sc->ctts_data) {
|
if (sc->tts_data) {
|
||||||
st->start_time += sc->ctts_data[0].offset;
|
st->start_time += sc->tts_data[0].offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5254,14 +5191,14 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FF_API_R_FRAME_RATE
|
#if FF_API_R_FRAME_RATE
|
||||||
for (int i = 1; sc->stts_count && i < sc->stts_count - 1; i++) {
|
for (int i = 1; sc->stts_count && i < sc->tts_count - 1; i++) {
|
||||||
if (sc->stts_data[i].duration == sc->stts_data[0].duration)
|
if (sc->tts_data[i].duration == sc->tts_data[0].duration)
|
||||||
continue;
|
continue;
|
||||||
stts_constant = 0;
|
stts_constant = 0;
|
||||||
}
|
}
|
||||||
if (stts_constant)
|
if (stts_constant)
|
||||||
av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den,
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5292,8 +5229,8 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
if (st->codecpar->codec_id == AV_CODEC_ID_MP3
|
if (st->codecpar->codec_id == AV_CODEC_ID_MP3
|
||||||
&& sc->time_scale == st->codecpar->sample_rate) {
|
&& sc->time_scale == st->codecpar->sample_rate) {
|
||||||
int stts_constant = 1;
|
int stts_constant = 1;
|
||||||
for (int i = 1; i < sc->stts_count; i++) {
|
for (int i = 1; sc->stts_count && i < sc->tts_count; i++) {
|
||||||
if (sc->stts_data[i].duration == sc->stts_data[0].duration)
|
if (sc->tts_data[i].duration == sc->tts_data[0].duration)
|
||||||
continue;
|
continue;
|
||||||
stts_constant = 0;
|
stts_constant = 0;
|
||||||
}
|
}
|
||||||
|
@ -5776,8 +5713,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
AVStream *st = NULL;
|
AVStream *st = NULL;
|
||||||
FFStream *sti = NULL;
|
FFStream *sti = NULL;
|
||||||
MOVStreamContext *sc;
|
MOVStreamContext *sc;
|
||||||
MOVStts *stts_data;
|
MOVTimeToSample *tts_data;
|
||||||
MOVCtts *ctts_data;
|
|
||||||
uint64_t offset;
|
uint64_t offset;
|
||||||
int64_t dts, pts = AV_NOPTS_VALUE;
|
int64_t dts, pts = AV_NOPTS_VALUE;
|
||||||
int data_offset = 0;
|
int data_offset = 0;
|
||||||
|
@ -5833,7 +5769,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
|
||||||
entries = avio_rb32(pb);
|
entries = avio_rb32(pb);
|
||||||
av_log(c->fc, AV_LOG_TRACE, "flags 0x%x entries %u\n", flags, entries);
|
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;
|
return AVERROR_INVALIDDATA;
|
||||||
if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
|
if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
|
||||||
if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
|
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)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
sti->index_entries= new_entries;
|
sti->index_entries= new_entries;
|
||||||
|
|
||||||
requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->ctts_data);
|
requested_size = (sti->nb_index_entries + entries) * sizeof(*sc->tts_data);
|
||||||
old_allocated_size = sc->ctts_allocated_size;
|
old_allocated_size = sc->tts_allocated_size;
|
||||||
ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size,
|
tts_data = av_fast_realloc(sc->tts_data, &sc->tts_allocated_size,
|
||||||
requested_size);
|
requested_size);
|
||||||
if (!ctts_data)
|
if (!tts_data)
|
||||||
return AVERROR(ENOMEM);
|
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
|
// zero valued entries. This ensures clips which mix boxes with and
|
||||||
// without ctts entries don't pickup uninitialized data.
|
// without time to sample entries don't pickup uninitialized data.
|
||||||
memset((uint8_t*)(sc->ctts_data) + old_allocated_size, 0,
|
memset((uint8_t*)(sc->tts_data) + old_allocated_size, 0,
|
||||||
sc->ctts_allocated_size - old_allocated_size);
|
sc->tts_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);
|
|
||||||
|
|
||||||
if (index_entry_pos < sti->nb_index_entries) {
|
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,
|
memmove(sti->index_entries + index_entry_pos + entries,
|
||||||
sti->index_entries + index_entry_pos,
|
sti->index_entries + index_entry_pos,
|
||||||
sizeof(*sti->index_entries) *
|
sizeof(*sti->index_entries) *
|
||||||
(sti->nb_index_entries - index_entry_pos));
|
(sti->nb_index_entries - index_entry_pos));
|
||||||
memmove(sc->ctts_data + index_entry_pos + entries,
|
memmove(sc->tts_data + index_entry_pos + entries,
|
||||||
sc->ctts_data + index_entry_pos,
|
sc->tts_data + index_entry_pos,
|
||||||
sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos));
|
sizeof(*sc->tts_data) * (sc->tts_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));
|
|
||||||
if (index_entry_pos < sc->current_sample) {
|
if (index_entry_pos < sc->current_sample) {
|
||||||
sc->current_sample += entries;
|
sc->current_sample += entries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sti->nb_index_entries += entries;
|
sti->nb_index_entries += entries;
|
||||||
sc->ctts_count = sti->nb_index_entries;
|
sc->tts_count = sti->nb_index_entries;
|
||||||
sc->stts_count = sti->nb_index_entries;
|
sc->stts_count = sti->nb_index_entries;
|
||||||
|
if (flags & MOV_TRUN_SAMPLE_CTS)
|
||||||
|
sc->ctts_count = sti->nb_index_entries;
|
||||||
|
|
||||||
// Record the index_entry position in frag_index of this fragment
|
// Record the index_entry position in frag_index of this fragment
|
||||||
if (frag_stream_info) {
|
if (frag_stream_info) {
|
||||||
|
@ -6013,10 +5936,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].min_distance = distance;
|
||||||
sti->index_entries[index_entry_pos].flags = index_entry_flags;
|
sti->index_entries[index_entry_pos].flags = index_entry_flags;
|
||||||
|
|
||||||
sc->ctts_data[index_entry_pos].count = 1;
|
sc->tts_data[index_entry_pos].count = 1;
|
||||||
sc->ctts_data[index_entry_pos].offset = ctts_duration;
|
sc->tts_data[index_entry_pos].offset = ctts_duration;
|
||||||
sc->stts_data[index_entry_pos].count = 1;
|
sc->tts_data[index_entry_pos].duration = sample_duration;
|
||||||
sc->stts_data[index_entry_pos].duration = sample_duration;
|
|
||||||
index_entry_pos++;
|
index_entry_pos++;
|
||||||
|
|
||||||
av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", "
|
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)
|
||||||
frag_stream_info->next_trun_dts = dts + sc->time_offset;
|
frag_stream_info->next_trun_dts = dts + sc->time_offset;
|
||||||
if (i < entries) {
|
if (i < entries) {
|
||||||
// EOF found before reading all entries. Fix the hole this would
|
// 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;
|
int gap = entries - i;
|
||||||
memmove(sti->index_entries + index_entry_pos,
|
memmove(sti->index_entries + index_entry_pos,
|
||||||
sti->index_entries + index_entry_pos + gap,
|
sti->index_entries + index_entry_pos + gap,
|
||||||
sizeof(*sti->index_entries) *
|
sizeof(*sti->index_entries) *
|
||||||
(sti->nb_index_entries - (index_entry_pos + gap)));
|
(sti->nb_index_entries - (index_entry_pos + gap)));
|
||||||
memmove(sc->ctts_data + index_entry_pos,
|
memmove(sc->tts_data + index_entry_pos,
|
||||||
sc->ctts_data + index_entry_pos + gap,
|
sc->tts_data + index_entry_pos + gap,
|
||||||
sizeof(*sc->ctts_data) *
|
sizeof(*sc->tts_data) *
|
||||||
(sc->ctts_count - (index_entry_pos + gap)));
|
(sc->tts_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)));
|
|
||||||
|
|
||||||
sti->nb_index_entries -= gap;
|
sti->nb_index_entries -= gap;
|
||||||
sc->ctts_count -= gap;
|
sc->tts_count -= gap;
|
||||||
sc->stts_count -= gap;
|
|
||||||
if (index_entry_pos < sc->current_sample) {
|
if (index_entry_pos < sc->current_sample) {
|
||||||
sc->current_sample -= gap;
|
sc->current_sample -= gap;
|
||||||
}
|
}
|
||||||
|
@ -9821,7 +9738,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
av_freep(&sc->ctts_data);
|
av_freep(&sc->tts_data);
|
||||||
for (int i = 0; i < sc->drefs_count; i++) {
|
for (int i = 0; i < sc->drefs_count; i++) {
|
||||||
av_freep(&sc->drefs[i].path);
|
av_freep(&sc->drefs[i].path);
|
||||||
av_freep(&sc->drefs[i].dir);
|
av_freep(&sc->drefs[i].dir);
|
||||||
|
@ -9838,6 +9755,7 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
|
||||||
av_freep(&sc->stsc_data);
|
av_freep(&sc->stsc_data);
|
||||||
av_freep(&sc->sample_sizes);
|
av_freep(&sc->sample_sizes);
|
||||||
av_freep(&sc->keyframes);
|
av_freep(&sc->keyframes);
|
||||||
|
av_freep(&sc->ctts_data);
|
||||||
av_freep(&sc->stts_data);
|
av_freep(&sc->stts_data);
|
||||||
av_freep(&sc->sdtp_data);
|
av_freep(&sc->sdtp_data);
|
||||||
av_freep(&sc->stps_data);
|
av_freep(&sc->stps_data);
|
||||||
|
@ -10859,27 +10777,10 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s
|
||||||
if (sample->flags & AVINDEX_DISCARD_FRAME) {
|
if (sample->flags & AVINDEX_DISCARD_FRAME) {
|
||||||
pkt->flags |= AV_PKT_FLAG_DISCARD;
|
pkt->flags |= AV_PKT_FLAG_DISCARD;
|
||||||
}
|
}
|
||||||
if (sc->stts_data && sc->stts_index < sc->stts_count) {
|
if (sc->stts_count && sc->tts_index < sc->tts_count)
|
||||||
pkt->duration = sc->stts_data[sc->stts_index].duration;
|
pkt->duration = sc->tts_data[sc->tts_index].duration;
|
||||||
|
if (sc->ctts_count && sc->tts_index < sc->tts_count) {
|
||||||
/* update stts context */
|
pkt->pts = av_sat_add64(pkt->dts, av_sat_add64(sc->dts_shift, sc->tts_data[sc->tts_index].offset));
|
||||||
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));
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (pkt->duration == 0) {
|
if (pkt->duration == 0) {
|
||||||
int64_t next_dts = (sc->current_sample < ffstream(st)->nb_index_entries) ?
|
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
|
||||||
pkt->pts = pkt->dts;
|
pkt->pts = pkt->dts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sc->tts_data && 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sc->sdtp_data && sc->current_sample <= sc->sdtp_count) {
|
if (sc->sdtp_data && sc->current_sample <= sc->sdtp_count) {
|
||||||
uint8_t sample_flags = sc->sdtp_data[sc->current_sample - 1];
|
uint8_t sample_flags = sc->sdtp_data[sc->current_sample - 1];
|
||||||
uint8_t sample_is_depended_on = (sample_flags >> 2) & 0x3;
|
uint8_t sample_is_depended_on = (sample_flags >> 2) & 0x3;
|
||||||
|
@ -10952,7 +10863,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
|
||||||
|
|
||||||
// Clear current sample
|
// Clear current sample
|
||||||
mov_current_sample_set(msc, 0);
|
mov_current_sample_set(msc, 0);
|
||||||
msc->ctts_index = 0;
|
msc->tts_index = 0;
|
||||||
|
|
||||||
// Discard current index entries
|
// Discard current index entries
|
||||||
avsti = ffstream(avst);
|
avsti = ffstream(avst);
|
||||||
|
@ -11185,27 +11096,14 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
|
||||||
|
|
||||||
mov_current_sample_set(sc, sample);
|
mov_current_sample_set(sc, sample);
|
||||||
av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, sc->current_sample);
|
av_log(s, AV_LOG_TRACE, "stream %d, found sample %d\n", st->index, sc->current_sample);
|
||||||
/* adjust stts index */
|
/* adjust time to sample index */
|
||||||
if (sc->stts_data) {
|
if (sc->tts_data) {
|
||||||
time_sample = 0;
|
time_sample = 0;
|
||||||
for (i = 0; i < sc->stts_count; i++) {
|
for (i = 0; i < sc->tts_count; i++) {
|
||||||
int next = time_sample + sc->stts_data[i].count;
|
int next = time_sample + sc->tts_data[i].count;
|
||||||
if (next > sc->current_sample) {
|
if (next > sc->current_sample) {
|
||||||
sc->stts_index = i;
|
sc->tts_index = i;
|
||||||
sc->stts_sample = sc->current_sample - time_sample;
|
sc->tts_sample = sc->current_sample - time_sample;
|
||||||
break;
|
|
||||||
}
|
|
||||||
time_sample = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* adjust ctts index */
|
|
||||||
if (sc->ctts_data) {
|
|
||||||
time_sample = 0;
|
|
||||||
for (i = 0; i < sc->ctts_count; i++) {
|
|
||||||
int next = time_sample + sc->ctts_data[i].count;
|
|
||||||
if (next > sc->current_sample) {
|
|
||||||
sc->ctts_index = i;
|
|
||||||
sc->ctts_sample = sc->current_sample - time_sample;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
time_sample = next;
|
time_sample = next;
|
||||||
|
|
Loading…
Add table
Reference in a new issue