]> 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 0dd92c350db5677f1c7c09d198a8c4021788f21c..f0c4433e108d59cc77062aef120933d3522941b9 100644 (file)
@@ -1,23 +1,23 @@
 /*****************************************************************************
  * libmp4.c : LibMP4 library for mp4 module for vlc
  *****************************************************************************
- * Copyright (C) 2001-2004, 2010 the VideoLAN team
+ * Copyright (C) 2001-2004, 2010 VLC authors and VideoLAN
  *
  * Author: Laurent Aimar <fenrir@via.ecp.fr>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -32,6 +32,7 @@
 #endif
 
 #include "libmp4.h"
+#include "languages.h"
 #include <math.h>
 
 /* Some assumptions:
@@ -47,7 +48,7 @@ static double conv_fx( int32_t fx ) {
 
 /* some functions for mp4 encoding of variables */
 #ifdef MP4_VERBOSE
-static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
+static void MP4_ConvertDate2Str( char *psz, uint64_t i_date, bool b_relative )
 {
     int i_day;
     int i_hour;
@@ -55,7 +56,8 @@ static void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
     int i_sec;
 
     /* date begin at 1 jan 1904 */
-    i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
+    if ( !b_relative )
+        i_date += ((INT64_C(1904) * 365) + 17) * 24 * 60 * 60;
 
     i_day = i_date / ( 60*60*24);
     i_hour = ( i_date /( 60*60 ) ) % 60;
@@ -90,7 +92,7 @@ int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
     }
     p_box->i_pos = stream_Tell( p_stream );
 
-    p_box->data.p_data = NULL;
+    p_box->data.p_payload = NULL;
     p_box->p_father = NULL;
     p_box->p_first  = NULL;
     p_box->p_last  = NULL;
@@ -122,12 +124,12 @@ int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box )
     {
         CreateUUID( &p_box->i_uuid, p_box->i_type );
     }
-#ifdef MP4_VERBOSE
+#ifdef MP4_ULTRA_VERBOSE
     if( p_box->i_size )
     {
         if MP4_BOX_TYPE_ASCII()
-            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64,
-                    (char*)&p_box->i_type, p_box->i_size );
+            msg_Dbg( p_stream, "found Box: %4.4s size %"PRId64" %"PRId64,
+                    (char*)&p_box->i_type, p_box->i_size, p_box->i_pos );
         else
             msg_Dbg( p_stream, "found Box: c%3.3s size %"PRId64,
                     (char*)&p_box->i_type+1, p_box->i_size );
@@ -189,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
  *****************************************************************************/
-static 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) )
       )
     {
@@ -207,7 +209,16 @@ static 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;
@@ -215,13 +226,23 @@ static int MP4_ReadBoxContainerChildren( stream_t *p_stream,
         p_container->p_last = p_box;
 
         if( p_box->i_type == i_last_child )
+        {
+            MP4_NextBox( p_stream, p_box );
             break;
+        }
 
     } while( MP4_NextBox( p_stream, p_box ) == 1 );
 
     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 );
@@ -280,7 +301,7 @@ static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box )
     }
 
     /* Nothing to do */
-#ifdef MP4_VERBOSE
+#ifdef MP4_ULTRA_VERBOSE
     if MP4_BOX_TYPE_ASCII()
         msg_Dbg( p_stream, "skip box: \"%4.4s\"", (char*)&p_box->i_type );
     else
@@ -289,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 );
@@ -371,13 +427,13 @@ static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
 
 
 #ifdef MP4_VERBOSE
-    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time, false );
     MP4_ConvertDate2Str( s_modification_time,
-                         p_box->data.p_mvhd->i_modification_time );
+                         p_box->data.p_mvhd->i_modification_time, false );
     if( p_box->data.p_mvhd->i_rate )
     {
         MP4_ConvertDate2Str( s_duration,
-                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate );
+                 p_box->data.p_mvhd->i_duration / p_box->data.p_mvhd->i_rate, true );
     }
     else
     {
@@ -500,6 +556,7 @@ static int MP4_ReadBox_stra( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_Box_data_stra_t *p_stra = p_box->data.p_stra;
 
     uint8_t i_reserved;
+    VLC_UNUSED(i_reserved);
     MP4_GET1BYTE( p_stra->i_es_cat );
     MP4_GET1BYTE( i_reserved );
     MP4_GET2BYTES( p_stra->i_track_ID );
@@ -592,6 +649,7 @@ static int MP4_ReadBox_sidx(  stream_t *p_stream, MP4_Box_t *p_box )
     }
 
     uint16_t i_reserved;
+    VLC_UNUSED(i_reserved);
     MP4_GET2BYTES( i_reserved );
     MP4_GET2BYTES( p_sidx_data->i_reference_count );
     uint16_t i_count = p_sidx_data->i_reference_count;
@@ -798,7 +856,7 @@ static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
     double scale[2];    // scale factor; sx = scale[0] , sy = scale[1]
     double translate[2];// amount to translate; tx = translate[0] , ty = translate[1]
 
-    int *matrix = p_box->data.p_tkhd->i_matrix;
+    int32_t *matrix = p_box->data.p_tkhd->i_matrix;
 
     translate[0] = conv_fx(matrix[6]);
     translate[1] = conv_fx(matrix[7]);
@@ -816,9 +874,9 @@ static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
     p_box->data.p_tkhd->f_rotation = rotation;
 
 #ifdef MP4_VERBOSE
-    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time );
-    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time );
-    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration );
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mvhd->i_creation_time, false );
+    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mvhd->i_modification_time, false );
+    MP4_ConvertDate2Str( s_duration, p_box->data.p_mvhd->i_duration, true );
 
     msg_Dbg( p_stream, "read box: \"tkhd\" creation %s modification %s duration %s track ID %d layer %d volume %f rotation %f scaleX %f scaleY %f translateX %f translateY %f width %f height %f. "
             "Matrix: %i %i %i %i %i %i %i %i %i",
@@ -833,8 +891,8 @@ static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
                   scale[1],
                   translate[0],
                   translate[1],
-                  (float)p_box->data.p_tkhd->i_width / 65536,
-                  (float)p_box->data.p_tkhd->i_height / 65536,
+                  (float)p_box->data.p_tkhd->i_width / BLOCK16x16,
+                  (float)p_box->data.p_tkhd->i_height / BLOCK16x16,
                   p_box->data.p_tkhd->i_matrix[0],
                   p_box->data.p_tkhd->i_matrix[1],
                   p_box->data.p_tkhd->i_matrix[2],
@@ -875,27 +933,23 @@ static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_GET4BYTES( p_box->data.p_mdhd->i_timescale );
         MP4_GET4BYTES( p_box->data.p_mdhd->i_duration );
     }
-    p_box->data.p_mdhd->i_language_code = i_language = GetWBE( p_peek );
-    for( unsigned i = 0; i < 3; i++ )
-    {
-        p_box->data.p_mdhd->i_language[i] =
-                    ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
-    }
 
-    MP4_GET2BYTES( p_box->data.p_mdhd->i_predefined );
+    MP4_GET2BYTES( i_language );
+    decodeQtLanguageCode( i_language, p_box->data.p_mdhd->rgs_language,
+                          &p_box->data.p_mdhd->b_mac_encoding );
+
+    MP4_GET2BYTES( p_box->data.p_mdhd->i_quality );
 
 #ifdef MP4_VERBOSE
