]> git.sesse.net Git - vlc/blobdiff - modules/demux/mp4/libmp4.c
demux: mp4: remove special handler for atom gnre
[vlc] / modules / demux / mp4 / libmp4.c
index 064f6f5d256a102ae5f80ad76d6efd84f7b697d0..f0c4433e108d59cc77062aef120933d3522941b9 100644 (file)
@@ -191,15 +191,15 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box )
  *       after called one of theses functions, file position is unknown
  *       you need to call MP4_GotoBox to go where you want
  *****************************************************************************/
-int MP4_ReadBoxContainerChildren( stream_t *p_stream,
-                                  MP4_Box_t *p_container, uint32_t i_last_child )
+static int MP4_ReadBoxContainerChildrenIndexed( stream_t *p_stream,
+               MP4_Box_t *p_container, uint32_t i_last_child, bool b_indexed )
 {
     MP4_Box_t *p_box;
 
     /* Size of root container is set to 0 when unknown, for exemple
      * with a DASH stream. In that case, we skip the following check */
     if( p_container->i_size
-            && ( stream_Tell( p_stream ) + 8 >
+            && ( stream_Tell( p_stream ) + ((b_indexed)?16:8) >
         (off_t)(p_container->i_pos + p_container->i_size) )
       )
     {
@@ -209,7 +209,16 @@ int MP4_ReadBoxContainerChildren( stream_t *p_stream,
 
     do
     {
+        uint32_t i_index = 0;
+        if ( b_indexed )
+        {
+            uint8_t read[8];
+            if ( stream_Read( p_stream, read, 8 ) < 8 )
+                return 0;
+            i_index = GetDWBE(&read[4]);
+        }
         if( ( p_box = MP4_ReadBox( p_stream, p_container ) ) == NULL ) break;
+        p_box->i_index = i_index;
 
         /* chain this box with the father and the other at same level */
         if( !p_container->p_first ) p_container->p_first = p_box;
@@ -227,6 +236,13 @@ int MP4_ReadBoxContainerChildren( stream_t *p_stream,
     return 1;
 }
 
+int MP4_ReadBoxContainerChildren( stream_t *p_stream, MP4_Box_t *p_container,
+                                  uint32_t i_last_child )
+{
+    return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_container,
+                                                i_last_child, false );
+}
+
 static int MP4_ReadBoxContainerRaw( stream_t *p_stream, MP4_Box_t *p_container )
 {
     return MP4_ReadBoxContainerChildren( p_stream, p_container, 0 );
@@ -294,6 +310,41 @@ static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
     return 1;
 }
 
+static int MP4_ReadBox_ilst( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    if( p_box->i_size < 8 || stream_Read( p_stream, NULL, 8 ) < 8 )
+        return 0;
+
+    /* Find our handler */
+    if ( !p_box->i_handler && p_box->p_father )
+    {
+        const MP4_Box_t *p_sibling = p_box->p_father->p_first;
+        while( p_sibling )
+        {
+            if ( p_sibling->i_type == ATOM_hdlr && p_sibling->data.p_hdlr )
+            {
+                p_box->i_handler = p_sibling->data.p_hdlr->i_handler_type;
+                break;
+            }
+            p_sibling = p_sibling->p_next;
+        }
+    }
+
+    switch( p_box->i_handler )
+    {
+    case 0:
+        msg_Warn( p_stream, "no handler for ilst atom" );
+        return 0;
+    case HANDLER_mdta:
+        return MP4_ReadBoxContainerChildrenIndexed( p_stream, p_box, 0, true );
+    case HANDLER_mdir:
+        return MP4_ReadBoxContainerChildren( p_stream, p_box, 0 );
+    default:
+        msg_Warn( p_stream, "Unknown ilst handler type '%4.4s'", (char*)&p_box->i_handler );
+        return 0;
+    }
+}
+
 static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_READBOX_ENTER( MP4_Box_data_ftyp_t );
@@ -1212,7 +1263,7 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
 
 
     MP4_GET1BYTE( i_type );
-    if( i_type == 0x03 ) /* MP4ESDescrTag */
+    if( i_type == 0x03 ) /* MP4ESDescrTag ISO/IEC 14496-1 8.3.3 */
     {
         i_len = MP4_ReadLengthDescriptor( &p_peek, &i_read );
 
@@ -1258,7 +1309,7 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_GET1BYTE( i_type ); /* get next type */
     }
 
-    if( i_type != 0x04)/* MP4DecConfigDescrTag */
+    if( i_type != 0x04)/* MP4DecConfigDescrTag ISO/IEC 14496-1 8.3.4 */
     {
          es_descriptor.p_decConfigDescr = NULL;
          MP4_READBOX_EXIT( 1 ); /* rest isn't interesting up to now */
@@ -1276,7 +1327,7 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
     if( unlikely( es_descriptor.p_decConfigDescr == NULL ) )
         MP4_READBOX_EXIT( 0 );
 
-    MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectTypeIndication );
+    MP4_GET1BYTE( es_descriptor.p_decConfigDescr->i_objectProfileIndication );
     MP4_GET1BYTE( i_flags );
     es_descriptor.p_decConfigDescr->i_streamType = i_flags >> 2;
     es_descriptor.p_decConfigDescr->b_upStream = ( i_flags >> 1 )&0x01;
@@ -1284,7 +1335,7 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_max_bitrate );
     MP4_GET4BYTES( es_descriptor.p_decConfigDescr->i_avg_bitrate );
     MP4_GET1BYTE( i_type );
-    if( i_type !=  0x05 )/* MP4DecSpecificDescrTag */
+    if( i_type !=  0x05 )/* MP4DecSpecificDescrTag ISO/IEC 14496-1 8.3.5 */
     {
         es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = 0;
         es_descriptor.p_decConfigDescr->p_decoder_specific_info  = NULL;
@@ -1459,6 +1510,101 @@ error:
     MP4_READBOX_EXIT( 0 );
 }
 
+static int MP4_ReadBox_WMA2( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_WMA2_t );
+
+    MP4_Box_data_WMA2_t *p_WMA2 = p_box->data.p_WMA2;
+
+    MP4_GET2BYTESLE( p_WMA2->Format.wFormatTag );
+    MP4_GET2BYTESLE( p_WMA2->Format.nChannels );
+    MP4_GET4BYTESLE( p_WMA2->Format.nSamplesPerSec );
+    MP4_GET4BYTESLE( p_WMA2->Format.nAvgBytesPerSec );
+    MP4_GET2BYTESLE( p_WMA2->Format.nBlockAlign );
+    MP4_GET2BYTESLE( p_WMA2->Format.wBitsPerSample );
+
+    uint16_t i_cbSize;
+    MP4_GET2BYTESLE( i_cbSize );
+
+    if ( i_read < 0 || i_cbSize > i_read )
+        goto error;
+
+    p_WMA2->i_extra = i_cbSize;
+    if ( p_WMA2->i_extra )
+    {
+        p_WMA2->p_extra = malloc( p_WMA2->i_extra );
+        if ( ! p_WMA2->p_extra )
+            goto error;
+        memcpy( p_WMA2->p_extra, p_peek, p_WMA2->i_extra );
+    }
+
+    MP4_READBOX_EXIT( 1 );
+
+error:
+    MP4_READBOX_EXIT( 0 );
+}
+
+static void MP4_FreeBox_WMA2( MP4_Box_t *p_box )
+{
+    FREENULL( p_box->data.p_WMA2->p_extra );
+}
+
+static int MP4_ReadBox_strf( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_strf_t );
+
+    MP4_Box_data_strf_t *p_strf = p_box->data.p_strf;
+
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biSize );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biWidth );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biHeight );
+    MP4_GET2BYTESLE( p_strf->bmiHeader.biPlanes );
+    MP4_GET2BYTESLE( p_strf->bmiHeader.biBitCount );
+    MP4_GETFOURCC( p_strf->bmiHeader.biCompression );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biSizeImage );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biXPelsPerMeter );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biYPelsPerMeter );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biClrUsed );
+    MP4_GET4BYTESLE( p_strf->bmiHeader.biClrImportant );
+
+    if ( i_read < 0 )
+        goto error;
+
+    p_strf->i_extra = i_read;
+    if ( p_strf->i_extra )
+    {
+        p_strf->p_extra = malloc( p_strf->i_extra );
+        if ( ! p_strf->p_extra )
+            goto error;
+        memcpy( p_strf->p_extra, p_peek, i_read );
+    }
+
+    MP4_READBOX_EXIT( 1 );
+
+error:
+    MP4_READBOX_EXIT( 0 );
+}
+
+static void MP4_FreeBox_strf( MP4_Box_t *p_box )
+{
+    FREENULL( p_box->data.p_strf->p_extra );
+}
+
+static int MP4_ReadBox_ASF( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_ASF_t );
+
+    MP4_Box_data_ASF_t *p_asf = p_box->data.p_asf;
+
+    if (i_read != 8)
+        MP4_READBOX_EXIT( 0 );
+
+    MP4_GET1BYTE( p_asf->i_stream_number );
+    /* remaining is unknown */
+
+    MP4_READBOX_EXIT( 1 );
+}
+
 static int MP4_ReadBox_stsdext_chan( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_READBOX_ENTER( MP4_Box_data_chan_t );
@@ -1472,23 +1618,30 @@ static int MP4_ReadBox_stsdext_chan( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET4BYTES( p_chan->layout.i_channels_layout_tag );
     MP4_GET4BYTES( p_chan->layout.i_channels_bitmap );
     MP4_GET4BYTES( p_chan->layout.i_channels_description_count );
-    if ( i_read < p_chan->layout.i_channels_description_count * 24 )
+
+    size_t i_descsize = 8 + 3 * sizeof(float);
+    if ( (size_t)i_read < p_chan->layout.i_channels_description_count * i_descsize )
         MP4_READBOX_EXIT( 0 );
 
     p_chan->layout.p_descriptions =
-        malloc( p_chan->layout.i_channels_description_count * 24 );
+        malloc( p_chan->layout.i_channels_description_count * i_descsize );
 
     if ( !p_chan->layout.p_descriptions )
         MP4_READBOX_EXIT( 0 );
 
-    for( uint32_t i=0; i<p_chan->layout.i_channels_description_count; i++ )
+    uint32_t i;
+    for( i=0; i<p_chan->layout.i_channels_description_count; i++ )
     {
+        if ( i_read < 20 )
+            break;
         MP4_GET4BYTES( p_chan->layout.p_descriptions[i].i_channel_label );
         MP4_GET4BYTES( p_chan->layout.p_descriptions[i].i_channel_flags );
         MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[0] );
         MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[1] );
         MP4_GET4BYTES( p_chan->layout.p_descriptions[i].f_coordinates[2] );
     }
