[FFmpeg-devel] [PATCH 1/3] moof is parsed corresponding to the smoothstreaming specification.

Florent Tribouilloy florent.tribouilloy at smartjog.com
Thu Jul 18 17:36:32 CEST 2013


Adapt the decoder to the Protected Interoperable File Format (PIFF) specification.
Create the stream when we got the traf and set the corresponding stream informatin.
It is used with the smoothstreaming decoder.

Signed-off-by: Florent Tribouilloy <florent.tribouilloy at smartjog.com>
---
 libavformat/isom.h |    5 +++
 libavformat/mov.c  |  111 ++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 95 insertions(+), 21 deletions(-)

diff --git a/libavformat/isom.h b/libavformat/isom.h
index b0fa453..842f733 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -150,6 +150,7 @@ typedef struct MOVContext {
     int time_scale;
     int64_t duration;     ///< duration of the longest track
     int found_moov;       ///< 'moov' atom has been found
+    int found_moof;       ///< 'moof' atom has been found
     int found_mdat;       ///< 'mdat' atom has been found
     DVDemuxContext *dv_demux;
     AVFormatContext *dv_fctx;
@@ -161,6 +162,7 @@ typedef struct MOVContext {
     int chapter_track;
     int use_absolute_path;
     int ignore_editlist;
+    int flags;
     int64_t next_root_atom; ///< offset of the next root atom
     int *bitrates;          ///< bitrates read before streams creation
     int bitrates_count;
@@ -178,6 +180,9 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id);
 #define MP4DecSpecificDescrTag          0x05
 #define MP4SLDescrTag                   0x06
 
+#define MOV_FLAG_NOTSET                 0x00
+#define MOV_FLAG_MSS                    0x01
+
 #define MOV_TFHD_BASE_DATA_OFFSET       0x01
 #define MOV_TFHD_STSD_ID                0x02
 #define MOV_TFHD_DEFAULT_DURATION       0x08
diff --git a/libavformat/mov.c b/libavformat/mov.c
index cdc00eb..2f59240 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -803,6 +803,7 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     c->fragment.moof_offset = avio_tell(pb) - 8;
     av_dlog(c->fc, "moof offset %"PRIx64"\n", c->fragment.moof_offset);
+    c->found_moof = 1;
     return mov_read_default(c, pb, atom);
 }
 
@@ -2337,6 +2338,54 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     return 0;
 }
 
+static int mov_read_traf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
+{
+    AVStream *st;
+    MOVStreamContext *sc;
+    int ret;
+
+    if ((c->flags & MOV_FLAG_MSS)) {
+        st = avformat_new_stream(c->fc, NULL);
+        if (!st)
+            return AVERROR(ENOMEM);
+        st->id = c->fc->nb_streams;
+        sc = av_mallocz(sizeof(MOVStreamContext));
+        if (!sc) {
+            av_free(st);
+            return AVERROR(ENOMEM);
+        }
+
+        st->priv_data = sc;
+        st->codec->codec_type = AVMEDIA_TYPE_DATA;
+        sc->ffindex = st->index;
+        fix_timescale(c, sc);
+
+        avpriv_set_pts_info(st, 64, 1, sc->time_scale);
+
+        mov_build_index(c, st);
+        sc->pb = c->fc->pb;
+        sc->pb_is_copied = 1;
+
+        if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+            if (!st->sample_aspect_ratio.num &&
+                (st->codec->width != sc->width || st->codec->height != sc->height)) {
+                st->sample_aspect_ratio = av_d2q(((double)st->codec->height * sc->width) /
+                                                 ((double)st->codec->width * sc->height), INT_MAX);
+            }
+
+            if (st->duration > 0)
+                av_reduce(&st->avg_frame_rate.num, &st->avg_frame_rate.den,
+                          sc->time_scale*st->nb_frames, st->duration, INT_MAX);
+
+        }
+
+    }
+
+    if ((ret = mov_read_default(c, pb, atom)) < 0)
+        return ret;
+    return 0;
+}
+
 static int mov_read_ilst(MOVContext *c, AVIOContext *pb, MOVAtom atom)
 {
     int ret;
@@ -2471,26 +2520,39 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom)
     if (!track_id)
         return AVERROR_INVALIDDATA;
     frag->track_id = track_id;