-    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time );
-    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time );
-    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration );
-    msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
+    MP4_ConvertDate2Str( s_creation_time, p_box->data.p_mdhd->i_creation_time, false );
+    MP4_ConvertDate2Str( s_modification_time, p_box->data.p_mdhd->i_modification_time, false );
+    MP4_ConvertDate2Str( s_duration, p_box->data.p_mdhd->i_duration, true );
+    msg_Dbg( p_stream, "read box: \"mdhd\" creation %s modification %s time scale %d duration %s language %3.3s",
                   s_creation_time,
                   s_modification_time,
                   (uint32_t)p_box->data.p_mdhd->i_timescale,
                   s_duration,
-                  p_box->data.p_mdhd->i_language[0],
-                  p_box->data.p_mdhd->i_language[1],
-                  p_box->data.p_mdhd->i_language[2] );
+                  (char*) &p_box->data.p_mdhd->rgs_language );
 #endif
     MP4_READBOX_EXIT( 1 );
 }
@@ -904,6 +958,7 @@ static int MP4_ReadBox_mdhd( stream_t *p_stream, MP4_Box_t *p_box )
 static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box )
 {
     int32_t i_reserved;
+    VLC_UNUSED(i_reserved);
 
     MP4_READBOX_ENTER( MP4_Box_data_hdlr_t );
 
@@ -1087,8 +1142,8 @@ static int MP4_ReadBox_dref( stream_t *p_stream, MP4_Box_t *p_box )
 
 static void MP4_FreeBox_stts( MP4_Box_t *p_box )
 {
-    FREENULL( p_box->data.p_stts->i_sample_count );
-    FREENULL( p_box->data.p_stts->i_sample_delta );
+    FREENULL( p_box->data.p_stts->pi_sample_count );
+    FREENULL( p_box->data.p_stts->pi_sample_delta );
 }
 
 static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
@@ -1098,22 +1153,26 @@ static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GETVERSIONFLAGS( p_box->data.p_stts );
     MP4_GET4BYTES( p_box->data.p_stts->i_entry_count );
 
-    p_box->data.p_stts->i_sample_count =
-        calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
-    p_box->data.p_stts->i_sample_delta =
+    p_box->data.p_stts->pi_sample_count =
         calloc( p_box->data.p_stts->i_entry_count, sizeof(uint32_t) );
-    if( p_box->data.p_stts->i_sample_count == NULL
-     || p_box->data.p_stts->i_sample_delta == NULL )
+    p_box->data.p_stts->pi_sample_delta =
+        calloc( p_box->data.p_stts->i_entry_count, sizeof(int32_t) );
+    if( p_box->data.p_stts->pi_sample_count == NULL
+     || p_box->data.p_stts->pi_sample_delta == NULL )
     {
         MP4_READBOX_EXIT( 0 );
     }
 
-    for( unsigned int i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
+    uint32_t i = 0;
+    for( ; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
     {
-        MP4_GET4BYTES( p_box->data.p_stts->i_sample_count[i] );
-        MP4_GET4BYTES( p_box->data.p_stts->i_sample_delta[i] );
+        MP4_GET4BYTES( p_box->data.p_stts->pi_sample_count[i] );
+        MP4_GET4BYTES( p_box->data.p_stts->pi_sample_delta[i] );
     }
 
+    if ( i < p_box->data.p_stts->i_entry_count )
+        p_box->data.p_stts->i_entry_count = i;
+
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"stts\" entry-count %d",
                       p_box->data.p_stts->i_entry_count );
@@ -1125,8 +1184,8 @@ static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box )
 
 static void MP4_FreeBox_ctts( MP4_Box_t *p_box )
 {
-    FREENULL( p_box->data.p_ctts->i_sample_count );
-    FREENULL( p_box->data.p_ctts->i_sample_offset );
+    FREENULL( p_box->data.p_ctts->pi_sample_count );
+    FREENULL( p_box->data.p_ctts->pi_sample_offset );
 }
 
 static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
@@ -1137,21 +1196,24 @@ static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box )
 
     MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
 
-    p_box->data.p_ctts->i_sample_count =
-        calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
-    p_box->data.p_ctts->i_sample_offset =
+    p_box->data.p_ctts->pi_sample_count =
         calloc( p_box->data.p_ctts->i_entry_count, sizeof(uint32_t) );
-    if( ( p_box->data.p_ctts->i_sample_count == NULL )
-     || ( p_box->data.p_ctts->i_sample_offset == NULL ) )
+    p_box->data.p_ctts->pi_sample_offset =
+        calloc( p_box->data.p_ctts->i_entry_count, sizeof(int32_t) );
+    if( ( p_box->data.p_ctts->pi_sample_count == NULL )
+     || ( p_box->data.p_ctts->pi_sample_offset == NULL ) )
     {
         MP4_READBOX_EXIT( 0 );
     }
 
-    for( unsigned int i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
+    uint32_t i = 0;
+    for( ; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
     {
-        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_count[i] );
-        MP4_GET4BYTES( p_box->data.p_ctts->i_sample_offset[i] );
+        MP4_GET4BYTES( p_box->data.p_ctts->pi_sample_count[i] );
+        MP4_GET4BYTES( p_box->data.p_ctts->pi_sample_offset[i] );
     }
+    if ( i < p_box->data.p_ctts->i_entry_count )
+        p_box->data.p_ctts->i_entry_count = i;
 
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"ctts\" entry-count %d",
@@ -1201,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 );
 
@@ -1226,6 +1288,7 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
             unsigned int i_len;
 
             MP4_GET1BYTE( i_len );
+            i_len = __MIN(i_read, i_len);
             es_descriptor.psz_URL = malloc( i_len + 1 );
             if( es_descriptor.psz_URL )
             {
@@ -1246,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 */
@@ -1264,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;
@@ -1272,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;
@@ -1300,6 +1363,29 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box )
 #undef es_descriptor
 }
 
+static void MP4_FreeBox_hvcC(MP4_Box_t *p_box )
+{
+    MP4_Box_data_hvcC_t *p_hvcC =  p_box->data.p_hvcC;
+    if( p_hvcC->i_hvcC > 0 ) FREENULL( p_hvcC->p_hvcC) ;
+}
+
+static int MP4_ReadBox_hvcC( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_data_hvcC_t *p_hvcC;
+
+    MP4_READBOX_ENTER( MP4_Box_data_hvcC_t );
+    p_hvcC = p_box->data.p_hvcC;
+
+    p_hvcC->i_hvcC = i_read;
+    if( p_hvcC->i_hvcC > 0 )
+    {
+        uint8_t * p = p_hvcC->p_hvcC = malloc( p_hvcC->i_hvcC );
+        if( p )
+            memcpy( p, p_peek, i_read );
+    }
+    MP4_READBOX_EXIT( 1 );
+}
+
 static void MP4_FreeBox_avcC( MP4_Box_t *p_box )
 {
     MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC;
@@ -1359,9 +1445,11 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
         if( !p_avcC->i_sps_length || !p_avcC->sps )
             goto error;
 
-        for( i = 0; i < p_avcC->i_sps; i++ )
+        for( i = 0; i < p_avcC->i_sps && i_read > 2; i++ )
         {
             MP4_GET2BYTES( p_avcC->i_sps_length[i] );
+            if ( p_avcC->i_sps_length[i] > i_read )
+                goto error;
             p_avcC->sps[i] = malloc( p_avcC->i_sps_length[i] );
             if( p_avcC->sps[i] )
                 memcpy( p_avcC->sps[i], p_peek, p_avcC->i_sps_length[i] );
@@ -1369,6 +1457,8 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
             p_peek += p_avcC->i_sps_length[i];
             i_read -= p_avcC->i_sps_length[i];
         }
+        if ( i != p_avcC->i_sps )
+            goto error;
     }
 
     MP4_GET1BYTE( p_avcC->i_pps );
