[FFmpeg-devel] [PATCH 1/3] avformat/mov: move edit list heuristics into mov_build_index()

Clément Bœsch u at pkh.me
Mon Dec 1 23:10:14 CET 2014


From: Clément Bœsch <clement at stupeflix.com>

mov_read_elst() is now only responsible from storing the table in a data
structure; this is consistent with other table readers functions.
---
 libavformat/isom.h | 10 +++++--
 libavformat/mov.c  | 78 +++++++++++++++++++++++++++++++++---------------------
 2 files changed, 56 insertions(+), 32 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 52da1a3..99188ce 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -53,6 +53,12 @@ typedef struct MOVStsc {
     int id;
 } MOVStsc;
 
+typedef struct MOVElst {
+    int64_t duration;
+    int64_t time;
+    float rate;
+} MOVElst;
+
 typedef struct MOVDref {
     uint32_t type;
     char *path;
@@ -121,6 +127,8 @@ typedef struct MOVStreamContext {
     MOVStsc *stsc_data;
     unsigned int stps_count;
     unsigned *stps_data;  ///< partial sync sample for mpeg-2 open gop
+    MOVElst *elst_data;
+    unsigned int elst_count;
     int ctts_index;
     int ctts_sample;
     unsigned int sample_size; ///< may contain value calculated from stsd or value from stsz atom
@@ -131,8 +139,6 @@ typedef struct MOVStreamContext {
     unsigned int keyframe_count;
     int *keyframes;
     int time_scale;
-    int64_t empty_duration; ///< empty duration of the first edit list entry
-    int64_t start_time;   ///< start time of the media
     int64_t time_offset;  ///< time offset of the edit list entries
     int current_sample;
     unsigned int bytes_per_frame;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 64c2c10..e294007 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -2249,11 +2249,32 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
     unsigned int i, j;
     uint64_t stream_size = 0;
 
+    if (sc->elst_count) {
+        int i, edit_start_index = 0, unsupported = 0;
+        int64_t empty_duration = 0; // empty duration of the first edit list entry
+        int64_t start_time = 0; // start time of the media
+
+        for (i = 0; i < sc->elst_count; i++) {
+            const MOVElst *e = &sc->elst_data[i];
+            if (i == 0 && e->time == -1) {
+                /* if empty, the first entry is the start time of the stream
+                 * relative to the presentation itself */
+                st->start_time = empty_duration = e->duration;
+                edit_start_index = 1;
+            } else if (i == edit_start_index && e->time >= 0) {
+                start_time = e->time;
+            } else
+                unsupported = 1;
+        }
+        if (unsupported)
+            av_log(mov->fc, AV_LOG_WARNING, "multiple edit list entries, "
+                   "a/v desync might occur, patch welcome\n");
+
     /* adjust first dts according to edit list */
-    if ((sc->empty_duration || sc->start_time) && mov->time_scale > 0) {
-        if (sc->empty_duration)
-            sc->empty_duration = av_rescale(sc->empty_duration, sc->time_scale, mov->time_scale);
-        sc->time_offset = sc->start_time - sc->empty_duration;
+    if ((empty_duration || start_time) && mov->time_scale > 0) {
+        if (empty_duration)
+            empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale);
+        sc->time_offset = start_time - empty_duration;
         current_dts = -sc->time_offset;
         if (sc->ctts_count>0 && sc->stts_count>0 &&
             sc->ctts_data[0].duration / FFMAX(sc->stts_data[0].duration, 1) > 16) {
@@ -2263,6 +2284,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st)
             st->codec->has_b_frames = 1;
         }
     }
+    }
 
     /* only use old uncompressed audio chunk demuxing when stts specifies it */
     if (!(st->codec->codec_type == AVMEDIA_TYPE_AUDIO &&
@@ -2607,6 +2629,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     av_freep(&sc->keyframes);
     av_freep(&sc->stts_data);
     av_freep(&sc->stps_data);
+    av_freep(&sc->elst_data);
     av_freep(&sc->rap_group);
 
     return 0;
@@ -3171,8 +3194,7 @@ free_and_return:
 static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     MOVStreamContext *sc;
-    int i, edit_count, version, edit_start_index = 0;
-    int unsupported = 0;
+    int i, edit_count, version;
 
     if (c->fc->nb_streams < 1 || c->ignore_editlist)
         return 0;
@@ -3182,37 +3204,32 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     avio_rb24(pb); /* flags */
     edit_count = avio_rb32(pb); /* entries */
 
-    if ((uint64_t)edit_count*12+8 > atom.size)
-        return AVERROR_INVALIDDATA;
+    if (!edit_count)
+        return 0;
+    if (sc->elst_data)
+        av_log(c->fc, AV_LOG_WARNING, "Duplicated ELST atom\n");
+    av_free(sc->elst_data);
+    sc->elst_count = 0;
+    sc->elst_data = av_malloc_array(edit_count, sizeof(*sc->elst_data));
+    if (!sc->elst_data)
+        return AVERROR(ENOMEM);
 
     av_dlog(c->fc, "track[%i].edit_count = %i\n", c->fc->nb_streams-1, edit_count);
-    for (i=0; i<edit_count; i++){
-        int64_t time;
-        int64_t duration;
-        int rate;
+    for (i = 0; i < edit_count && !pb->eof_reached; i++) {
+        MOVElst *e = &sc->elst_data[i];
+
         if (version == 1) {
-            duration = avio_rb64(pb);
-            time     = avio_rb64(pb);
+            e->duration = avio_rb64(pb);
+            e->time     = avio_rb64(pb);
         } else {
-            duration = avio_rb32(pb); /* segment duration */
-            time     = (int32_t)avio_rb32(pb); /* media time */
+            e->duration = avio_rb32(pb); /* segment duration */
+            e->time     = (int32_t)avio_rb32(pb); /* media time */
         }
-        rate = avio_rb32(pb);
-        if (i == 0 && time == -1) {
-            sc->empty_duration = duration;
-            edit_start_index = 1;
-        } else if (i == edit_start_index && time >= 0)
-            sc->start_time = time;
-        else
-            unsupported = 1;
-
+        e->rate = avio_rb32(pb) / 65536.0;
         av_dlog(c->fc, "duration=%"PRId64" time=%"PRId64" rate=%f\n",
-                duration, time, rate / 65536.0);
+                e->duration, e->time, e->rate);
     }
-
-    if (unsupported)
-        av_log(c->fc, AV_LOG_WARNING, "multiple edit list entries, "
-               "a/v desync might occur, patch welcome\n");
+    sc->elst_count = i;
 
     return 0;
 }
@@ -3716,6 +3733,7 @@ static int mov_read_close(AVFormatContext *s)
         av_freep(&sc->keyframes);
         av_freep(&sc->stts_data);
         av_freep(&sc->stps_data);
+        av_freep(&sc->elst_data);
         av_freep(&sc->rap_group);
         av_freep(&sc->display_matrix);
     }
-- 
2.1.3



More information about the ffmpeg-devel mailing list