[2/2] movdec: Add an option for not parsing all fragments in seekable files

Message ID 1329820780-46392-2-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö Feb. 21, 2012, 10:39 a.m.
In nonseekable files, we already stop parsing the toplevel atoms
after finding moov and one mdat. In large seekable files (or files
that are seekable, but slowly, e.g. http), reading all the fragments
at the start can take a considerable amount of time. This allows
opting out from this behaviour.

If there's some generic AVFormatContext field that could be used
for this, that might be a good idea, but if using e.g.
max_analyze_duration for this, we would never get a proper
duration set for sensibly fragmented mp4 files.
---
 libavformat/isom.h |    2 ++
 libavformat/mov.c  |   25 +++++++++++++++++++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)

Comments

Luca Barbato Feb. 21, 2012, 12:22 p.m. | #1
On 21/02/12 11:39, Martin Storsjö wrote:
> In nonseekable files, we already stop parsing the toplevel atoms
> after finding moov and one mdat. In large seekable files (or files
> that are seekable, but slowly, e.g. http), reading all the fragments
> at the start can take a considerable amount of time. This allows
> opting out from this behaviour.
> 
> If there's some generic AVFormatContext field that could be used
> for this, that might be a good idea, but if using e.g.
> max_analyze_duration for this, we would never get a proper
> duration set for sensibly fragmented mp4 files.

Nice =)

lu

Patch

diff --git a/libavformat/isom.h b/libavformat/isom.h
index 214af58..7b2f13c 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -130,6 +130,7 @@  typedef struct MOVStreamContext {
 } MOVStreamContext;
 
 typedef struct MOVContext {
+    const AVClass *class; ///< Class for private options
     AVFormatContext *fc;
     int time_scale;
     int64_t duration;     ///< duration of the longest track
@@ -144,6 +145,7 @@  typedef struct MOVContext {
     int itunes_metadata;  ///< metadata are itunes style
     int chapter_track;
     int64_t next_root_atom; ///< offset of the next root atom
+    int flags;
 } MOVContext;
 
 int ff_mp4_read_descr_len(AVIOContext *pb);
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 7281596..1f23e54 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -30,6 +30,7 @@ 
 #include "libavutil/mathematics.h"
 #include "libavutil/avstring.h"
 #include "libavutil/dict.h"
+#include "libavutil/opt.h"
 #include "avformat.h"
 #include "internal.h"
 #include "avio_internal.h"
@@ -54,6 +55,17 @@ 
 #undef NDEBUG
 #include <assert.h>
 
+#define OFFSET(x) offsetof(MOVContext, x)
+#define D AV_OPT_FLAG_DECODING_PARAM
+
+#define MOV_FLAG_SKIP_PARSE_FRAGS 0x01
+
+const AVOption options[] = {
+    { "movflags", "Flags for the mov demuxer", OFFSET(flags), AV_OPT_TYPE_FLAGS, { 0 }, INT_MIN, INT_MAX, D, "movflags" },
+    { "skip_parse_frags", "Don't parse fragments initially in seekable files", 0, AV_OPT_TYPE_CONST, { MOV_FLAG_SKIP_PARSE_FRAGS }, 0, 0, D, "movflags" },
+    { NULL }
+};
+
 /* those functions parse an atom */
 /* links atom IDs to parse functions */
 typedef struct MOVParseTableEntry {
@@ -350,8 +362,9 @@  static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             if (err < 0)
                 return err;
             if (c->found_moov && c->found_mdat &&
-                (!pb->seekable || start_pos + a.size == avio_size(pb))) {
-                if (!pb->seekable)
+                ((!pb->seekable || c->flags & MOV_FLAG_SKIP_PARSE_FRAGS) ||
+                 start_pos + a.size == avio_size(pb))) {
+                if (!pb->seekable || c->flags & MOV_FLAG_SKIP_PARSE_FRAGS)
                     c->next_root_atom = start_pos + a.size;
                 return 0;
             }
@@ -2833,6 +2846,13 @@  static int mov_read_close(AVFormatContext *s)
     return 0;
 }
 
+static const AVClass mov_demuxer_class = {
+    .class_name     = "MOV/MP4 demuxer",
+    .item_name      = av_default_item_name,
+    .option         = options,
+    .version        = LIBAVUTIL_VERSION_INT,
+};
+
 AVInputFormat ff_mov_demuxer = {
     .name           = "mov,mp4,m4a,3gp,3g2,mj2",
     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime/MPEG-4/Motion JPEG 2000 format"),
@@ -2842,4 +2862,5 @@  AVInputFormat ff_mov_demuxer = {
     .read_packet    = mov_read_packet,
     .read_close     = mov_read_close,
     .read_seek      = mov_read_seek,
+    .priv_class     = &mov_demuxer_class,
 };