@@ -1380,9 +1470,11 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
         if( !p_avcC->i_pps_length || !p_avcC->pps )
             goto error;
 
-        for( i = 0; i < p_avcC->i_pps; i++ )
+        for( i = 0; i < p_avcC->i_pps && i_read > 2; i++ )
         {
             MP4_GET2BYTES( p_avcC->i_pps_length[i] );
+            if( p_avcC->i_pps_length[i] > i_read )
+                goto error;
             p_avcC->pps[i] = malloc( p_avcC->i_pps_length[i] );
             if( p_avcC->pps[i] )
                 memcpy( p_avcC->pps[i], p_peek, p_avcC->i_pps_length[i] );
@@ -1390,6 +1482,8 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
             p_peek += p_avcC->i_pps_length[i];
             i_read -= p_avcC->i_pps_length[i];
         }
+        if ( i != p_avcC->i_pps )
+            goto error;
     }
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream,
@@ -1412,9 +1506,199 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_READBOX_EXIT( 1 );
 
 error:
+    MP4_FreeBox_avcC( p_box );
     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 );
+    MP4_Box_data_chan_t *p_chan = p_box->data.p_chan;
+
+    if ( i_read < 16 )
+        MP4_READBOX_EXIT( 0 );
+
+    MP4_GET1BYTE( p_chan->i_version );
+    MP4_GET3BYTES( p_chan->i_channels_flags );
+    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 );
+
+    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 * i_descsize );
+
+    if ( !p_chan->layout.p_descriptions )
+        MP4_READBOX_EXIT( 0 );
+
+    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,
+             "read box: \"chan\" flags=0x%x tag=0x%x bitmap=0x%x descriptions=%u",
+             p_chan->i_channels_flags, p_chan->layout.i_channels_layout_tag,
+             p_chan->layout.i_channels_bitmap, p_chan->layout.i_channels_description_count );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_stsdext_chan( MP4_Box_t *p_box )
+{
+    MP4_Box_data_chan_t *p_chan = p_box->data.p_chan;
+    free( p_chan->layout.p_descriptions );
+}
+
+static int MP4_ReadBox_dec3( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_dec3_t );
+
+    MP4_Box_data_dec3_t *p_dec3 = p_box->data.p_dec3;
+
+    unsigned i_header;
+    MP4_GET2BYTES( i_header );
+
+    p_dec3->i_data_rate = i_header >> 3;
+    p_dec3->i_num_ind_sub = (i_header & 0x7) + 1;
+    for (uint8_t i = 0; i < p_dec3->i_num_ind_sub; i++) {
+        MP4_GET3BYTES( i_header );
+        p_dec3->stream[i].i_fscod = ( i_header >> 22 ) & 0x03;
+        p_dec3->stream[i].i_bsid  = ( i_header >> 17 ) & 0x01f;
+        p_dec3->stream[i].i_bsmod = ( i_header >> 12 ) & 0x01f;
+        p_dec3->stream[i].i_acmod = ( i_header >> 9 ) & 0x07;
+        p_dec3->stream[i].i_lfeon = ( i_header >> 8 ) & 0x01;
+        p_dec3->stream[i].i_num_dep_sub = (i_header >> 1) & 0x0f;
+        if (p_dec3->stream[i].i_num_dep_sub) {
+            MP4_GET1BYTE( p_dec3->stream[i].i_chan_loc );
+            p_dec3->stream[i].i_chan_loc |= (i_header & 1) << 8;
+        } else
+            p_dec3->stream[i].i_chan_loc = 0;
+    }
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream,
+        "read box: \"dec3\" bitrate %dkbps %d independant substreams",
+            p_dec3->i_data_rate, p_dec3->i_num_ind_sub);
+
+    for (uint8_t i = 0; i < p_dec3->i_num_ind_sub; i++)
+        msg_Dbg( p_stream,
+                "\tstream %d: bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x "
+                "num dependant subs=%d chan_loc=0x%x",
+                i, p_dec3->stream[i].i_bsid, p_dec3->stream[i].i_bsmod, p_dec3->stream[i].i_acmod,
+                p_dec3->stream[i].i_lfeon, p_dec3->stream[i].i_num_dep_sub, p_dec3->stream[i].i_chan_loc );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
 static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_Box_data_dac3_t *p_dac3;
@@ -1490,73 +1774,9 @@ 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;
-    uint32_t 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;
-    uint32_t 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;
     MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
     p_box->data.p_sample_soun->p_qt_description = NULL;
 
@@ -1596,7 +1816,7 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
 
     MP4_GET2BYTES( p_box->data.p_sample_soun->i_channelcount );
     MP4_GET2BYTES( p_box->data.p_sample_soun->i_samplesize );
-    MP4_GET2BYTES( p_box->data.p_sample_soun->i_predefined );
+    MP4_GET2BYTES( p_box->data.p_sample_soun->i_compressionid );
     MP4_GET2BYTES( p_box->data.p_sample_soun->i_reserved3 );
     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratehi );
     MP4_GET2BYTES( p_box->data.p_sample_soun->i_sampleratelo );
@@ -1625,25 +1845,57 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
     {
         /* SoundDescriptionV2 */
         double f_sample_rate;
-        int64_t dummy;
-        uint32_t i_channel;
-
-        MP4_GET4BYTES( p_box->data.p_sample_soun->i_sample_per_packet );
-        MP4_GET8BYTES( dummy );
-        memcpy( &f_sample_rate, &dummy, 8 );
+        int64_t i_dummy64;
+        uint32_t i_channel, i_extoffset, i_dummy32;
+
+        /* Checks */
+        if ( p_box->data.p_sample_soun->i_channelcount != 0x3  ||
+             p_box->data.p_sample_soun->i_samplesize != 0x0010 ||
+             p_box->data.p_sample_soun->i_compressionid != 0xFFFE ||
+             p_box->data.p_sample_soun->i_reserved3 != 0x0     ||
+             p_box->data.p_sample_soun->i_sampleratehi != 0x1  ||//65536
+             p_box->data.p_sample_soun->i_sampleratelo != 0x0 )  //remainder
+        {
+            msg_Err( p_stream, "invalid stsd V2 box defaults" );
+            MP4_READBOX_EXIT( 0 );
+        }
+        /* !Checks */
 
+        MP4_GET4BYTES( i_extoffset ); /* offset to stsd extentions */
+        MP4_GET8BYTES( i_dummy64 );
+        memcpy( &f_sample_rate, &i_dummy64, 8 );
         msg_Dbg( p_stream, "read box: %f Hz", f_sample_rate );
-        p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % 65536;
-        p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / 65536;
+        p_box->data.p_sample_soun->i_sampleratehi = (int)f_sample_rate % BLOCK16x16;
+        p_box->data.p_sample_soun->i_sampleratelo = f_sample_rate / BLOCK16x16;
 
         MP4_GET4BYTES( i_channel );
         p_box->data.p_sample_soun->i_channelcount = i_channel;
 
+        MP4_GET4BYTES( i_dummy32 );
+        if ( i_dummy32 != 0x7F000000 )
+        {
+            msg_Err( p_stream, "invalid stsd V2 box" );
+            MP4_READBOX_EXIT( 0 );
+        }
+
+        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constbitsperchannel );
+        MP4_GET4BYTES( p_box->data.p_sample_soun->i_formatflags );
+        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constbytesperaudiopacket );
+        MP4_GET4BYTES( p_box->data.p_sample_soun->i_constLPCMframesperaudiopacket );
+
 #ifdef MP4_VERBOSE