+    if ( i<p_chan->layout.i_channels_description_count )
+        p_chan->layout.i_channels_description_count = i;
 
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream,
@@ -1621,74 +1774,6 @@ static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_READBOX_EXIT( 1 );
 }
 
-static int MP4_ReadBox_gnre( stream_t *p_stream, MP4_Box_t *p_box )
-{
-    MP4_Box_data_gnre_t *p_gnre;
-    MP4_READBOX_ENTER( MP4_Box_data_gnre_t );
-
-    p_gnre = p_box->data.p_gnre;
-
-    uint32_t i_data_len;
-    uint32_t i_data_tag;
-
-    MP4_GET4BYTES( i_data_len );
-    MP4_GETFOURCC( i_data_tag );
-    if( i_data_len < 10 || i_data_tag != ATOM_data )
-        MP4_READBOX_EXIT( 0 );
-
-    uint32_t i_version;
-    VLC_UNUSED(i_version);
-    uint32_t i_reserved;
-    VLC_UNUSED(i_reserved);
-    MP4_GET4BYTES( i_version );
-    MP4_GET4BYTES( i_reserved );
-    MP4_GET2BYTES( p_gnre->i_genre );
-    if( p_gnre->i_genre == 0 )
-        MP4_READBOX_EXIT( 0 );
-#ifdef MP4_VERBOSE
-    msg_Dbg( p_stream, "read box: \"gnre\" genre=%i", p_gnre->i_genre );
-#endif
-
-    MP4_READBOX_EXIT( 1 );
-}
-
-static int MP4_ReadBox_trkn( stream_t *p_stream, MP4_Box_t *p_box )
-{
-    MP4_Box_data_trkn_t *p_trkn;
-    MP4_READBOX_ENTER( MP4_Box_data_trkn_t );
-
-    p_trkn = p_box->data.p_trkn;
-
-    uint32_t i_data_len;
-    uint32_t i_data_tag;
-
-    MP4_GET4BYTES( i_data_len );
-    MP4_GETFOURCC( i_data_tag );
-    if( i_data_len < 12 || i_data_tag != ATOM_data )
-        MP4_READBOX_EXIT( 0 );
-
-    uint32_t i_version;
-    VLC_UNUSED(i_version);
-    uint32_t i_reserved;
-    VLC_UNUSED(i_reserved);
-    MP4_GET4BYTES( i_version );
-    MP4_GET4BYTES( i_reserved );
-    MP4_GET2BYTES( i_reserved );
-    MP4_GET2BYTES( p_trkn->i_track_number );
-#ifdef MP4_VERBOSE
-    msg_Dbg( p_stream, "read box: \"trkn\" number=%i", p_trkn->i_track_number );
-#endif
-    if( i_data_len > 15 )
-    {
-       MP4_GET2BYTES( p_trkn->i_track_total );
-#ifdef MP4_VERBOSE
-       msg_Dbg( p_stream, "read box: \"trkn\" total=%i", p_trkn->i_track_total );
-#endif
-    }
-
-    MP4_READBOX_EXIT( 1 );
-}
-
 static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
 {
     p_box->i_handler = ATOM_soun;
@@ -2750,43 +2835,61 @@ static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
     return 1;
 }
 