-    for (i = 0; i < c->trex_count; i++)
-        if (c->trex_data[i].track_id == frag->track_id) {
-            trex = &c->trex_data[i];
-            break;
+
+    if (!(c->flags & MOV_FLAG_MSS)) {
+        for (i = 0; i < c->trex_count; i++)
+            if (c->trex_data[i].track_id == frag->track_id) {
+                trex = &c->trex_data[i];
+                break;
+            }
+        if (!trex) {
+            av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n");
+            return AVERROR_INVALIDDATA;
         }
-    if (!trex) {
-        av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n");
-        return AVERROR_INVALIDDATA;
-    }
 
-    frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
-                             avio_rb64(pb) : frag->moof_offset;
-    frag->stsd_id  = flags & MOV_TFHD_STSD_ID ? avio_rb32(pb) : trex->stsd_id;
+        frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
+            avio_rb64(pb) : frag->moof_offset;
+        frag->stsd_id  = flags & MOV_TFHD_STSD_ID ? avio_rb32(pb) : trex->stsd_id;
 
-    frag->duration = flags & MOV_TFHD_DEFAULT_DURATION ?
-                     avio_rb32(pb) : trex->duration;
-    frag->size     = flags & MOV_TFHD_DEFAULT_SIZE ?
-                     avio_rb32(pb) : trex->size;
-    frag->flags    = flags & MOV_TFHD_DEFAULT_FLAGS ?
-                     avio_rb32(pb) : trex->flags;
+        frag->duration = flags & MOV_TFHD_DEFAULT_DURATION ?
+            avio_rb32(pb) : trex->duration;
+        frag->size     = flags & MOV_TFHD_DEFAULT_SIZE ?
+            avio_rb32(pb) : trex->size;
+        frag->flags    = flags & MOV_TFHD_DEFAULT_FLAGS ?
+            avio_rb32(pb) : trex->flags;
+    } else {
+        frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ?
+            avio_rb64(pb) : frag->moof_offset;
+        frag->track_id = 1; /* only one for smooth */
+        frag->stsd_id = 1;
+        frag->duration = flags & MOV_TFHD_DEFAULT_DURATION ?
+            avio_rb32(pb) : 0;
+        frag->size = flags & MOV_TFHD_DEFAULT_SIZE ?
+            avio_rb32(pb) : 0;
+        frag->flags    = flags & MOV_TFHD_DEFAULT_FLAGS ? avio_rb32(pb) : 0;
+    }
     av_dlog(c->fc, "frag flags 0x%x\n", frag->flags);
     return 0;
 }
@@ -2870,7 +2932,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = {
 { MKTAG('t','k','h','d'), mov_read_tkhd }, /* track header */
 { MKTAG('t','f','h','d'), mov_read_tfhd }, /* track fragment header */
 { MKTAG('t','r','a','k'), mov_read_trak },
-{ MKTAG('t','r','a','f'), mov_read_default },
+{ MKTAG('t','r','a','f'), mov_read_traf },
 { MKTAG('t','r','e','f'), mov_read_default },
 { MKTAG('t','m','c','d'), mov_read_tmcd },
 { MKTAG('c','h','a','p'), mov_read_chap },
@@ -2907,7 +2969,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             a.size = avio_rb32(pb);
             a.type = avio_rl32(pb);
             if (atom.type != MKTAG('r','o','o','t') &&
-                atom.type != MKTAG('m','o','o','v'))
+                atom.type != MKTAG('m','o','o','v') && atom.type != MKTAG('m','o','o','f'))
             {
                 if (a.type == MKTAG('t','r','a','k') || a.type == MKTAG('m','d','a','t'))
                 {
@@ -2951,7 +3013,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom)
             int err = parse(c, pb, a);
             if (err < 0)
                 return err;
-            if (c->found_moov && c->found_mdat &&
+            if ((c->found_moov || c->found_moof) && c->found_mdat &&
                 ((!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX) ||
                  start_pos + a.size == avio_size(pb))) {
                 if (!pb->seekable || c->fc->flags & AVFMT_FLAG_IGNIDX)
@@ -3265,7 +3327,7 @@ static int mov_read_header(AVFormatContext *s)
         mov_read_close(s);
         return err;
     }
-    if (!mov->found_moov) {
+    if (!mov->found_moov && !mov->found_moof) {
         av_log(s, AV_LOG_ERROR, "moov atom not found\n");
         mov_read_close(s);
         return AVERROR_INVALIDDATA;
@@ -3508,6 +3570,13 @@ static int mov_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti
 }
 
 static const AVOption options[] = {
+    {"movdflags", "MOV demuxer flags", offsetof(MOVContext, flags),
+        AV_OPT_TYPE_FLAGS, {.i64 = MOV_FLAG_NOTSET}, INT_MIN, INT_MAX,
+        AV_OPT_FLAG_ENCODING_PARAM, "movdflags"},
+    {"smooth",
+        "Understand boxes from the smooth streaming fragments", 0,
+        AV_OPT_TYPE_CONST, {.i64 = MOV_FLAG_MSS}, INT_MIN, INT_MAX,
+        AV_OPT_FLAG_ENCODING_PARAM, "movdflags"},
     {"use_absolute_path",
         "allow using absolute path when opening alias, this is a possible security issue",
         offsetof(MOVContext, use_absolute_path), FF_OPT_TYPE_INT, {.i64 = 0},
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list