[vlc-commits] add support for parsing moof box in libmp4

Luc Saillard git at videolan.org
Fri Jul 22 02:15:42 CEST 2011


vlc | branch: master | Luc Saillard <luc.saillard at sfr.com> | Wed Jul 20 18:13:04 2011 +0200| [3defabc04f3c4b492358bd4c8b183a06516c7ae8] | committer: Jean-Baptiste Kempf

add support for parsing moof box in libmp4

moof box is a new box mainly used to produce fragmented mp4 movie.
Smoothstreaming is known to used this format.

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3defabc04f3c4b492358bd4c8b183a06516c7ae8
---

 modules/demux/mp4/libmp4.c |  124 ++++++++++++++++++++++++++++++++++++++++++++
 modules/demux/mp4/libmp4.h |   60 +++++++++++++++++++++
 modules/demux/mp4/mp4.c    |    9 +++-
 3 files changed, 191 insertions(+), 2 deletions(-)

diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c
index 7eb900a..51efe16 100644
--- a/modules/demux/mp4/libmp4.c
+++ b/modules/demux/mp4/libmp4.c
@@ -476,6 +476,124 @@ static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
     MP4_READBOX_EXIT( 1 );
 }
 
+static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
+
+    MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
+                  p_box->data.p_mfhd->i_sequence_number );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_tfhd(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
+
+    MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
+
+    if( p_box->data.p_tfhd->i_version == 0 )
+    {
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+            MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+            MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+            MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
+
+#ifdef MP4_VERBOSE
+        char psz_base[128] = "\0";
+        char psz_desc[128] = "\0";
+        char psz_dura[128] = "\0";
+        char psz_size[128] = "\0";
+        char psz_flag[128] = "\0";
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+            snprintf(psz_base, sizeof(psz_base), "base offset %lld", p_box->data.p_tfhd->i_base_data_offset);
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+            snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+            snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+            snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
+        if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+            snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
+
+        msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
+                    p_box->data.p_tfhd->i_version,
+                    p_box->data.p_tfhd->i_flags,
+                    p_box->data.p_tfhd->i_track_ID,
+                    psz_base, psz_desc, psz_dura, psz_size, psz_flag );
+#endif
+    }
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_trun(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_trun_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_trun );
+
+    MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
+
+    if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
+        MP4_GET8BYTES( p_box->data.p_trun->i_data_offset );
+    if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
+        MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
+
+    p_box->data.p_trun->p_samples =
+      calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
+    if ( p_box->data.p_trun->p_samples == NULL )
+      MP4_READBOX_EXIT( 0 );
+
+    for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
+    {
+        MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
+            MP4_GET4BYTES( p_sample->i_duration );
+        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
+            MP4_GET4BYTES( p_sample->i_size );
+        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
+            MP4_GET4BYTES( p_sample->i_flags );
+        if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
+            MP4_GET4BYTES( p_sample->i_composition_time_offset );
+    }
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"trun\" version %d flags 0x%x sample count %d",
+                  p_box->data.p_trun->i_version,
+                  p_box->data.p_trun->i_flags,
+                  p_box->data.p_trun->i_sample_count );
+
+    for( unsigned int i = 0; i<p_box->data.p_trun->i_sample_count; i++ )
+    {
+        MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+        msg_Dbg( p_stream, "read box: \"trun\" sample %4.4d flags 0x%x duration %d size %d composition time offset %d",
+                        i, p_sample->i_flags, p_sample->i_duration,
+                        p_sample->i_size, p_sample->i_composition_time_offset );
+    }
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_trun( MP4_Box_t *p_box )
+{
+    FREENULL( p_box->data.p_trun->p_samples );
+}
+
+
+
 static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
 {
     unsigned int i;
@@ -2782,6 +2900,12 @@ static const struct
     /* iTunes/Quicktime meta info */
     { FOURCC_meta,  MP4_ReadBox_meta,       MP4_FreeBox_Common },
 
+    /* found in smoothstreaming */
+    { FOURCC_traf,  MP4_ReadBoxContainer,      MP4_FreeBox_Common },
+    { FOURCC_mfhd,  MP4_ReadBox_mfhd,          MP4_FreeBox_Common },
+    { FOURCC_tfhd,  MP4_ReadBox_tfhd,          MP4_FreeBox_Common },
+    { FOURCC_trun,  MP4_ReadBox_trun,          MP4_FreeBox_trun },
+
     /* Last entry */
     { 0,             MP4_ReadBox_default,       NULL }
 };
diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h
index 5e2181a..89a5dc1 100644
--- a/modules/demux/mp4/libmp4.h
+++ b/modules/demux/mp4/libmp4.h
@@ -821,6 +821,63 @@ typedef struct
 
 } MP4_Box_data_rmqu_t;
 
+typedef struct MP4_Box_data_mfhd_s
+{
+    uint32_t i_sequence_number;
+
+    uint8_t *p_vendor_extension;
+
+} MP4_Box_data_mfhd_t;
+
+#define MP4_TFHD_BASE_DATA_OFFSET     (1LL<<0)
+#define MP4_TFHD_SAMPLE_DESC_INDEX    (1LL<<1)
+#define MP4_TFHD_DFLT_SAMPLE_DURATION (1LL<<3)
+#define MP4_TFHD_DFLT_SAMPLE_SIZE     (1LL<<4)
+#define MP4_TFHD_DFLT_SAMPLE_FLAGS    (1LL<<5)
+typedef struct MP4_Box_data_tfhd_s
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+    uint32_t i_track_ID;
+
+    /* optional fields */
+    uint64_t i_base_data_offset;
+    uint32_t i_sample_description_index;
+    uint32_t i_default_sample_duration;
+    uint32_t i_default_sample_size;
+    uint32_t i_default_sample_flags;
+
+} MP4_Box_data_tfhd_t;
+
+#define MP4_TRUN_DATA_OFFSET         (1<<0)
+#define MP4_TRUN_FIRST_FLAGS         (1<<2)
+#define MP4_TRUN_SAMPLE_DURATION     (1<<8)
+#define MP4_TRUN_SAMPLE_SIZE         (1<<9)
+#define MP4_TRUN_SAMPLE_FLAGS        (1<<10)
+#define MP4_TRUN_SAMPLE_TIME_OFFSET  (1<<11)
+typedef struct MP4_descriptor_trun_sample_t
+{
+    uint32_t i_duration;
+    uint32_t i_size;
+    uint32_t i_flags;
+    uint32_t i_composition_time_offset;
+} MP4_descriptor_trun_sample_t;
+
+typedef struct MP4_Box_data_trun_s
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+    uint32_t i_sample_count;
+
+    /* optional fields */
+    uint32_t i_data_offset;
+    uint32_t i_first_sample_flags;
+
+    MP4_descriptor_trun_sample_t *p_samples;
+
+} MP4_Box_data_trun_t;
+
+
 typedef struct
 {
     char *psz_text;
@@ -916,6 +973,9 @@ typedef union MP4_Box_data_s
 {
     MP4_Box_data_ftyp_t *p_ftyp;
     MP4_Box_data_mvhd_t *p_mvhd;
+    MP4_Box_data_mfhd_t *p_mfhd;
+    MP4_Box_data_tfhd_t *p_tfhd;
+    MP4_Box_data_trun_t *p_trun;
     MP4_Box_data_tkhd_t *p_tkhd;
     MP4_Box_data_mdhd_t *p_mdhd;
     MP4_Box_data_hdlr_t *p_hdlr;
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 562a18d..b4f99f4 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -368,8 +368,13 @@ static int Open( vlc_object_t * p_this )
 
         if( !p_foov )
         {
-            msg_Err( p_demux, "MP4 plugin discarded (no moov box)" );
-            goto error;
+            /* search also for moof box used by smoothstreaming */
+            p_foov = MP4_BoxGet( p_sys->p_root, "/moof" );
+            if( !p_foov )
+            {
+                msg_Err( p_demux, "MP4 plugin discarded (no moov,foov,moof box)" );
+                goto error;
+            }
         }
         /* we have a free box as a moov, rename it */
         p_foov->i_type = FOURCC_moov;



More information about the vlc-commits mailing list