-static int MP4_ReadBox_name( stream_t *p_stream, MP4_Box_t *p_box )
+static int MP4_ReadBox_String( stream_t *p_stream, MP4_Box_t *p_box )
 {
-    MP4_READBOX_ENTER( MP4_Box_data_name_t );
+    MP4_READBOX_ENTER( MP4_Box_data_string_t );
 
-    p_box->data.p_name->psz_text = malloc( p_box->i_size + 1 - 8 ); /* +\0, -name, -size */
-    if( p_box->data.p_name->psz_text == NULL )
+    p_box->data.p_string->psz_text = malloc( p_box->i_size + 1 - 8 ); /* +\0, -name, -size */
+    if( p_box->data.p_string->psz_text == NULL )
         MP4_READBOX_EXIT( 0 );
 
-    memcpy( p_box->data.p_name->psz_text, p_peek, p_box->i_size - 8 );
-    p_box->data.p_name->psz_text[p_box->i_size - 8] = '\0';
+    memcpy( p_box->data.p_string->psz_text, p_peek, p_box->i_size - 8 );
+    p_box->data.p_string->psz_text[p_box->i_size - 8] = '\0';
 
 #ifdef MP4_VERBOSE
-        msg_Dbg( p_stream, "read box: \"name\" text=`%s'",
-                 p_box->data.p_name->psz_text );
+        msg_Dbg( p_stream, "read box: \"%4.4s\" text=`%s'", (char *) & p_box->i_type,
+                 p_box->data.p_string->psz_text );
 #endif
     MP4_READBOX_EXIT( 1 );
 }
 
