[FFmpeg-devel] [PATCH] avformat/mov: fix hang while seek on a kind of fragmented mp4.

Charles Liu liuchh83 at gmail.com
Wed Feb 20 17:54:56 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  | 375 ++++++++++++++++++++++-----------------------
 2 files changed, 185 insertions(+), 200 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 69452cae8e..2b06f5fa58 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..cd37d08299 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)   // name?
 {
-    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;
+    MOVFragmentIndex *frag_index = NULL;
 
-    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;
-        }
-
-    // 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,10 @@ 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)
+static int64_t get_frag_time(MOVFragmentIndex *frag_index,
+                             int index, int track_id)
 {
-    av_assert0(frag_stream_info);
+    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 +1213,10 @@ 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;
+    int a, b, m;
     int64_t frag_time;
     int id = -1;
 
@@ -1282,89 +1232,103 @@ 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++) {
+                MOVFragmentIndex *tmp_frag_index = av_mallocz(sizeof(MOVFragmentIndex));
+                if (!tmp_frag_index)
+                    return AVERROR(ENOMEM);
+
+                c->frag_indices[i] = tmp_frag_index;
+                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 +1353,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 +4521,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 +4542,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 +4556,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 +4642,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 +4667,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 +4695,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 +4717,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 +4911,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 +4937,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 +4983,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 +4992,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 +5010,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 +5028,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 +5834,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)
@@ -6247,7 +6224,9 @@ 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) {
+
+        MOVFragmentIndex *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;
         }
     }
@@ -6570,22 +6549,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 +6851,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 +7210,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 (i = 0; i < index->nb_items; i++)
+            mov_free_encryption_index(&index->item[i].stream_info.encryption_index);
+
+        av_freep(&index->item);
+        av_freep(&index);
     }
-    av_freep(&mov->frag_index.item);
+    av_freep(&mov->frag_indices);
 
     av_freep(&mov->aes_decrypt);
     av_freep(&mov->chapter_tracks);
@@ -7285,6 +7266,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 +7281,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 +7297,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 +7566,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 +7602,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 +7673,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 +7797,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