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.buitenh...@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

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to