-static void MP4_FreeBox_name( MP4_Box_t *p_box )
+static void MP4_FreeBox_String( MP4_Box_t *p_box )
 {
-    FREENULL( p_box->data.p_name->psz_text );
+    FREENULL( p_box->data.p_string->psz_text );
 }
 
 static int MP4_ReadBox_data( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_READBOX_ENTER( MP4_Box_data_data_t );
+    MP4_Box_data_data_t *p_data = p_box->data.p_data;
 
-    /* What's that header ?? */
-    if ( i_read <= 8 )
+    if ( i_read < 8 || i_read - 8 > UINT32_MAX )
         MP4_READBOX_EXIT( 0 );
 
-    p_box->data.p_data->p_blob = malloc( i_read - 8 );
+    uint8_t i_type;
+    MP4_GET1BYTE( i_type );
+    if ( i_type != 0 )
+    {
+#ifdef MP4_VERBOSE
+        msg_Dbg( p_stream, "skipping unknown 'data' atom with type %"PRIu8, i_type );
+#endif
+        MP4_READBOX_EXIT( 0 );
+    }
+
+    MP4_GET3BYTES( p_data->e_wellknowntype );
+    MP4_GET2BYTES( p_data->locale.i_country );
+    MP4_GET2BYTES( p_data->locale.i_language );
+#ifdef MP4_VERBOSE
+        msg_Dbg( p_stream, "read 'data' atom: knowntype=%"PRIu32", country=%"PRIu16" lang=%"PRIu16
+                 ", size %"PRId64" bytes", p_data->e_wellknowntype,
+                 p_data->locale.i_country, p_data->locale.i_language, i_read );
+#endif
+    p_box->data.p_data->p_blob = malloc( i_read );
     if ( !p_box->data.p_data->p_blob )
         MP4_READBOX_EXIT( 0 );
 
-    p_box->data.p_data->i_blob = i_read - 8;
-    memcpy( p_box->data.p_data->p_blob, p_peek + 8, i_read - 8 );
+    p_box->data.p_data->i_blob = i_read;
+    memcpy( p_box->data.p_data->p_blob, p_peek, i_read);
 
     MP4_READBOX_EXIT( 1 );
 }
@@ -2796,89 +2899,62 @@ static void MP4_FreeBox_data( MP4_Box_t *p_box )
     free( p_box->data.p_data->p_blob );
 }
 
