[FFmpeg-devel] [PATCH] avformat/mov: fix hang while seek on a kind of fragmented mp4.
Charles Liu
liuchh83 at gmail.com
Fri Feb 22 12:20:40 EET 2019
1. organize fragmented information according to the tracks.
2. do NOT skip the last boxes of fragmented info.
ticket #7572
Signed-off-by: Charles Liu <liuchh83 at gmail.com>
---
libavformat/isom.h | 10 +-
libavformat/mov.c | 374 +++++++++++++++++++++------------------------
2 files changed, 181 insertions(+), 203 deletions(-)
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 69452cae8e..eea8fa4e8f 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -125,7 +125,7 @@ typedef struct MOVEncryptionIndex {
} MOVEncryptionIndex;
typedef struct MOVFragmentStreamInfo {
- int id;
+ unsigned stsd_id;
int64_t sidx_pts;
int64_t first_tfra_pts;
int64_t tfdt_dts;
@@ -136,14 +136,13 @@ typedef struct MOVFragmentStreamInfo {
typedef struct MOVFragmentIndexItem {
int64_t moof_offset;
int headers_read;
- int current;
- int nb_stream_info;
- MOVFragmentStreamInfo * stream_info;
+ MOVFragmentStreamInfo stream_info;
} MOVFragmentIndexItem;
typedef struct MOVFragmentIndex {
int allocated_size;
int complete;
+ int id; // track id
int current;
int nb_items;
MOVFragmentIndexItem * item;
@@ -274,7 +273,8 @@ typedef struct MOVContext {
int moov_retry;
int use_mfra_for;
int has_looked_for_mfra;
- MOVFragmentIndex frag_index;
+ unsigned nb_frag_indices;
+ MOVFragmentIndex *frag_indices;
int atom_depth;
unsigned int aax_mode; ///< 'aax' file has been detected
uint8_t file_key[20];
diff --git a/libavformat/mov.c b/libavformat/mov.c
index bbd588c705..a16788fd21 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -1153,59 +1153,29 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0; /* now go for mdat */
}
-static MOVFragmentStreamInfo * get_frag_stream_info(
- MOVFragmentIndex *frag_index,
- int index,
- int id)
+static MOVFragmentIndex *mov_find_frag_index(MOVFragmentIndex *frag_indices, int nb_frag_indices, int track_id)
{
- int i;
- MOVFragmentIndexItem * item;
+ unsigned i;
+ MOVFragmentIndex *frag_index = NULL;
- if (index < 0 || index >= frag_index->nb_items)
- return NULL;
- item = &frag_index->item[index];
- for (i = 0; i < item->nb_stream_info; i++)
- if (item->stream_info[i].id == id)
- return &item->stream_info[i];
+ for (i = 0; i < nb_frag_indices; i++)
+ if (frag_indices[i].id == track_id)
+ frag_index = &frag_indices[i];
- // This shouldn't happen
- return NULL;
+ return frag_index;
}
-static void set_frag_stream(MOVFragmentIndex *frag_index, int id)
+static MOVFragmentStreamInfo *get_current_frag_stream_info(MOVContext *c, int id)
{
- int i;
- MOVFragmentIndexItem * item;
-
- if (frag_index->current < 0 ||
- frag_index->current >= frag_index->nb_items)
- return;
-
- item = &frag_index->item[frag_index->current];
- for (i = 0; i < item->nb_stream_info; i++)
- if (item->stream_info[i].id == id) {
- item->current = i;
- return;
- }
+ MOVFragmentIndex *frag_index = NULL;
- // id not found. This shouldn't happen.
- item->current = -1;
-}
-
-static MOVFragmentStreamInfo * get_current_frag_stream_info(
- MOVFragmentIndex *frag_index)
-{
- MOVFragmentIndexItem *item;
- if (frag_index->current < 0 ||
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, id);
+ if (!frag_index ||
+ frag_index->current < 0 ||
frag_index->current >= frag_index->nb_items)
return NULL;
- item = &frag_index->item[frag_index->current];
- if (item->current >= 0 && item->current < item->nb_stream_info)
- return &item->stream_info[item->current];
-
- // This shouldn't happen
- return NULL;
+ return &frag_index->item[frag_index->current].stream_info;
}
static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset)
@@ -1232,9 +1202,9 @@ static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset)
return b;
}
-static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info)
-{
- av_assert0(frag_stream_info);
+static int64_t get_frag_time(MOVFragmentIndex *frag_index,
+ int index, int track_id) {
+ MOVFragmentStreamInfo *frag_stream_info = &frag_index->item[index].stream_info;
if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE)
return frag_stream_info->sidx_pts;
if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE)
@@ -1242,31 +1212,9 @@ static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info)
return frag_stream_info->tfdt_dts;
}
-static int64_t get_frag_time(MOVFragmentIndex *frag_index,
- int index, int track_id)
-{
- MOVFragmentStreamInfo * frag_stream_info;
- int64_t timestamp;
- int i;
-
- if (track_id >= 0) {
- frag_stream_info = get_frag_stream_info(frag_index, index, track_id);
- return frag_stream_info->sidx_pts;
- }
-
- for (i = 0; i < frag_index->item[index].nb_stream_info; i++) {
- frag_stream_info = &frag_index->item[index].stream_info[i];
- timestamp = get_stream_info_time(frag_stream_info);
- if (timestamp != AV_NOPTS_VALUE)
- return timestamp;
- }
- return AV_NOPTS_VALUE;
-}
-
static int search_frag_timestamp(MOVFragmentIndex *frag_index,
- AVStream *st, int64_t timestamp)
-{
- int a, b, m, m0;
+ AVStream *st, int64_t timestamp) {
+ int a, b, m;
int64_t frag_time;
int id = -1;
@@ -1282,89 +1230,98 @@ static int search_frag_timestamp(MOVFragmentIndex *frag_index,
b = frag_index->nb_items;
while (b - a > 1) {
- m0 = m = (a + b) >> 1;
-
- while (m < b &&
- (frag_time = get_frag_time(frag_index, m, id)) == AV_NOPTS_VALUE)
- m++;
+ m = (a + b) >> 1;
+ frag_time = get_frag_time(frag_index, m, id);
+ if (frag_time == AV_NOPTS_VALUE)
+ return -1;
- if (m < b && frag_time <= timestamp)
+ if (frag_time >= timestamp)
+ b = m;
+ if (frag_time <= timestamp)
a = m;
- else
- b = m0;
}
return a;
}
-static int update_frag_index(MOVContext *c, int64_t offset)
+static int update_frag_index(MOVContext *c, int track_id, int64_t offset)
{
int index, i;
- MOVFragmentIndexItem * item;
- MOVFragmentStreamInfo * frag_stream_info;
+ MOVFragmentIndex *frag_index = NULL;
+ MOVFragmentIndexItem *item;
+
+ do {
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, track_id);
+ if (frag_index == NULL) {
+ c->nb_frag_indices = c->fc->nb_streams;
+ c->frag_indices = av_mallocz_array(c->nb_frag_indices, sizeof(*c->frag_indices));
+ if (!c->frag_indices)
+ return AVERROR(ENOMEM);
+
+ for (i = 0; i < c->fc->nb_streams; i++)
+ c->frag_indices[i].id = c->fc->streams[i]->id;
+ }
+ } while (!frag_index);
// If moof_offset already exists in frag_index, return index to it
- index = search_frag_moof_offset(&c->frag_index, offset);
- if (index < c->frag_index.nb_items &&
- c->frag_index.item[index].moof_offset == offset)
+ index = search_frag_moof_offset(frag_index, offset);
+ if (index < frag_index->nb_items &&
+ frag_index->item[index].moof_offset == offset) {
+ frag_index->current = index;
return index;
+ }
// offset is not yet in frag index.
// Insert new item at index (sorted by moof offset)
- item = av_fast_realloc(c->frag_index.item,
- &c->frag_index.allocated_size,
- (c->frag_index.nb_items + 1) *
- sizeof(*c->frag_index.item));
- if(!item)
- return -1;
- c->frag_index.item = item;
-
- frag_stream_info = av_realloc_array(NULL, c->fc->nb_streams,
- sizeof(*item->stream_info));
- if (!frag_stream_info)
- return -1;
+ item = av_fast_realloc(frag_index->item,
+ &frag_index->allocated_size,
+ (frag_index->nb_items + 1) *
+ sizeof(*frag_index->item));
+ if (!item)
+ return AVERROR(ENOMEM);
+ frag_index->item = item;
for (i = 0; i < c->fc->nb_streams; i++) {
// Avoid building frag index if streams lack track id.
if (c->fc->streams[i]->id < 0)
return AVERROR_INVALIDDATA;
-
- frag_stream_info[i].id = c->fc->streams[i]->id;
- frag_stream_info[i].sidx_pts = AV_NOPTS_VALUE;
- frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE;
- frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE;
- frag_stream_info[i].index_entry = -1;
- frag_stream_info[i].encryption_index = NULL;
}
- if (index < c->frag_index.nb_items)
- memmove(c->frag_index.item + index + 1, c->frag_index.item + index,
- (c->frag_index.nb_items - index) * sizeof(*c->frag_index.item));
+ if (index < frag_index->nb_items)
+ memmove(frag_index->item + index + 1, frag_index->item + index,
+ (frag_index->nb_items - index) * sizeof(*frag_index->item));
- item = &c->frag_index.item[index];
+ item = &frag_index->item[index];
item->headers_read = 0;
- item->current = 0;
- item->nb_stream_info = c->fc->nb_streams;
item->moof_offset = offset;
- item->stream_info = frag_stream_info;
- c->frag_index.nb_items++;
+ item->stream_info.sidx_pts = AV_NOPTS_VALUE;
+ item->stream_info.tfdt_dts = AV_NOPTS_VALUE;
+ item->stream_info.first_tfra_pts = AV_NOPTS_VALUE;
+ item->stream_info.index_entry = -1;
+ item->stream_info.encryption_index = NULL;
+
+ frag_index->nb_items++;
+ frag_index->current = index;
return index;
}
-static void fix_frag_index_entries(MOVFragmentIndex *frag_index, int index,
- int id, int entries)
+static void fix_frag_index_entries(MOVFragmentIndex *frag_indices, int nb_frag_indices, int track_id,
+ int index, int entries)
{
int i;
- MOVFragmentStreamInfo * frag_stream_info;
+ MOVFragmentIndex *frag_index;
if (index < 0)
return;
- for (i = index; i < frag_index->nb_items; i++) {
- frag_stream_info = get_frag_stream_info(frag_index, i, id);
- if (frag_stream_info && frag_stream_info->index_entry >= 0)
- frag_stream_info->index_entry += entries;
- }
+
+ frag_index = mov_find_frag_index(frag_indices, nb_frag_indices, track_id);
+ if (!frag_index)
+ return;
+
+ for (i = index; i < frag_index->nb_items; i++)
+ if (frag_index->item[i].stream_info.index_entry >= 0)
+ frag_index->item[i].stream_info.index_entry += entries;
}
static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
@@ -1389,7 +1346,6 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8;
av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset);
- c->frag_index.current = update_frag_index(c, c->fragment.moof_offset);
return mov_read_default(c, pb, atom);
}
@@ -4558,7 +4514,8 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
MOVFragment *frag = &c->fragment;
MOVTrackExt *trex = NULL;
- int flags, track_id, i;
+ int flags, track_id, i, index;
+ MOVFragmentIndex *frag_index = NULL;
c->fragment.found_tfhd = 1;
@@ -4578,7 +4535,6 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
}
frag->track_id = track_id;
- set_frag_stream(&c->frag_index, track_id);
frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
avio_rb64(pb) : flags & MOV_TFHD_DEFAULT_BASE_IS_MOOF ?
@@ -4593,6 +4549,14 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb) : trex->flags;
av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags);
+ index = update_frag_index(c, frag->track_id, frag->moof_offset);
+ if (index < 0) return index;
+
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, track_id);
+ if (index < frag_index->nb_items)
+ frag_index->item[index].stream_info.stsd_id = frag->stsd_id;
+ frag_index->item[index].headers_read = 1;
+
return 0;
}
@@ -4671,7 +4635,7 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom)
base_media_decode_time = avio_rb32(pb);
}
- frag_stream_info = get_current_frag_stream_info(&c->frag_index);
+ frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id);
if (frag_stream_info)
frag_stream_info->tfdt_dts = base_media_decode_time;
sc->track_end = base_media_decode_time;
@@ -4696,6 +4660,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
size_t old_ctts_allocated_size;
AVIndexEntry *new_entries;
MOVFragmentStreamInfo * frag_stream_info;
+ MOVFragmentIndex *frag_index = NULL;
if (!frag->found_tfhd) {
av_log(c->fc, AV_LOG_ERROR, "trun track id unknown, no tfhd was found\n");
@@ -4723,12 +4688,14 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
// and it's samples are in index_entries at the given position.
// New index entries will be inserted before the index_entry found.
index_entry_pos = st->nb_index_entries;
- for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) {
- frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id);
- if (frag_stream_info && frag_stream_info->index_entry >= 0) {
- next_frag_index = i;
- index_entry_pos = frag_stream_info->index_entry;
- break;
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, st->id);
+ if (frag_index) {
+ for (i = frag_index->current + 1; i < frag_index->nb_items; i++) {
+ if (frag_index->item[i].stream_info.index_entry >= 0) {
+ next_frag_index = i;
+ index_entry_pos = frag_index->item[i].stream_info.index_entry;
+ break;
+ }
}
}
av_assert0(index_entry_pos <= st->nb_index_entries);
@@ -4743,7 +4710,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb);
if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb);
- frag_stream_info = get_current_frag_stream_info(&c->frag_index);
+ frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id);
if (frag_stream_info)
{
if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE &&
@@ -4937,8 +4904,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom)
// If a hole was created to insert the new index_entries into,
// the index_entry recorded for all subsequent moof must
// be incremented by the number of entries inserted.
- fix_frag_index_entries(&c->frag_index, next_frag_index,
- frag->track_id, entries);
+ fix_frag_index_entries(c->frag_indices, c->nb_frag_indices, frag->track_id,
+ next_frag_index, entries);
if (pb->eof_reached) {
av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n");
@@ -4963,6 +4930,8 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
AVStream *ref_st = NULL;
MOVStreamContext *sc, *ref_sc = NULL;
AVRational timescale;
+ MOVFragmentIndex *frag_index;
+ MOVFragmentStreamInfo *frag_stream_info = NULL;
version = avio_r8(pb);
if (version > 1) {
@@ -5007,7 +4976,6 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
for (i = 0; i < item_count; i++) {
int index;
- MOVFragmentStreamInfo * frag_stream_info;
uint32_t size = avio_rb32(pb);
uint32_t duration = avio_rb32(pb);
if (size & 0x80000000) {
@@ -5017,8 +4985,10 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avio_rb32(pb); // sap_flags
timestamp = av_rescale_q(pts, st->time_base, timescale);
- index = update_frag_index(c, offset);
- frag_stream_info = get_frag_stream_info(&c->frag_index, index, track_id);
+ index = update_frag_index(c, track_id, offset);
+ if (index < 0) return index;
+
+ frag_stream_info = get_current_frag_stream_info(c, track_id);
if (frag_stream_info)
frag_stream_info->sidx_pts = timestamp;
@@ -5033,13 +5003,11 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
if (offset == avio_size(pb)) {
// Find first entry in fragment index that came from an sidx.
// This will pretty much always be the first entry.
- for (i = 0; i < c->frag_index.nb_items; i++) {
- MOVFragmentIndexItem * item = &c->frag_index.item[i];
- for (j = 0; ref_st == NULL && j < item->nb_stream_info; j++) {
- MOVFragmentStreamInfo * si;
- si = &item->stream_info[j];
- if (si->sidx_pts != AV_NOPTS_VALUE) {
- ref_st = c->fc->streams[j];
+ for (i = 0; i < c->nb_frag_indices; i++) {
+ MOVFragmentIndex *frag_index = &c->frag_indices[i];
+ for (j = 0; j < frag_index->nb_items; j++) {
+ if (frag_index->item[j].stream_info.sidx_pts != AV_NOPTS_VALUE) {
+ ref_st = c->fc->streams[i];
ref_sc = ref_st->priv_data;
break;
}
@@ -5053,7 +5021,9 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom)
}
}
- c->frag_index.complete = 1;
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, st->id);
+ if (frag_index)
+ frag_index->complete = 1;
}
return 0;
@@ -5857,12 +5827,12 @@ static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encry
AVStream *st;
int i;
- frag_stream_info = get_current_frag_stream_info(&c->frag_index);
+ frag_stream_info = get_current_frag_stream_info(c, c->fragment.track_id);
if (frag_stream_info) {
for (i = 0; i < c->fc->nb_streams; i++) {
- if (c->fc->streams[i]->id == frag_stream_info->id) {
- st = c->fc->streams[i];
- break;
+ if (c->fc->streams[i]->id == c->fragment.track_id) {
+ st = c->fc->streams[i];
+ break;
}
}
if (i == c->fc->nb_streams)
@@ -6180,6 +6150,7 @@ static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom)
int i, ret;
unsigned int version, entry_count, aux_info_type, aux_info_param;
unsigned int alloc_size = 0;
+ MOVFragmentIndex *frag_index;
ret = get_current_encryption_info(c, &encryption_index, &sc);
if (ret != 1)
@@ -6247,9 +6218,10 @@ static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom)
} else {
encryption_index->auxiliary_offsets[i] = avio_rb64(pb);
}
- if (c->frag_index.current >= 0) {
+
+ frag_index = mov_find_frag_index(c->frag_indices, c->nb_frag_indices, c->fragment.track_id);
+ if (frag_index && frag_index->current >= 0)
encryption_index->auxiliary_offsets[i] += c->fragment.base_data_offset;
- }
}
if (pb->eof_reached) {
@@ -6570,22 +6542,23 @@ static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *s
return 0;
}
-static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index)
+static int cenc_filter(MOVContext *mov, AVStream *st, MOVStreamContext *sc, AVPacket *pkt, int current_index)
{
- MOVFragmentStreamInfo *frag_stream_info;
- MOVEncryptionIndex *encryption_index;
+ MOVEncryptionIndex *encryption_index = NULL;
AVEncryptionInfo *encrypted_sample;
- int encrypted_index, ret;
+ int encrypted_index = current_index, ret, index = -1;
+ MOVFragmentIndex *frag_index;
- frag_stream_info = get_frag_stream_info(&mov->frag_index, mov->frag_index.current, st->id);
- encrypted_index = current_index;
- encryption_index = NULL;
- if (frag_stream_info) {
+ frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, st->id);
+ if (frag_index)
+ index = search_frag_timestamp(frag_index, st, pkt->pts);
+
+ if (index != -1) {
// Note this only supports encryption info in the first sample descriptor.
- if (mov->fragment.stsd_id == 1) {
- if (frag_stream_info->encryption_index) {
- encrypted_index = current_index - frag_stream_info->index_entry;
- encryption_index = frag_stream_info->encryption_index;
+ if (frag_index->item[index].stream_info.stsd_id == 1) {
+ if (frag_index->item[index].stream_info.encryption_index) {
+ encrypted_index = current_index - frag_index->item[index].stream_info.index_entry;
+ encryption_index = frag_index->item[index].stream_info.encryption_index;
} else {
encryption_index = sc->cenc.encryption_index;
}
@@ -6871,9 +6844,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return err;
}
if (c->found_moov && c->found_mdat &&
- ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) ||
+ ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX) ||
start_pos + a.size == avio_size(pb))) {
- if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete)
+ if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX)
c->next_root_atom = start_pos + a.size;
c->atom_depth --;
return 0;
@@ -7230,14 +7203,15 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&mov->trex_data);
av_freep(&mov->bitrates);
- for (i = 0; i < mov->frag_index.nb_items; i++) {
- MOVFragmentStreamInfo *frag = mov->frag_index.item[i].stream_info;
- for (j = 0; j < mov->frag_index.item[i].nb_stream_info; j++) {
- mov_free_encryption_index(&frag[j].encryption_index);
- }
- av_freep(&mov->frag_index.item[i].stream_info);
+ for (i = 0; i < mov->nb_frag_indices; i++) {
+ MOVFragmentIndex *index = &mov->frag_indices[i];
+ for (j = 0; j < index->nb_items; j++)
+ mov_free_encryption_index(&index->item[j].stream_info.encryption_index);
+
+ av_freep(&index->item);
}
- av_freep(&mov->frag_index.item);
+ av_freep(&mov->frag_indices);
+ mov->nb_frag_indices = 0;
av_freep(&mov->aes_decrypt);
av_freep(&mov->chapter_tracks);
@@ -7285,6 +7259,7 @@ static int read_tfra(MOVContext *mov, AVIOContext *f)
int64_t pos = avio_tell(f);
uint32_t size = avio_rb32(f);
unsigned track_id, item_count;
+ MOVFragmentStreamInfo *frag_stream_info = NULL;
if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a')) {
return 1;
@@ -7299,7 +7274,6 @@ static int read_tfra(MOVContext *mov, AVIOContext *f)
for (i = 0; i < item_count; i++) {
int64_t time, offset;
int index;
- MOVFragmentStreamInfo * frag_stream_info;
if (avio_feof(f)) {
return AVERROR_INVALIDDATA;
@@ -7316,11 +7290,14 @@ static int read_tfra(MOVContext *mov, AVIOContext *f)
// The first sample of each stream in a fragment is always a random
// access sample. So it's entry in the tfra can be used as the
// initial PTS of the fragment.
- index = update_frag_index(mov, offset);
- frag_stream_info = get_frag_stream_info(&mov->frag_index, index, track_id);
+ index = update_frag_index(mov, track_id, offset);
+ if (index < 0) return index;
+
+ frag_stream_info = get_current_frag_stream_info(mov, track_id);
if (frag_stream_info &&
- frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE)
+ frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE) {
frag_stream_info->first_tfra_pts = time;
+ }
for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++)
avio_r8(f);
@@ -7582,10 +7559,6 @@ static int mov_read_header(AVFormatContext *s)
}
ff_configure_buffers_for_index(s, AV_TIME_BASE);
- for (i = 0; i < mov->frag_index.nb_items; i++)
- if (mov->frag_index.item[i].moof_offset <= mov->fragment.moof_offset)
- mov->frag_index.item[i].headers_read = 1;
-
return 0;
}
@@ -7622,27 +7595,26 @@ static int should_retry(AVIOContext *pb, int error_code) {
return 1;
}
-static int mov_switch_root(AVFormatContext *s, int64_t target, int index)
+static int mov_switch_root(AVFormatContext *s, int64_t target)
{
- int ret;
+ int ret, i, index;
+ MOVFragmentIndex *frag_index;
MOVContext *mov = s->priv_data;
- if (index >= 0 && index < mov->frag_index.nb_items)
- target = mov->frag_index.item[index].moof_offset;
if (avio_seek(s->pb, target, SEEK_SET) != target) {
av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target);
return AVERROR_INVALIDDATA;
}
- mov->next_root_atom = 0;
- if (index < 0 || index >= mov->frag_index.nb_items)
- index = search_frag_moof_offset(&mov->frag_index, target);
- if (index < mov->frag_index.nb_items) {
- if (index + 1 < mov->frag_index.nb_items)
- mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;
- if (mov->frag_index.item[index].headers_read)
- return 0;
- mov->frag_index.item[index].headers_read = 1;
+ for (i = 0; i < mov->nb_frag_indices; i++) {
+ frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, i + 1);
+ if (frag_index == NULL)
+ return -1;
+
+ index = search_frag_moof_offset(frag_index, target);
+ if (index < frag_index->nb_items)
+ if (frag_index->item[index].moof_offset == target && frag_index->item[index].headers_read)
+ return 0;
}
mov->found_mdat = 0;
@@ -7694,7 +7666,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) {
if (!mov->next_root_atom)
return AVERROR_EOF;
- if ((ret = mov_switch_root(s, mov->next_root_atom, -1)) < 0)
+ if ((ret = mov_switch_root(s, mov->next_root_atom)) < 0)
return ret;
goto retry;
}
@@ -7818,17 +7790,23 @@ static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp
{
MOVContext *mov = s->priv_data;
int index;
+ int64_t target;
+ MOVFragmentIndex *frag_index;
- if (!mov->frag_index.complete)
+ frag_index = mov_find_frag_index(mov->frag_indices, mov->nb_frag_indices, st->id);
+ if (frag_index == NULL || !frag_index->complete)
return 0;
- index = search_frag_timestamp(&mov->frag_index, st, timestamp);
+ index = search_frag_timestamp(frag_index, st, timestamp);
if (index < 0)
index = 0;
- if (!mov->frag_index.item[index].headers_read)
- return mov_switch_root(s, -1, index);
- if (index + 1 < mov->frag_index.nb_items)
- mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset;
+
+ if (index < frag_index->nb_items) {
+ target = frag_index->item[index].moof_offset;
+
+ if (!frag_index->item[index].headers_read)
+ return mov_switch_root(s, target);
+ }
return 0;
}
--
2.20.1
More information about the ffmpeg-devel
mailing list