-        msg_Dbg( p_stream, "read box: \"soun\" V2" );
+        msg_Dbg( p_stream, "read box: \"soun\" V2 rate=%f bitsperchannel=%u "
+                           "flags=%u bytesperpacket=%u lpcmframesperpacket=%u",
+                 f_sample_rate,
+                 p_box->data.p_sample_soun->i_constbitsperchannel,
+                 p_box->data.p_sample_soun->i_formatflags,
+                 p_box->data.p_sample_soun->i_constbytesperaudiopacket,
+                 p_box->data.p_sample_soun->i_constLPCMframesperaudiopacket );
 #endif
-        stream_Seek( p_stream, p_box->i_pos +
-                        mp4_box_headersize( p_box ) + 28 + 36 );
+        if ( i_extoffset < p_box->i_size )
+            stream_Seek( p_stream, p_box->i_pos + i_extoffset );
+        else
+            stream_Seek( p_stream, p_box->i_pos + p_box->i_size );
     }
     else
     {
@@ -1672,6 +1924,7 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
         p_box->data.p_sample_soun->i_channelcount = 1;
     }
 
+    /* Loads extensions */
     MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds/wave/... */
 
 #ifdef MP4_VERBOSE
@@ -1680,7 +1933,7 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
              p_box->data.p_sample_soun->i_channelcount,
              p_box->data.p_sample_soun->i_samplesize,
              (float)p_box->data.p_sample_soun->i_sampleratehi +
-             (float)p_box->data.p_sample_soun->i_sampleratelo / 65536 );
+             (float)p_box->data.p_sample_soun->i_sampleratelo / BLOCK16x16 );
 
 #endif
     MP4_READBOX_EXIT( 1 );
@@ -1695,6 +1948,7 @@ static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
 
 int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
 {
+    p_box->i_handler = ATOM_vide;
     MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
 
     for( unsigned i = 0; i < 6 ; i++ )
@@ -1738,6 +1992,8 @@ int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
 
+    if ( i_read < 32 )
+        MP4_READBOX_EXIT( 0 );
     memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
     p_peek += 32; i_read -= 32;
 
@@ -1781,6 +2037,7 @@ static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
 {
     int32_t t;
 
+    p_box->i_handler = ATOM_text;
     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
 
     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
@@ -1816,7 +2073,7 @@ static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[0] );
     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[1] );
     MP4_GET2BYTES( p_box->data.p_sample_text->i_background_color[2] );
-    p_box->data.p_sample_text->i_background_color[3] = 0;
+    p_box->data.p_sample_text->i_background_color[3] = 0xFF;
 
     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_top );
     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_left );
@@ -1831,6 +2088,7 @@ static int MP4_ReadBox_sample_text( stream_t *p_stream, MP4_Box_t *p_box )
 
 static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
 {
+    p_box->i_handler = ATOM_text;
     MP4_READBOX_ENTER( MP4_Box_data_sample_text_t );
 
     MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved1 );
@@ -1853,6 +2111,13 @@ static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_bottom );
     MP4_GET2BYTES( p_box->data.p_sample_text->i_text_box_right );
 
+    MP4_GET4BYTES( p_box->data.p_sample_text->i_reserved3 );
+
+    MP4_GET2BYTES( p_box->data.p_sample_text->i_font_id );
+    MP4_GET1BYTE ( p_box->data.p_sample_text->i_font_face );
+    MP4_GET1BYTE ( p_box->data.p_sample_text->i_font_size );
+    MP4_GET4BYTES( p_box->data.p_sample_text->i_font_color );
+
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"tx3g\" in stsd text" );
 #endif
@@ -2031,13 +2296,16 @@ static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box )
     if( unlikely( p_box->data.p_stss->i_sample_number == NULL ) )
         MP4_READBOX_EXIT( 0 );
 
-    for( unsigned int i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
+    unsigned int i;
+    for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 4 ); i++ )
     {
 
         MP4_GET4BYTES( p_box->data.p_stss->i_sample_number[i] );
         /* XXX in libmp4 sample begin at 0 */
         p_box->data.p_stss->i_sample_number[i]--;
     }
+    if ( i < p_box->data.p_stss->i_entry_count )
+        p_box->data.p_stss->i_entry_count = i;
 
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"stss\" entry-count %d",
@@ -2078,11 +2346,14 @@ static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_READBOX_EXIT( 0 );
     }
 
-    for( unsigned i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
+    unsigned i;
+    for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
     {
         MP4_GET4BYTES( p_box->data.p_stsh->i_shadowed_sample_number[i] );
         MP4_GET4BYTES( p_box->data.p_stsh->i_sync_sample_number[i] );
     }
+    if ( i < p_box->data.p_stss->i_entry_count )
+        p_box->data.p_stss->i_entry_count = i;
 
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"stsh\" entry-count %d",
@@ -2195,7 +2466,7 @@ static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
     p_box->data.p_elst->i_segment_duration =
         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
     p_box->data.p_elst->i_media_time =
-        calloc( p_box->data.p_elst->i_entry_count, sizeof(uint64_t) );
+        calloc( p_box->data.p_elst->i_entry_count, sizeof(int64_t) );
     p_box->data.p_elst->i_media_rate_integer =
         calloc( p_box->data.p_elst->i_entry_count, sizeof(uint16_t) );
     p_box->data.p_elst->i_media_rate_fraction =
@@ -2208,19 +2479,21 @@ static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_READBOX_EXIT( 0 );
     }
 