+static int MP4_ReadBox_Metadata( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    const uint8_t *p_peek;
+    if ( stream_Peek( p_stream, &p_peek, 16 ) < 16 )
+        return 0;
+    if ( stream_Read( p_stream, NULL, 8 ) < 8 )
+        return 0;
+    return MP4_ReadBoxContainerChildren( p_stream, p_box, ATOM_data );
+}
+
 static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
 {
-    uint16_t i16;
+    return MP4_ReadBox_Metadata( p_stream, p_box );
 
-    MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
+/* FIXME: find out what was that 2 bytes sized atom and its own handler */
+//    if ( GetWBE( &p_peek[8] ) > 0 )
+//        uint16_t i16;
 
-    p_box->data.p_0xa9xxx->psz_text = NULL;
+//    MP4_READBOX_ENTER( MP4_Box_data_string_t );
 
-    MP4_GET2BYTES( i16 );
+//    p_box->data.p_string->psz_text = NULL;
 
-    if( i16 > 0 )
-    {
-        int i_length = i16;
+//    MP4_GET2BYTES( i16 );
 
-        MP4_GET2BYTES( i16 );
-        if( i_length >= i_read ) i_length = i_read + 1;
+//    if( i16 > 0 )
+//    {
+//        int i_length = i16;
 
-        p_box->data.p_0xa9xxx->psz_text = malloc( i_length );
-        if( p_box->data.p_0xa9xxx->psz_text == NULL )
-            MP4_READBOX_EXIT( 0 );
+//        MP4_GET2BYTES( i16 );
+//        if( i_length >= i_read ) i_length = i_read + 1;
 
-        i_length--;
-        memcpy( p_box->data.p_0xa9xxx->psz_text,
-                p_peek, i_length );
-        p_box->data.p_0xa9xxx->psz_text[i_length] = '\0';
+//        p_box->data.p_string->psz_text = malloc( i_length );
+//        if( p_box->data.p_string->psz_text == NULL )
+//            MP4_READBOX_EXIT( 0 );
 
-#ifdef MP4_VERBOSE
-        msg_Dbg( p_stream,
-                 "read box: \"c%3.3s\" text=`%s'",
-                 ((char*)&p_box->i_type + 1),
-                 p_box->data.p_0xa9xxx->psz_text );
-#endif
-    }
-    else
-    {
-        /* try iTune/Quicktime format, rewind to start */
-        p_peek -= 2; i_read += 2;
-        // we are expecting a 'data' box
-        uint32_t i_data_len;
-        uint32_t i_data_tag;
+//        i_length--;
+//        memcpy( p_box->data.p_string->psz_text,
+//                p_peek, i_length );
+//        p_box->data.p_string->psz_text[i_length] = '\0';
 
-        MP4_GET4BYTES( i_data_len );
-        if( i_data_len > i_read ) i_data_len = i_read;
-        MP4_GETFOURCC( i_data_tag );
-        if( (i_data_len > 0) && (i_data_tag == ATOM_data) )
-        {
-            /* data box contains a version/flags field */
-            uint32_t i_version;
-            uint32_t i_reserved;
-            VLC_UNUSED(i_reserved);
-            MP4_GET4BYTES( i_version );
-            MP4_GET4BYTES( i_reserved );
-            // version should be 0, flags should be 1 for text, 0 for data
-            if( ( i_version == 0x00000001 ) && (i_data_len >= 12 ) )
-            {
-                // the rest is the text
-                i_data_len -= 12;
-                p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 );
-                if( p_box->data.p_0xa9xxx->psz_text == NULL )
-                    MP4_READBOX_EXIT( 0 );
-
-                memcpy( p_box->data.p_0xa9xxx->psz_text,
-                        p_peek, i_data_len );
-                p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0';
-#ifdef MP4_VERBOSE
-        msg_Dbg( p_stream,
-                 "read box: \"c%3.3s\" text=`%s'",
-                 ((char*)&p_box->i_type+1),
-                 p_box->data.p_0xa9xxx->psz_text );
-#endif
-            }
-            else
-            {
-                // TODO: handle data values for ID3 tag values, track num or cover art,etc...
-            }
-        }
-    }
+//#ifdef MP4_VERBOSE
+//        msg_Dbg( p_stream,
+//                 "read box: \"c%3.3s\" text=`%s'",
+//                 ((char*)&p_box->i_type + 1),
+//                 p_box->data.p_string->psz_text );
+//#endif
+//    }
+//    else
 
-    MP4_READBOX_EXIT( 1 );
+//    MP4_READBOX_EXIT( 1 );
 }
 static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box )
 {
-    FREENULL( p_box->data.p_0xa9xxx->psz_text );
+    /* If Meta, that box should be empty /common */
+    if( p_box->data.p_string )
+        FREENULL( p_box->data.p_string->psz_text );
 }
 
 /* Chapter support */
@@ -2910,6 +2986,8 @@ static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
         uint64_t i_start;
         uint8_t i_len;
         int i_copy;
+        if ( i_read < 9 )
+            break;
         MP4_GET8BYTES( i_start );
         MP4_GET1BYTE( i_len );
 
@@ -2926,6 +3004,10 @@ static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
         p_peek += i_copy;
         i_read -= i_copy;
     }
+
+    if ( i != p_chpl->i_chapter )
+        p_chpl->i_chapter = i;
+
     /* Bubble sort by increasing start date */
     do
     {
@@ -2982,6 +3064,60 @@ static void MP4_FreeBox_tref_generic( MP4_Box_t *p_box )
     FREENULL( p_box->data.p_tref_generic->i_track_ID );
 }
 
