[FFmpeg-devel] [PATCH] mov: Add option to keep packet order after seeking

Derek Buitenhuis derek.buitenhuis at gmail.com
Mon Mar 16 17:07:07 CET 2015


The current behavior may produce packets in a different order
after seeking, compared to demuxing linearly from the beginning.
This is because the MOV demuxer seeks in each stream based on
timestamp, which may not necessarily match the original packet
order.

This makes implementing certain operations, such as segmenting,
quite hard, and slower than need be.

Therefore, add an option which retains the same packet order
after seeking, as when a file is demuxed linearly. This is
accomplished by seeking in the other streams, based on file
position, rather than timestamp.

The positional search in the index entries is implemented as
a linear search since, in MOV, the index entries may be out of
order in terms of file position, in particularily insane files.

Signed-off-by: Derek Buitenhuis <derek.buitenhuis at gmail.com>
---
 libavformat/isom.h    |  1 +
 libavformat/mov.c     | 71 ++++++++++++++++++++++++++++++++++++++++-----------
 libavformat/version.h |  4 +--
 3 files changed, 59 insertions(+), 17 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index d233839..1ab085e 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -186,6 +186,7 @@ typedef struct MOVContext {
     int chapter_track;
     int use_absolute_path;
     int ignore_editlist;
+    int seek_keep_order;
     int64_t next_root_atom; ///< offset of the next root atom
     int export_all;
     int export_xmp;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index de4004f..e674113 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -4291,13 +4291,35 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
     return 0;
 }
 
-static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, int flags)
+static int mov_search_sample_pos(AVStream *st, int64_t pos)
+{
+    int i;
+
+    /* This is linear search because entries may be out of order pos-wise. */
+    for (i = 0; i < st->nb_index_entries; i++)
+        if (st->index_entries[i].pos >= pos)
+            return i;
+
+    return -1;
+}
+
+static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t val, int flags, int pos)
 {
     MOVStreamContext *sc = st->priv_data;
+    int64_t timestamp;
     int sample, time_sample;
     int i;
 
-    sample = av_index_search_timestamp(st, timestamp, flags);
+    if (!pos) {
+        sample    = av_index_search_timestamp(st, val, flags);
+        timestamp = val;
+    } else {
+        sample = mov_search_sample_pos(st, val);
+        if (sample < 0)
+            return AVERROR_INVALIDDATA;
+
+        timestamp = st->index_entries[sample].timestamp;
+    }
     av_dlog(s, "stream %d, timestamp %"PRId64", sample %d\n", st->index, timestamp, sample);
     if (sample < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp)
         sample = 0;
@@ -4323,32 +4345,47 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp,
 
 static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags)
 {
+    MOVContext *mc = s->priv_data;
     AVStream *st;
-    int64_t seek_timestamp, timestamp;
+    int64_t timestamp;
     int sample;
-    int i;
 
     if (stream_index >= s->nb_streams)
         return AVERROR_INVALIDDATA;
 
     st = s->streams[stream_index];
-    sample = mov_seek_stream(s, st, sample_time, flags);
+    sample = mov_seek_stream(s, st, sample_time, flags, 0);
     if (sample < 0)
         return sample;
 
-    /* adjust seek timestamp to found sample timestamp */
-    seek_timestamp = st->index_entries[sample].timestamp;
+    if (!mc->seek_keep_order) {
+        /* adjust seek timestamp to found sample timestamp */
+        int64_t seek_timestamp = st->index_entries[sample].timestamp;
+        int i;
 
-    for (i = 0; i < s->nb_streams; i++) {
-        MOVStreamContext *sc = s->streams[i]->priv_data;
-        st = s->streams[i];
-        st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0;
+        for (i = 0; i < s->nb_streams; i++) {
+            MOVStreamContext *sc = s->streams[i]->priv_data;
+            st = s->streams[i];
+            st->skip_samples = (sample_time <= 0) ? sc->start_pad : 0;
 
-        if (stream_index == i)
-            continue;
+            if (stream_index == i)
+                continue;
 
-        timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base);
-        mov_seek_stream(s, st, timestamp, flags);
+            timestamp = av_rescale_q(seek_timestamp, s->streams[stream_index]->time_base, st->time_base);
+            mov_seek_stream(s, st, timestamp, flags, 0);
+        }
+    } else {
+        int64_t seek_pos = st->index_entries[sample].pos;
+        int i;
+
+        for (i = 0; i < s->nb_streams; i++) {
+            st = s->streams[i];
+
+            if (stream_index == i)
+                continue;
+
+            mov_seek_stream(s, st, seek_pos, flags, 1);
+        }
     }
     return 0;
 }
@@ -4362,6 +4399,10 @@ static const AVOption mov_options[] = {
         0, 1, FLAGS},
     {"ignore_editlist", "", OFFSET(ignore_editlist), FF_OPT_TYPE_INT, {.i64 = 0},
         0, 1, FLAGS},
+    {"seek_keep_order",
+        "If seeking, keep the same packet demuxing order as if demuxing linearly.",
+        OFFSET(seek_keep_order), FF_OPT_TYPE_INT, { .i64 = 0 },
+        0, 1, FLAGS},
     {"use_mfra_for",
         "use mfra for fragment timestamps",
         OFFSET(use_mfra_for), FF_OPT_TYPE_INT, {.i64 = FF_MOV_FLAG_MFRA_AUTO},
diff --git a/libavformat/version.h b/libavformat/version.h
index ba4c7c8..52ecfd0 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -30,8 +30,8 @@
 #include "libavutil/version.h"
 
 #define LIBAVFORMAT_VERSION_MAJOR 56
-#define LIBAVFORMAT_VERSION_MINOR  25
-#define LIBAVFORMAT_VERSION_MICRO 101
+#define LIBAVFORMAT_VERSION_MINOR  26
+#define LIBAVFORMAT_VERSION_MICRO 100
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
-- 
1.8.3.1



More information about the ffmpeg-devel mailing list