-
-    for( unsigned i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
+    unsigned i;
+    for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
     {
         if( p_box->data.p_elst->i_version == 1 )
         {
-
+            if ( i_read < 20 )
+                break;
             MP4_GET8BYTES( p_box->data.p_elst->i_segment_duration[i] );
 
             MP4_GET8BYTES( p_box->data.p_elst->i_media_time[i] );
         }
         else
         {
-
+            if ( i_read < 12 )
+                break;
             MP4_GET4BYTES( p_box->data.p_elst->i_segment_duration[i] );
 
             MP4_GET4BYTES( p_box->data.p_elst->i_media_time[i] );
@@ -2230,7 +2503,8 @@ static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_integer[i] );
         MP4_GET2BYTES( p_box->data.p_elst->i_media_rate_fraction[i] );
     }
-
+    if ( i < p_box->data.p_elst->i_entry_count )
+        p_box->data.p_elst->i_entry_count = i;
 #ifdef MP4_VERBOSE
     msg_Dbg( p_stream, "read box: \"elst\" entry-count %lu",
              (unsigned long)p_box->data.p_elst->i_entry_count );
@@ -2240,26 +2514,21 @@ static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box )
 
 static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box )
 {
-    unsigned int i_language;
+    uint16_t i_language;
+    bool b_mac;
 
     MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
 
     MP4_GETVERSIONFLAGS( p_box->data.p_cprt );
 
-    i_language = GetWBE( p_peek );
-    for( unsigned i = 0; i < 3; i++ )
-    {
-        p_box->data.p_cprt->i_language[i] =
-            ( ( i_language >> ( (2-i)*5 ) )&0x1f ) + 0x60;
-    }
-    p_peek += 2; i_read -= 2;
+    MP4_GET2BYTES( i_language );
+    decodeQtLanguageCode( i_language, p_box->data.p_cprt->rgs_language, &b_mac );
+
     MP4_GETSTRINGZ( p_box->data.p_cprt->psz_notice );
 
 #ifdef MP4_VERBOSE
-    msg_Dbg( p_stream, "read box: \"cprt\" language %c%c%c notice %s",
-                      p_box->data.p_cprt->i_language[0],
-                      p_box->data.p_cprt->i_language[1],
-                      p_box->data.p_cprt->i_language[2],
+    msg_Dbg( p_stream, "read box: \"cprt\" language %3.3s notice %s",
+                      p_box->data.p_cprt->rgs_language,
                       p_box->data.p_cprt->psz_notice );
 
 #endif
@@ -2566,111 +2835,126 @@ 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_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box )
+static int MP4_ReadBox_data( stream_t *p_stream, MP4_Box_t *p_box )
 {
-    uint16_t i16;
-
-    MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t );
+    MP4_READBOX_ENTER( MP4_Box_data_data_t );
+    MP4_Box_data_data_t *p_data = p_box->data.p_data;
 
-    p_box->data.p_0xa9xxx->psz_text = NULL;
-
-    MP4_GET2BYTES( i16 );
+    if ( i_read < 8 || i_read - 8 > UINT32_MAX )
+        MP4_READBOX_EXIT( 0 );
 
-    if( i16 > 0 )
+    uint8_t i_type;
+    MP4_GET1BYTE( i_type );
+    if ( i_type != 0 )
     {
-        int i_length = i16;
-
-        MP4_GET2BYTES( i16 );
-        if( i_length >= i_read ) i_length = i_read + 1;
-
-        p_box->data.p_0xa9xxx->psz_text = malloc( i_length );
-        if( p_box->data.p_0xa9xxx->psz_text == NULL )
-            MP4_READBOX_EXIT( 0 );
-
-        i_length--;
-        memcpy( p_box->data.p_0xa9xxx->psz_text,
-                p_peek, i_length );
-        p_box->data.p_0xa9xxx->psz_text[i_length] = '\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 );
+        msg_Dbg( p_stream, "skipping unknown 'data' atom with type %"PRIu8, i_type );
 #endif
+        MP4_READBOX_EXIT( 0 );
     }
-    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;
-
-        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;
-            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';
+    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 box: \"c%3.3s\" text=`%s'",
-                 ((char*)&p_box->i_type+1),
-                 p_box->data.p_0xa9xxx->psz_text );
+        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
-            }
-            else
-            {
-                // TODO: handle data values for ID3 tag values, track num or cover art,etc...
-            }
-        }
-    }
+    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;
+    memcpy( p_box->data.p_data->p_blob, p_peek, i_read);
 
     MP4_READBOX_EXIT( 1 );
 }
+
+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 )
+{
+    return MP4_ReadBox_Metadata( p_stream, p_box );
+
+/* FIXME: find out what was that 2 bytes sized atom and its own handler */
+//    if ( GetWBE( &p_peek[8] ) > 0 )
+//        uint16_t i16;
+
+//    MP4_READBOX_ENTER( MP4_Box_data_string_t );
+
+//    p_box->data.p_string->psz_text = NULL;
+
+//    MP4_GET2BYTES( i16 );
+
+//    if( i16 > 0 )
+//    {
+//        int i_length = i16;
+
+//        MP4_GET2BYTES( i16 );
+//        if( i_length >= i_read ) i_length = i_read + 1;
+
+//        p_box->data.p_string->psz_text = malloc( i_length );
+//        if( p_box->data.p_string->psz_text == NULL )
+//            MP4_READBOX_EXIT( 0 );
+
+//        i_length--;
+//        memcpy( p_box->data.p_string->psz_text,
+//                p_peek, i_length );
+//        p_box->data.p_string->psz_text[i_length] = '\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_string->psz_text );
+//#endif
+//    }
+//    else
+
+//    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 */
@@ -2685,6 +2969,7 @@ static int MP4_ReadBox_chpl( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_Box_data_chpl_t *p_chpl;
     uint32_t i_dummy;
+    VLC_UNUSED(i_dummy);
     int i;
     MP4_READBOX_ENTER( MP4_Box_data_chpl_t );
 
@@ -2701,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 );
 
@@ -2717,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
     {
@@ -2773,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];
@@ -2783,9 +3128,23 @@ static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
     if( i_actually_read < 8 )
         return 0;
 
-    /* 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 ( p_box->p_father && p_box->p_father->i_type == 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 || memcmp( meta_data, "\0\0\0", 4 ) )
+            return 0;
+    }
+
+    if ( !MP4_ReadBoxContainerChildren( p_stream, p_box, 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;
 
     /* then it behaves like a container */
@@ -2795,6 +3154,7 @@ static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
 static int MP4_ReadBox_iods( stream_t *p_stream, MP4_Box_t *p_box )
 {
     char i_unused;
+    VLC_UNUSED(i_unused);
 
     MP4_READBOX_ENTER( MP4_Box_data_iods_t );
     MP4_GETVERSIONFLAGS( p_box->data.p_iods );
@@ -2898,8 +3258,9 @@ static int MP4_ReadBox_sdtp( stream_t *p_stream, MP4_Box_t *p_box )
         MP4_GET1BYTE( p_sdtp->p_sample_table[i] );
 
 #ifdef MP4_VERBOSE
-    msg_Info( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
-    msg_Dbg( p_stream,
+    msg_Dbg( p_stream, "i_sample_count is %"PRIu32"", i_sample_count );
+    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],
@@ -2962,15 +3323,25 @@ static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
                         || !p_tfra->p_trun_number || !p_tfra->p_sample_number )
         goto error;
 
-    for( uint32_t i = 0; i < i_number_of_entries; i++ )
+    int i_fields_length = 3 + p_tfra->i_length_size_of_traf_num
+            + p_tfra->i_length_size_of_trun_num
+            + p_tfra->i_length_size_of_sample_num;
+
+    uint32_t i;
+    for( i = 0; i < i_number_of_entries; i++ )
     {
+
         if( p_tfra->i_version == 1 )
         {
+            if ( i_read < i_fields_length + 16 )
+                break;
             MP4_GET8BYTES( p_tfra->p_time[i*2] );
             MP4_GET8BYTES( p_tfra->p_moof_offset[i*2] );
         }
         else
         {
+            if ( i_read < i_fields_length + 8 )
+                break;
             MP4_GET4BYTES( p_tfra->p_time[i] );
             MP4_GET4BYTES( p_tfra->p_moof_offset[i] );
         }
@@ -3028,6 +3399,8 @@ static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
                 goto error;
         }
     }
+    if ( i < i_number_of_entries )
+        i_number_of_entries = i;
 
 #ifdef MP4_VERBOSE
     if( p_tfra->i_version == 0 )
@@ -3049,8 +3422,8 @@ static int MP4_ReadBox_tfra( stream_t *p_stream, MP4_Box_t *p_box )
                 ((uint64_t *)(p_tfra->p_moof_offset))[1] );
     }
 