+static int MP4_ReadBox_keys( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_keys_t );
+
+    if ( i_read < 8 )
+        MP4_READBOX_EXIT( 0 );
+
+    uint32_t i_count;
+    MP4_GET4BYTES( i_count ); /* reserved + flags */
+    if ( i_count != 0 )
+        MP4_READBOX_EXIT( 0 );
+
+    MP4_GET4BYTES( i_count );
+    p_box->data.p_keys->p_entries = calloc( i_count, sizeof(*p_box->data.p_keys->p_entries) );
+    if ( !p_box->data.p_keys->p_entries )
+        MP4_READBOX_EXIT( 0 );
+    p_box->data.p_keys->i_entry_count = i_count;
+
+    uint32_t i=0;
+    for( ; i < i_count; i++ )
+    {
+        if ( i_read < 8 )
+            break;
+        uint32_t i_keysize;
+        MP4_GET4BYTES( i_keysize );
+        if ( (i_keysize < 8) || (i_keysize - 4 > i_read) )
+            break;
+        MP4_GETFOURCC( p_box->data.p_keys->p_entries[i].i_namespace );
+        i_keysize -= 8;
+        p_box->data.p_keys->p_entries[i].psz_value = malloc( i_keysize + 1 );
+        if ( !p_box->data.p_keys->p_entries[i].psz_value )
+            break;
+        memcpy( p_box->data.p_keys->p_entries[i].psz_value, p_peek, i_keysize );
+        p_box->data.p_keys->p_entries[i].psz_value[i_keysize] = 0;
+        p_peek += i_keysize;
+        i_read -= i_keysize;
+#ifdef MP4_ULTRA_VERBOSE
+        msg_Dbg( p_stream, "read box: \"keys\": %u '%s'", i + 1,
+                 p_box->data.p_keys->p_entries[i].p_value );
+#endif
+    }
+    if ( i < i_count )
+        p_box->data.p_keys->i_entry_count = i;
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_keys( MP4_Box_t *p_box )
+{
+    for( uint32_t i=0; i<p_box->data.p_keys->i_entry_count; i++ )
+        free( p_box->data.p_keys->p_entries[i].psz_value );
+    free( p_box->data.p_keys->p_entries );
+}
+
 static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
 {
     uint8_t meta_data[8];
@@ -2992,33 +3128,27 @@ static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
     if( i_actually_read < 8 )
         return 0;
 
-    if ( !p_box->p_father )
-        return 0;
-
-    switch( p_box->p_father->i_type )
+    if ( p_box->p_father && p_box->p_father->i_type == ATOM_udta ) /* itunes udta/meta */
     {
-    case ATOM_udta: /* itunes udta/meta */
         /* meta content starts with a 4 byte version/flags value (should be 0) */
         i_actually_read = stream_Read( p_stream, meta_data, 4 );
-        if( i_actually_read < 4 )
+        if( i_actually_read < 4 || memcmp( meta_data, "\0\0\0", 4 ) )
             return 0;
+    }
 
-        /* then it behaves like a container */
-        return MP4_ReadBoxContainerRaw( p_stream, p_box );
-
-    default: /* regular meta atom */
-
-        i_actually_read = stream_Read( p_stream, meta_data, 8 );
-        if( i_actually_read < 8 )
-            return 0;
+    if ( !MP4_ReadBoxContainerChildren( p_stream, p_box, ATOM_hdlr ) )
+        return 0;
 
-        /* Mandatory */
-        if ( VLC_FOURCC( meta_data[4], meta_data[5], meta_data[6], meta_data[7] ) != ATOM_hdlr )
-            return 0;
+    /* Mandatory */
+    const MP4_Box_t *p_hdlr = MP4_BoxGet( p_box, "hdlr" );
+    if ( !p_hdlr || !BOXDATA(p_hdlr) ||
+         ( BOXDATA(p_hdlr)->i_handler_type != HANDLER_mdta &&
+           BOXDATA(p_hdlr)->i_handler_type != HANDLER_mdir ) ||
+         BOXDATA(p_hdlr)->i_version != 0 )
+        return 0;
 
-        //ft
-    }
-    return 1;
+    /* then it behaves like a container */
+    return MP4_ReadBoxContainerRaw( p_stream, p_box );
 }
 
 static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
@@ -3129,7 +3259,8 @@ static int MP4_ReadBox_sdtp( stream_t *p_stream, MP4_Box_t *p_box )
 
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
-    msg_Dbg( p_stream,
+    if ( i_sample_count > 3 )
+        msg_Dbg( p_stream,
              "read box: \"sdtp\" head: %"PRIx8" %"PRIx8" %"PRIx8" %"PRIx8"",
                  p_sdtp->p_sample_table[0],
                  p_sdtp->p_sample_table[1],
@@ -3391,7 +3522,9 @@ static const struct
     { ATOM_tref,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_trak },
     { ATOM_gmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_minf },
     { ATOM_wave,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_stsd },
-    { ATOM_ilst,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_meta },
+    { ATOM_wave,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_mp4a }, /* some quicktime mp4a/wave/mp4a.. */
+    { ATOM_wave,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_WMA2 }, /* flip4mac */
+    { ATOM_ilst,    MP4_ReadBox_ilst,         MP4_FreeBox_Common, ATOM_meta },
     { ATOM_mvex,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_moov },
     { ATOM_mvex,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_ftyp },
 
@@ -3428,6 +3561,7 @@ static const struct
     { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds, ATOM_wave }, /* mp4a in wave chunk */
     { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds, ATOM_mp4a },
     { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds, ATOM_mp4v },
+    { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds, ATOM_mp4s },
     { ATOM_dcom,    MP4_ReadBox_dcom,         MP4_FreeBox_Common, 0 },
     { ATOM_cmvd,    MP4_ReadBox_cmvd,         MP4_FreeBox_cmvd, 0 },
     { ATOM_avcC,    MP4_ReadBox_avcC,         MP4_FreeBox_avcC, ATOM_avc1 },
@@ -3438,6 +3572,7 @@ static const struct
     { ATOM_enda,    MP4_ReadBox_enda,         MP4_FreeBox_Common, 0 },
     { ATOM_iods,    MP4_ReadBox_iods,         MP4_FreeBox_Common, 0 },
     { ATOM_pasp,    MP4_ReadBox_pasp,         MP4_FreeBox_Common, 0 },
+    { ATOM_keys,    MP4_ReadBox_keys,         MP4_FreeBox_keys,   ATOM_meta },
 
     /* Nothing to do with this box */
     { ATOM_mdat,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
@@ -3477,8 +3612,10 @@ static const struct
     { ATOM_sawb,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
     { ATOM_OggS,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
     { ATOM_alac,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_WMA2,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd }, /* flip4mac */
     /* Sound extensions */
     { ATOM_chan,    MP4_ReadBox_stsdext_chan, MP4_FreeBox_stsdext_chan, 0 },
+    { ATOM_WMA2,    MP4_ReadBox_WMA2,         MP4_FreeBox_WMA2,        ATOM_wave }, /* flip4mac */
 
     { ATOM_drmi,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
     { ATOM_vide,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
@@ -3504,6 +3641,7 @@ static const struct
     { ATOM_qdrw,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
     { ATOM_mp2v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
     { ATOM_hdv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_WMV3,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
 
     { ATOM_mjqt,    MP4_ReadBox_default,      NULL, 0 }, /* found in mjpa/b */
     { ATOM_mjht,    MP4_ReadBox_default,      NULL, 0 },
@@ -3522,7 +3660,11 @@ static const struct
     { ATOM_yv12,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, 0 },
     { ATOM_yuv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, 0 },
 
-    { ATOM_mp4s,    MP4_ReadBox_sample_mp4s,  MP4_FreeBox_Common, 0 },
+    { ATOM_strf,    MP4_ReadBox_strf,         MP4_FreeBox_strf,        ATOM_WMV3 }, /* flip4mac */
+    { ATOM_ASF ,    MP4_ReadBox_ASF,          MP4_FreeBox_Common,      ATOM_WMV3 }, /* flip4mac */
+    { ATOM_ASF ,    MP4_ReadBox_ASF,          MP4_FreeBox_Common,      ATOM_wave }, /* flip4mac */
+
+    { ATOM_mp4s,    MP4_ReadBox_sample_mp4s,  MP4_FreeBox_Common,      ATOM_stsd },
 
     /* XXX there is 2 box where we could find this entry stbl and tref*/
     { ATOM_hint,    MP4_ReadBox_default,      MP4_FreeBox_Common, 0 },
@@ -3550,65 +3692,84 @@ static const struct
     { ATOM_iviv,    MP4_ReadBox_drms,         MP4_FreeBox_Common, 0 },
     { ATOM_priv,    MP4_ReadBox_drms,         MP4_FreeBox_Common, 0 },
     { ATOM_frma,    MP4_ReadBox_frma,         MP4_FreeBox_Common, ATOM_sinf }, /* and rinf */
+    { ATOM_frma,    MP4_ReadBox_frma,         MP4_FreeBox_Common, ATOM_wave }, /* flip4mac */
     { ATOM_skcr,    MP4_ReadBox_skcr,         MP4_FreeBox_Common, 0 },
 
-    /* found in udta */
-    { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    /* ilst meta tags */
     { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9req, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9com, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9day, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9src, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9enc, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9url, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9com, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9too, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
     { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9st3, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9ard, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9arg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9cak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9con, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9lnt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9phg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9pub, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9sne, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9sol, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9thx, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_0xa9xpd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
-    { ATOM_chpl,    MP4_ReadBox_chpl,         MP4_FreeBox_chpl,    ATOM_udta },
-
-    { ATOM_gnre,    MP4_ReadBox_gnre,         MP4_FreeBox_Common,  ATOM_ilst },
-    { ATOM_trkn,    MP4_ReadBox_trkn,         MP4_FreeBox_Common,  ATOM_ilst },
+    { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9too, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_chpl,    MP4_ReadBox_chpl,         MP4_FreeBox_chpl,    ATOM_ilst },
+    { ATOM_covr,    MP4_ReadBoxContainer,     MP4_FreeBox_Common,  ATOM_ilst },
+    { ATOM_gnre,    MP4_ReadBox_Metadata,     MP4_FreeBox_Common,  ATOM_ilst },
+    { ATOM_trkn,    MP4_ReadBox_Metadata,     MP4_FreeBox_Common,  ATOM_ilst },
+
+    /* udta */
+    { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9ard, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9arg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9cak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9con, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9com, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9day, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9isr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9lab, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9lal, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9lnt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9mal, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9phg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9pub, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9req, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9sne, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9snm, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9sol, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9src, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9st3, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9thx, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9too, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9url, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9xpd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_0xa9xyz, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_udta },
+    { ATOM_name,    MP4_ReadBox_String,       MP4_FreeBox_String,  ATOM_udta },
+    { ATOM_vndr,    MP4_ReadBox_String,       MP4_FreeBox_String,  ATOM_udta },
+    { ATOM_SDLN,    MP4_ReadBox_String,       MP4_FreeBox_String,  ATOM_udta },
 
     /* iTunes/Quicktime meta info */
     { ATOM_meta,    MP4_ReadBox_meta,         MP4_FreeBox_Common,  0 },
-    { ATOM_name,    MP4_ReadBox_name,         MP4_FreeBox_name,    0 },
-    { ATOM_covr,    MP4_ReadBoxContainer,     MP4_FreeBox_Common,  ATOM_ilst },
     { ATOM_data,    MP4_ReadBox_data,         MP4_FreeBox_data,    0 },
 
     /* found in smoothstreaming */
@@ -3677,6 +3838,8 @@ static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
         return NULL;
     }
 
+    p_box->pf_free = MP4_Box_Function[i_index].MP4_FreeBox_function;
+
     return p_box;
 }
 
@@ -3686,7 +3849,6 @@ static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
  *****************************************************************************/
 void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
 {
-    unsigned int i_index;
     MP4_Box_t    *p_child;
 
     if( !p_box )
@@ -3704,15 +3866,7 @@ void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
     /* Now search function to call */
     if( p_box->data.p_payload )
     {
-        for( i_index = 0; ; i_index++ )
-        {
-            if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
-                ( MP4_Box_Function[i_index].i_type == 0 ) )
-            {
-                break;
-            }
-        }
-        if( MP4_Box_Function[i_index].MP4_FreeBox_function == NULL )
+        if (unlikely( p_box->pf_free == NULL ))
         {
             /* Should not happen */
             if MP4_BOX_TYPE_ASCII()
@@ -3726,7 +3880,7 @@ void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
         }
         else
         {
-            MP4_Box_Function[i_index].MP4_FreeBox_function( p_box );
+            p_box->pf_free( p_box );
         }
         free( p_box->data.p_payload );
     }
@@ -3898,15 +4052,13 @@ static void MP4_BoxDumpStructure_Internal( stream_t *s,
                                     MP4_Box_t *p_box, unsigned int i_level )
 {
     MP4_Box_t *p_child;
+    uint32_t i_displayedtype = p_box->i_type;
+    if( ! MP4_BOX_TYPE_ASCII() ) ((char*)&i_displayedtype)[0] = 'c';
 
     if( !i_level )
     {
-        if MP4_BOX_TYPE_ASCII()
-            msg_Dbg( s, "dumping root Box \"%4.4s\"",
-                              (char*)&p_box->i_type );
-        else
-            msg_Dbg( s, "dumping root Box \"c%3.3s\"",
-                              (char*)&p_box->i_type+1 );
+        msg_Dbg( s, "dumping root Box \"%4.4s\"",
+                          (char*)&i_displayedtype );
     }
     else
     {
@@ -3919,16 +4071,12 @@ static void MP4_BoxDumpStructure_Internal( stream_t *s,
         {
             str[i*4] = '|';
         }
-        if( MP4_BOX_TYPE_ASCII() )
-            snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
-                      "+ %4.4s size %"PRIu64" offset %ld%s",
-                        (char*)&p_box->i_type, p_box->i_size, p_box->i_pos,
-                    p_box->e_flags & BOX_FLAG_INCOMPLETE ? " (\?\?\?\?)" : "" );
-        else
-            snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
-                      "+ c%3.3s size %"PRIu64" offset %ld%s",
-                        (char*)&p_box->i_type+1, p_box->i_size, p_box->i_pos,
-                    p_box->e_flags & BOX_FLAG_INCOMPLETE ? " (\?\?\?\?)" : "" );
+
+        snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
+                  "+ %4.4s size %"PRIu64" offset %ju%s",
+                    (char*)&i_displayedtype, p_box->i_size,
+                  (uintmax_t)p_box->i_pos,
+                p_box->e_flags & BOX_FLAG_INCOMPLETE ? " (\?\?\?\?)" : "" );
         msg_Dbg( s, "%s", str );
     }
     p_child = p_box->p_first;