-    msg_Info( p_stream, "number_of_entries is %"PRIu32"", i_number_of_entries );
-    msg_Info( p_stream, "track ID is: %"PRIu32"", p_tfra->i_track_ID );
+    msg_Dbg( p_stream, "number_of_entries is %"PRIu32"", i_number_of_entries );
+    msg_Dbg( p_stream, "track ID is: %"PRIu32"", p_tfra->i_track_ID );
 #endif
 
     MP4_READBOX_EXIT( 1 );
@@ -3112,6 +3485,7 @@ unknown:
         msg_Warn( p_stream,
                 "unknown box type c%3.3s (incompletely loaded)",
                 (char*)&p_box->i_type+1 );
+    p_box->e_flags |= BOX_FLAG_INCOMPLETE;
 
     return 1;
 }
@@ -3125,240 +3499,295 @@ static const struct
     uint32_t i_type;
     int  (*MP4_ReadBox_function )( stream_t *p_stream, MP4_Box_t *p_box );
     void (*MP4_FreeBox_function )( MP4_Box_t *p_box );
+    uint32_t i_parent; /* set parent to restrict, duplicating if needed; 0 for any */
 } MP4_Box_Function [] =
 {
     /* Containers */
-    { ATOM_moov,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_trak,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_mdia,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_moof,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_minf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_stbl,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_dinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_edts,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_udta,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_nmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_hnti,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_rmra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_rmda,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_tref,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_gmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_wave,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_ilst,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_mvex,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
+    { ATOM_moov,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_foov,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_trak,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_moov },
+    { ATOM_trak,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_foov },
+    { ATOM_mdia,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_trak },
+    { ATOM_moof,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_minf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_mdia },
+    { ATOM_stbl,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_dinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_dinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_meta },
+    { ATOM_edts,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_trak },
+    { ATOM_udta,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_nmhd,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_hnti,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_udta },
+    { ATOM_rmra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_moov },
+    { ATOM_rmda,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, ATOM_rmra },
+    { 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_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 },
 
     /* specific box */
-    { ATOM_ftyp,    MP4_ReadBox_ftyp,         MP4_FreeBox_ftyp },
-    { ATOM_cmov,    MP4_ReadBox_cmov,         MP4_FreeBox_Common },
-    { ATOM_mvhd,    MP4_ReadBox_mvhd,         MP4_FreeBox_Common },
-    { ATOM_tkhd,    MP4_ReadBox_tkhd,         MP4_FreeBox_Common },
-    { ATOM_mdhd,    MP4_ReadBox_mdhd,         MP4_FreeBox_Common },
-    { ATOM_hdlr,    MP4_ReadBox_hdlr,         MP4_FreeBox_hdlr },
-    { ATOM_vmhd,    MP4_ReadBox_vmhd,         MP4_FreeBox_Common },
-    { ATOM_smhd,    MP4_ReadBox_smhd,         MP4_FreeBox_Common },
-    { ATOM_hmhd,    MP4_ReadBox_hmhd,         MP4_FreeBox_Common },
-    { ATOM_url,     MP4_ReadBox_url,          MP4_FreeBox_url },
-    { ATOM_urn,     MP4_ReadBox_urn,          MP4_FreeBox_urn },
-    { ATOM_dref,    MP4_ReadBox_dref,         MP4_FreeBox_Common },
-    { ATOM_stts,    MP4_ReadBox_stts,         MP4_FreeBox_stts },
-    { ATOM_ctts,    MP4_ReadBox_ctts,         MP4_FreeBox_ctts },
-    { ATOM_stsd,    MP4_ReadBox_stsd,         MP4_FreeBox_Common },
-    { ATOM_stsz,    MP4_ReadBox_stsz,         MP4_FreeBox_stsz },
-    { ATOM_stsc,    MP4_ReadBox_stsc,         MP4_FreeBox_stsc },
-    { ATOM_stco,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64 },
-    { ATOM_co64,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64 },
-    { ATOM_stss,    MP4_ReadBox_stss,         MP4_FreeBox_stss },
-    { ATOM_stsh,    MP4_ReadBox_stsh,         MP4_FreeBox_stsh },
-    { ATOM_stdp,    MP4_ReadBox_stdp,         MP4_FreeBox_stdp },
-    { ATOM_padb,    MP4_ReadBox_padb,         MP4_FreeBox_padb },
-    { ATOM_elst,    MP4_ReadBox_elst,         MP4_FreeBox_elst },
-    { ATOM_cprt,    MP4_ReadBox_cprt,         MP4_FreeBox_cprt },
-    { ATOM_esds,    MP4_ReadBox_esds,         MP4_FreeBox_esds },
-    { ATOM_dcom,    MP4_ReadBox_dcom,         MP4_FreeBox_Common },
-    { ATOM_cmvd,    MP4_ReadBox_cmvd,         MP4_FreeBox_cmvd },
-    { ATOM_avcC,    MP4_ReadBox_avcC,         MP4_FreeBox_avcC },
-    { ATOM_dac3,    MP4_ReadBox_dac3,         MP4_FreeBox_Common },
-    { ATOM_dvc1,    MP4_ReadBox_dvc1,         MP4_FreeBox_Common },
-    { ATOM_enda,    MP4_ReadBox_enda,         MP4_FreeBox_Common },
-    { ATOM_gnre,    MP4_ReadBox_gnre,         MP4_FreeBox_Common },
-    { ATOM_trkn,    MP4_ReadBox_trkn,         MP4_FreeBox_Common },
-    { ATOM_iods,    MP4_ReadBox_iods,         MP4_FreeBox_Common },
-    { ATOM_pasp,    MP4_ReadBox_pasp,         MP4_FreeBox_Common },
+    { ATOM_ftyp,    MP4_ReadBox_ftyp,         MP4_FreeBox_ftyp, 0 },
+    { ATOM_cmov,    MP4_ReadBox_cmov,         MP4_FreeBox_Common, 0 },
+    { ATOM_mvhd,    MP4_ReadBox_mvhd,         MP4_FreeBox_Common, ATOM_moov },
+    { ATOM_mvhd,    MP4_ReadBox_mvhd,         MP4_FreeBox_Common, ATOM_foov },
+    { ATOM_tkhd,    MP4_ReadBox_tkhd,         MP4_FreeBox_Common, ATOM_trak },
+    { ATOM_mdhd,    MP4_ReadBox_mdhd,         MP4_FreeBox_Common, ATOM_mdia },
+    { ATOM_hdlr,    MP4_ReadBox_hdlr,         MP4_FreeBox_hdlr,   ATOM_mdia },
+    { ATOM_hdlr,    MP4_ReadBox_hdlr,         MP4_FreeBox_hdlr,   ATOM_meta },
+    { ATOM_hdlr,    MP4_ReadBox_hdlr,         MP4_FreeBox_hdlr,   ATOM_minf },
+    { ATOM_vmhd,    MP4_ReadBox_vmhd,         MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_smhd,    MP4_ReadBox_smhd,         MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_hmhd,    MP4_ReadBox_hmhd,         MP4_FreeBox_Common, ATOM_minf },
+    { ATOM_alis,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, ATOM_dref },
+    { ATOM_url,     MP4_ReadBox_url,          MP4_FreeBox_url, 0 },
+    { ATOM_urn,     MP4_ReadBox_urn,          MP4_FreeBox_urn, 0 },
+    { ATOM_dref,    MP4_ReadBox_dref,         MP4_FreeBox_Common, 0 },
+    { ATOM_stts,    MP4_ReadBox_stts,         MP4_FreeBox_stts,   ATOM_stbl },
+    { ATOM_ctts,    MP4_ReadBox_ctts,         MP4_FreeBox_ctts,   ATOM_stbl },
+    { ATOM_stsd,    MP4_ReadBox_stsd,         MP4_FreeBox_Common, ATOM_stbl },
+    { ATOM_stsz,    MP4_ReadBox_stsz,         MP4_FreeBox_stsz,   ATOM_stbl },
+    { ATOM_stsc,    MP4_ReadBox_stsc,         MP4_FreeBox_stsc,   ATOM_stbl },
+    { ATOM_stco,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64, ATOM_stbl },
+    { ATOM_co64,    MP4_ReadBox_stco_co64,    MP4_FreeBox_stco_co64, ATOM_stbl },
+    { ATOM_stss,    MP4_ReadBox_stss,         MP4_FreeBox_stss, ATOM_stbl },
+    { ATOM_stsh,    MP4_ReadBox_stsh,         MP4_FreeBox_stsh, ATOM_stbl },
+    { ATOM_stdp,    MP4_ReadBox_stdp,         MP4_FreeBox_stdp, 0 },
+    { ATOM_padb,    MP4_ReadBox_padb,         MP4_FreeBox_padb, 0 },
+    { ATOM_elst,    MP4_ReadBox_elst,         MP4_FreeBox_elst, ATOM_edts },
+    { ATOM_cprt,    MP4_ReadBox_cprt,         MP4_FreeBox_cprt, 0 },
+    { 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 },
+    { ATOM_hvcC,    MP4_ReadBox_hvcC,         MP4_FreeBox_hvcC, 0 },
+    { ATOM_dac3,    MP4_ReadBox_dac3,         MP4_FreeBox_Common, 0 },
+    { ATOM_dec3,    MP4_ReadBox_dec3,         MP4_FreeBox_Common, 0 },
+    { ATOM_dvc1,    MP4_ReadBox_dvc1,         MP4_FreeBox_Common, 0 },
+    { 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 },
-    { ATOM_skip,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
-    { ATOM_free,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
-    { ATOM_wide,    MP4_ReadBoxSkip,          MP4_FreeBox_Common },
+    { ATOM_mdat,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
+    { ATOM_skip,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
+    { ATOM_free,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
+    { ATOM_wide,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
+    { ATOM_binm,    MP4_ReadBoxSkip,          MP4_FreeBox_Common, 0 },
+
+    /* Subtitles */
+    { ATOM_tx3g,    MP4_ReadBox_sample_tx3g,      MP4_FreeBox_Common, 0 },
+    //{ ATOM_text,    MP4_ReadBox_sample_text,      MP4_FreeBox_Common, 0 },
 
     /* for codecs */
-    { ATOM_soun,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_ms02,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_ms11,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_ms55,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM__mp3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_mp4a,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_twos,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_sowt,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_QDMC,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_QDM2,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_ima4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_IMA4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_dvi,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_alaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_ulaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_raw,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_MAC3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_MAC6,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_Qclp,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_samr,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_sawb,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_OggS,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_alac,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-
-    { ATOM_drmi,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_vide,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_mp4v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_SVQ1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_SVQ3,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_ZyGo,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_DIVX,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_XVID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_h263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_s263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_cvid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3IV1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3iv1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3IV2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3iv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3IVD,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3ivd,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3VID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_3vid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_mjpa,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_mjpb,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_qdrw,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_mp2v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_hdv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-
-    { ATOM_mjqt,    MP4_ReadBox_default,      NULL }, /* found in mjpa/b */
-    { ATOM_mjht,    MP4_ReadBox_default,      NULL },
-
-    { ATOM_dvc,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_dvp,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_dv5n,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_dv5p,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_VP31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_vp31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_h264,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-
-    { ATOM_jpeg,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_avc1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-
-    { ATOM_yv12,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-    { ATOM_yuv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide },
-
-    { ATOM_mp4s,    MP4_ReadBox_sample_mp4s,  MP4_FreeBox_Common },
+    { ATOM_soun,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ac3,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_eac3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_lpcm,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ms02,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ms11,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ms55,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM__mp3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_mp4a,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_twos,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_sowt,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_QDMC,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_QDM2,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ima4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_IMA4,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_dvi,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_alaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_ulaw,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_raw,     MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_MAC3,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_MAC6,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_Qclp,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { ATOM_samr,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, ATOM_stsd },
+    { 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 },
+    { ATOM_mp4v,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_SVQ1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_SVQ3,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_ZyGo,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_DIVX,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_XVID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_h263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_s263,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_cvid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3IV1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3iv1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3IV2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3iv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3IVD,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3ivd,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3VID,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_3vid,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_mjpa,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_mjpb,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { 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 },
+
+    { ATOM_dvc,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_dvp,     MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_dv5n,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_dv5p,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_VP31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_vp31,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_h264,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+
+    { ATOM_jpeg,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+    { ATOM_avc1,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, ATOM_stsd },
+
+    { ATOM_yv12,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, 0 },
+    { ATOM_yuv2,    MP4_ReadBox_sample_vide,  MP4_FreeBox_sample_vide, 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 },
+    { ATOM_hint,    MP4_ReadBox_default,      MP4_FreeBox_Common, 0 },
 
     /* found in tref box */
-    { ATOM_dpnd,    MP4_ReadBox_default,      NULL },
-    { ATOM_ipir,    MP4_ReadBox_default,      NULL },
-    { ATOM_mpod,    MP4_ReadBox_default,      NULL },
-    { ATOM_chap,    MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic },
+    { ATOM_dpnd,    MP4_ReadBox_default,      NULL, 0 },
+    { ATOM_ipir,    MP4_ReadBox_default,      NULL, 0 },
+    { ATOM_mpod,    MP4_ReadBox_default,      NULL, 0 },
+    { ATOM_chap,    MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic, 0 },
 
     /* found in hnti */
-    { ATOM_rtp,     MP4_ReadBox_default,      NULL },
-
-    /* found in rmra */
-    { ATOM_rdrf,    MP4_ReadBox_rdrf,         MP4_FreeBox_rdrf   },
-    { ATOM_rmdr,    MP4_ReadBox_rmdr,         MP4_FreeBox_Common },
-    { ATOM_rmqu,    MP4_ReadBox_rmqu,         MP4_FreeBox_Common },
-    { ATOM_rmvc,    MP4_ReadBox_rmvc,         MP4_FreeBox_Common },
-
-    { ATOM_drms,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun },
-    { ATOM_sinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_schi,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_user,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
-    { ATOM_key,     MP4_ReadBox_drms,         MP4_FreeBox_Common },
-    { ATOM_iviv,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
-    { ATOM_priv,    MP4_ReadBox_drms,         MP4_FreeBox_Common },
-    { ATOM_frma,    MP4_ReadBox_frma,         MP4_FreeBox_Common },
-    { ATOM_skcr,    MP4_ReadBox_skcr,         MP4_FreeBox_Common },
-
-    /* found in udta */
-    { ATOM_0xa9nam, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9aut, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9cpy, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9swr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9inf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9ART, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9dir, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9cmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9req, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9day, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9fmt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9prd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9prf, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9src, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9alb, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9dis, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9enc, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9trk, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9dsa, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9hst, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9url, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9ope, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9com, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9wrt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9too, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9wrn, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9mak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9mod, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9PRD, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9grp, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9lyr, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9gen, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9st3, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9ard, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9arg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9cak, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9con, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9des, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9lnt, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9phg, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9pub, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9sne, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9sol, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9thx, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-    { ATOM_0xa9xpd, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx },
-
-    { ATOM_chpl,    MP4_ReadBox_chpl,         MP4_FreeBox_chpl },
+    { ATOM_rtp,     MP4_ReadBox_default,      NULL, 0 },
+
+    /* found in rmra/rmda */
+    { ATOM_rdrf,    MP4_ReadBox_rdrf,         MP4_FreeBox_rdrf  , ATOM_rmda },
+    { ATOM_rmdr,    MP4_ReadBox_rmdr,         MP4_FreeBox_Common, ATOM_rmda },
+    { ATOM_rmqu,    MP4_ReadBox_rmqu,         MP4_FreeBox_Common, ATOM_rmda },
+    { ATOM_rmvc,    MP4_ReadBox_rmvc,         MP4_FreeBox_Common, ATOM_rmda },
+
+    { ATOM_drms,    MP4_ReadBox_sample_soun,  MP4_FreeBox_sample_soun, 0 },
+    { ATOM_sinf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_schi,    MP4_ReadBoxContainer,     MP4_FreeBox_Common, 0 },
+    { ATOM_user,    MP4_ReadBox_drms,         MP4_FreeBox_Common, 0 },
+    { ATOM_key,     MP4_ReadBox_drms,         MP4_FreeBox_Common, 0 },
+    { 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 },
+
+    /* ilst meta tags */
+    { ATOM_0xa9ART, 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_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_0xa9enc, MP4_ReadBox_0xa9xxx,      MP4_FreeBox_0xa9xxx, ATOM_ilst },
+    { ATOM_0xa9gen, 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_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 },
-    { ATOM_name,    MP4_ReadBox_name,         MP4_FreeBox_name },
+    { ATOM_meta,    MP4_ReadBox_meta,         MP4_FreeBox_Common,  0 },
+    { ATOM_data,    MP4_ReadBox_data,         MP4_FreeBox_data,    0 },
 
     /* found in smoothstreaming */
-    { ATOM_traf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_mfra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common },
-    { ATOM_mfhd,    MP4_ReadBox_mfhd,         MP4_FreeBox_Common },
-    { ATOM_sidx,    MP4_ReadBox_sidx,         MP4_FreeBox_sidx },
-    { ATOM_tfhd,    MP4_ReadBox_tfhd,         MP4_FreeBox_Common },
-    { ATOM_trun,    MP4_ReadBox_trun,         MP4_FreeBox_trun },
-    { ATOM_trex,    MP4_ReadBox_trex,         MP4_FreeBox_Common },
-    { ATOM_mehd,    MP4_ReadBox_mehd,         MP4_FreeBox_Common },
-    { ATOM_sdtp,    MP4_ReadBox_sdtp,         MP4_FreeBox_sdtp },
-    { ATOM_tfra,    MP4_ReadBox_tfra,         MP4_FreeBox_tfra },
-    { ATOM_mfro,    MP4_ReadBox_mfro,         MP4_FreeBox_Common },
-    { ATOM_uuid,    MP4_ReadBox_uuid,         MP4_FreeBox_uuid },
+    { ATOM_traf,    MP4_ReadBoxContainer,     MP4_FreeBox_Common,  ATOM_moof },
+    { ATOM_mfra,    MP4_ReadBoxContainer,     MP4_FreeBox_Common,  0 },
+    { ATOM_mfhd,    MP4_ReadBox_mfhd,         MP4_FreeBox_Common,  ATOM_moof },
+    { ATOM_sidx,    MP4_ReadBox_sidx,         MP4_FreeBox_sidx,    0 },
+    { ATOM_tfhd,    MP4_ReadBox_tfhd,         MP4_FreeBox_Common,  ATOM_traf },
+    { ATOM_trun,    MP4_ReadBox_trun,         MP4_FreeBox_trun,    ATOM_traf },
+    { ATOM_trex,    MP4_ReadBox_trex,         MP4_FreeBox_Common,  ATOM_mvex },
+    { ATOM_mehd,    MP4_ReadBox_mehd,         MP4_FreeBox_Common,  ATOM_mvex },
+    { ATOM_sdtp,    MP4_ReadBox_sdtp,         MP4_FreeBox_sdtp,    0 },
+    { ATOM_tfra,    MP4_ReadBox_tfra,         MP4_FreeBox_tfra,    ATOM_mfra },
+    { ATOM_mfro,    MP4_ReadBox_mfro,         MP4_FreeBox_Common,  ATOM_mfra },
+    { ATOM_uuid,    MP4_ReadBox_uuid,         MP4_FreeBox_uuid,    0 },
 
     /* Last entry */
-    { 0,              MP4_ReadBox_default,      NULL }
+    { 0,              MP4_ReadBox_default,      NULL, 0 }
 };
 
 
@@ -3391,6 +3820,11 @@ static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father )
     /* Now search function to call */
     for( i_index = 0; ; i_index++ )
     {
+        if ( MP4_Box_Function[i_index].i_parent &&
+             p_box->p_father &&
+             p_box->p_father->i_type != MP4_Box_Function[i_index].i_parent )
+            continue;
+
         if( ( MP4_Box_Function[i_index].i_type == p_box->i_type )||
             ( MP4_Box_Function[i_index].i_type == 0 ) )
         {
@@ -3404,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;
 }
 
@@ -3413,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 )
@@ -3429,17 +3864,9 @@ void MP4_BoxFree( stream_t *s, MP4_Box_t *p_box )
     }
 
     /* Now search function to call */
-    if( p_box->data.p_data )
+    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()
@@ -3453,9 +3880,9 @@ 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_data );
+        free( p_box->data.p_payload );
     }
     free( p_box );
 }
@@ -3527,6 +3954,13 @@ MP4_Box_t *MP4_BoxGetNextChunk( stream_t *s )
 
     MP4_ReadBoxContainerChildren( s, p_chunk, ATOM_moof );
 
+    p_tmp_box = p_chunk->p_first;
+    while( p_tmp_box )
+    {
+        p_chunk->i_size += p_tmp_box->i_size;
+        p_tmp_box = p_tmp_box->p_next;
+    }
+
     return p_chunk;
 }
 
@@ -3553,7 +3987,7 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
     p_root->i_size = 0;
     CreateUUID( &p_root->i_uuid, p_root->i_type );
 
-    p_root->data.p_data = NULL;
+    p_root->data.p_payload = NULL;
     p_root->p_father    = NULL;
     p_root->p_first     = NULL;
     p_root->p_last      = NULL;
@@ -3571,7 +4005,7 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
         return p_root;
 
     p_root->i_size = stream_Size( s );
-    if( stream_Tell( s ) < stream_Size( s ) )
+    if( stream_Tell( s ) + 8 < stream_Size( s ) )
     {
         /* Get the rest of the file */
         i_result = MP4_ReadBoxContainerRaw( p_stream, p_root );
@@ -3609,6 +4043,7 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
 
 error:
     free( p_root );
+    stream_Seek( p_stream, 0 );
     return NULL;
 }
 
@@ -3617,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
     {
@@ -3638,14 +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 %d",
-                        (char*)&p_box->i_type, (uint32_t)p_box->i_size );
-        else
-            snprintf( &str[i_level * 4], sizeof(str) - 4*i_level,
-                      "+ c%3.3s size %d",
-                        (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
+
+        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;