]> git.sesse.net Git - vlc/blobdiff - modules/demux/mp4/libmp4.c
smem: Allow usage of RGBA
[vlc] / modules / demux / mp4 / libmp4.c
index cbd9858e65bd88be7eddde1d90d4c63d9949644c..b6f860f9f224535eb53f454eef696497b29beb93 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * libmp4.c : LibMP4 library for mp4 module for vlc
  *****************************************************************************
- * Copyright (C) 2001-2004 the VideoLAN team
+ * Copyright (C) 2001-2004, 2010 the VideoLAN team
  * $Id$
  *
  * Author: Laurent Aimar <fenrir@via.ecp.fr>
  * 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
 # include "config.h"
 #endif
 
 #include <vlc_common.h>
-
-
 #include <vlc_demux.h>
 
 #ifdef HAVE_ZLIB_H
 
 /*****************************************************************************
  * Here are defined some macro to make life simpler but before using it
- *  *look* at the code.
+ * *look* at the code.
  *
  *****************************************************************************/
+
 #define MP4_BOX_HEADERSIZE( p_box )             \
   ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 )     \
       + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
 
 
 /* Some assumptions:
       * The input method HAVE to be seekable
* The input method HAS to be seekable
 
 */
 
@@ -1111,6 +1111,111 @@ error:
     MP4_READBOX_EXIT( 0 );
 }
 
+static int MP4_ReadBox_dac3( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_data_dac3_t *p_dac3;
+    MP4_READBOX_ENTER( MP4_Box_data_dac3_t );
+
+    p_dac3 = p_box->data.p_dac3;
+
+    unsigned i_header;
+    MP4_GET3BYTES( i_header );
+
+    p_dac3->i_fscod = ( i_header >> 22 ) & 0x03;
+    p_dac3->i_bsid  = ( i_header >> 17 ) & 0x01f;
+    p_dac3->i_bsmod = ( i_header >> 14 ) & 0x07;
+    p_dac3->i_acmod = ( i_header >> 11 ) & 0x07;
+    p_dac3->i_lfeon = ( i_header >> 10 ) & 0x01;
+    p_dac3->i_bitrate_code = ( i_header >> 5) & 0x1f;
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream,
+             "read box: \"dac3\" fscod=0x%x bsid=0x%x bsmod=0x%x acmod=0x%x lfeon=0x%x bitrate_code=0x%x",
+             p_dac3->i_fscod, p_dac3->i_bsid, p_dac3->i_bsmod, p_dac3->i_acmod, p_dac3->i_lfeon, p_dac3->i_bitrate_code );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_enda( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_Box_data_enda_t *p_enda;
+    MP4_READBOX_ENTER( MP4_Box_data_enda_t );
+
+    p_enda = p_box->data.p_enda;
+
+    MP4_GET2BYTES( p_enda->i_little_endian );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream,
+             "read box: \"enda\" little_endian=%d", p_enda->i_little_endian );
+#endif
+    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 != VLC_FOURCC('d', 'a', 't', 'a') )
+        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 != VLC_FOURCC('d', 'a', 't', 'a') )
+        MP4_READBOX_EXIT( 0 );
+
+    uint32_t i_version;
+    uint32_t i_reserved;
+    MP4_GET4BYTES( i_version );
+    MP4_GET4BYTES( i_reserved );
+    MP4_GET4BYTES( 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_GET4BYTES( 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 )
 {
     unsigned int i;
@@ -1218,12 +1323,12 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box )
 
     if( p_box->i_type == FOURCC_drms )
     {
-        p_box->data.p_sample_soun->p_drms =
-            drms_alloc( config_GetHomeDir() );
-
-        if( p_box->data.p_sample_soun->p_drms == NULL )
+        char *home = config_GetUserDir( VLC_HOME_DIR );
+        if( home != NULL )
         {
-            msg_Err( p_stream, "drms_alloc() failed" );
+            p_box->data.p_sample_soun->p_drms = drms_alloc( home );
+            if( p_box->data.p_sample_soun->p_drms == NULL )
+                msg_Err( p_stream, "drms_alloc() failed" );
         }
     }
 
@@ -1316,6 +1421,18 @@ int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
 
     stream_Seek( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
+
+    if( p_box->i_type == FOURCC_drmi )
+    {
+        char *home = config_GetUserDir( VLC_HOME_DIR );
+        if( home != NULL )
+        {
+            p_box->data.p_sample_vide->p_drms = drms_alloc( home );
+            if( p_box->data.p_sample_vide->p_drms == NULL )
+                msg_Err( p_stream, "drms_alloc() failed" );
+        }
+    }
+
     MP4_ReadBoxContainerRaw( p_stream, p_box );
 
 #ifdef MP4_VERBOSE
@@ -1332,6 +1449,14 @@ int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box )
 void MP4_FreeBox_sample_vide( MP4_Box_t *p_box )
 {
     FREENULL( p_box->data.p_sample_vide->p_qt_image_description );
+
+    if( p_box->i_type == FOURCC_drmi )
+    {
+        if( p_box->data.p_sample_vide->p_drms )
+        {
+            drms_free( p_box->data.p_sample_vide->p_drms );
+        }
+    }
 }
 
 static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box )
@@ -1418,7 +1543,7 @@ 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_right );
 
 #ifdef MP4_VERBOSE
-    msg_Dbg( p_stream, "read box: \"text\" in stsd text" );
+    msg_Dbg( p_stream, "read box: \"tx3g\" in stsd text" );
 #endif
     MP4_READBOX_EXIT( 1 );
 }
@@ -1872,10 +1997,7 @@ static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box )
     p_box->data.p_cmvd->i_compressed_size = i_read;
 
     if( !( p_box->data.p_cmvd->p_data = malloc( i_read ) ) )
-    {
-        msg_Dbg( p_stream, "read box: \"cmvd\" not enough memory to load data" );
         return( 1 );
-    }
 
     /* now copy compressed data */
     memcpy( p_box->data.p_cmvd->p_data,
@@ -1910,10 +2032,7 @@ static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
 #endif
 
     if( !( p_box->data.p_cmov = malloc( sizeof( MP4_Box_data_cmov_t ) ) ) )
-    {
-        msg_Err( p_stream, "out of memory" );
         return 0;
-    }
     memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
 
     if( !p_box->p_father ||
@@ -1934,29 +2053,25 @@ static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
         p_cmvd->data.p_cmvd->p_data == NULL )
     {
         msg_Warn( p_stream, "read box: \"cmov\" incomplete" );
-        return 1;
+        return 0;
     }
 
     if( p_dcom->data.p_dcom->i_algorithm != FOURCC_zlib )
     {
         msg_Dbg( p_stream, "read box: \"cmov\" compression algorithm : %4.4s "
                  "not supported", (char*)&p_dcom->data.p_dcom->i_algorithm );
-        return 1;
+        return 0;
     }
 
 #ifndef HAVE_ZLIB_H
     msg_Dbg( p_stream, "read box: \"cmov\" zlib unsupported" );
-    return 1;
+    return 0;
 
 #else
     /* decompress data */
     /* allocate a new buffer */
     if( !( p_data = malloc( p_cmvd->data.p_cmvd->i_uncompressed_size ) ) )
-    {
-        msg_Err( p_stream, "read box: \"cmov\" not enough memory to "
-                 "uncompress data" );
-        return 1;
-    }
+        return 0;
     /* init default structures */
     z_data.next_in   = p_cmvd->data.p_cmvd->p_data;
     z_data.avail_in  = p_cmvd->data.p_cmvd->i_compressed_size;
@@ -1971,7 +2086,7 @@ static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
     {
         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
         free( p_data );
-        return 1;
+        return 0;
     }
 
     /* uncompress */
@@ -1980,7 +2095,7 @@ static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
     {
         msg_Err( p_stream, "read box: \"cmov\" error while uncompressing" );
         free( p_data );
-        return 1;
+        return 0;
     }
 
     if( p_cmvd->data.p_cmvd->i_uncompressed_size != z_data.total_out )
@@ -2001,7 +2116,7 @@ static int MP4_ReadBox_cmov( stream_t *p_stream, MP4_Box_t *p_box )
     p_cmvd->data.p_cmvd->p_data = p_data;
     p_cmvd->data.p_cmvd->b_compressed = 0;
 
-    msg_Dbg( p_stream, "read box: \"cmov\" box succesfully uncompressed" );
+    msg_Dbg( p_stream, "read box: \"cmov\" box successfully uncompressed" );
 
     /* now create a memory stream */
     p_stream_memory =
@@ -2116,21 +2231,59 @@ static int MP4_ReadBox_rmvc( stream_t *p_stream, MP4_Box_t *p_box )
     MP4_READBOX_EXIT( 1 );
 }
 
+static int MP4_ReadBox_frma( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_frma_t );
+
+    MP4_GETFOURCC( p_box->data.p_frma->i_type );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"frma\" i_type:%4.4s",
+             (char *)&p_box->data.p_frma->i_type );
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_skcr( stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_frma_t );
+
+    MP4_GET4BYTES( p_box->data.p_skcr->i_init );
+    MP4_GET4BYTES( p_box->data.p_skcr->i_encr );
+    MP4_GET4BYTES( p_box->data.p_skcr->i_decr );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"skcr\" i_init:%d i_encr:%d i_decr:%d",
+             p_box->data.p_skcr->i_init,
+             p_box->data.p_skcr->i_encr,
+             p_box->data.p_skcr->i_decr );
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+}
+
 static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
 {
     MP4_Box_t *p_drms_box = p_box;
+    void *p_drms = NULL;
 
     MP4_READBOX_ENTER( uint8_t );
 
     do
     {
         p_drms_box = p_drms_box->p_father;
-    } while( p_drms_box && p_drms_box->i_type != FOURCC_drms );
+    } while( p_drms_box && p_drms_box->i_type != FOURCC_drms
+                        && p_drms_box->i_type != FOURCC_drmi );
+
+    if( p_drms_box && p_drms_box->i_type == FOURCC_drms )
+        p_drms = p_drms_box->data.p_sample_soun->p_drms;
+    else if( p_drms_box && p_drms_box->i_type == FOURCC_drmi )
+        p_drms = p_drms_box->data.p_sample_vide->p_drms;
 
-    if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms )
+    if( p_drms_box && p_drms )
     {
-        int i_ret = drms_init( p_drms_box->data.p_sample_soun->p_drms,
-                               p_box->i_type, p_peek, i_read );
+        int i_ret = drms_init( p_drms, p_box->i_type, p_peek, i_read );
         if( i_ret )
         {
             const char *psz_error;
@@ -2152,8 +2305,12 @@ static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box )
                 msg_Err( p_stream, "drms_init(c%3.3s) failed (%s)",
                         (char *)&p_box->i_type+1, psz_error );
 
-            drms_free( p_drms_box->data.p_sample_soun->p_drms );
-            p_drms_box->data.p_sample_soun->p_drms = NULL;
+            drms_free( p_drms );
+
+            if( p_drms_box->i_type == FOURCC_drms )
+                p_drms_box->data.p_sample_soun->p_drms = NULL;
+            else if( p_drms_box->i_type == FOURCC_drmi )
+                p_drms_box->data.p_sample_vide->p_drms = NULL;
         }
     }
 
@@ -2394,6 +2551,7 @@ static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
             case FOURCC_text:
                 return MP4_ReadBox_sample_text( p_stream, p_box );
             case FOURCC_tx3g:
+            case FOURCC_sbtl:
                 return MP4_ReadBox_sample_tx3g( p_stream, p_box );
             default:
                 msg_Warn( p_stream,
@@ -2475,6 +2633,10 @@ static const struct
     { FOURCC_dcom,  MP4_ReadBox_dcom,       MP4_FreeBox_Common },
     { FOURCC_cmvd,  MP4_ReadBox_cmvd,       MP4_FreeBox_cmvd },
     { FOURCC_avcC,  MP4_ReadBox_avcC,       MP4_FreeBox_avcC },
+    { FOURCC_dac3,  MP4_ReadBox_dac3,       MP4_FreeBox_Common },
+    { FOURCC_enda,  MP4_ReadBox_enda,       MP4_FreeBox_Common },
+    { FOURCC_gnre,  MP4_ReadBox_gnre,       MP4_FreeBox_Common },
+    { FOURCC_trkn,  MP4_ReadBox_trkn,       MP4_FreeBox_Common },
 
     /* Nothing to do with this box */
     { FOURCC_mdat,  MP4_ReadBoxSkip,        MP4_FreeBox_Common },
@@ -2507,6 +2669,7 @@ static const struct
     { FOURCC_OggS,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
     { FOURCC_alac,  MP4_ReadBox_sample_soun,    MP4_FreeBox_sample_soun },
 
+    { FOURCC_drmi,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
     { FOURCC_vide,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
     { FOURCC_mp4v,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
     { FOURCC_SVQ1,  MP4_ReadBox_sample_vide,    MP4_FreeBox_sample_vide },
@@ -2576,6 +2739,8 @@ static const struct
     { FOURCC_iviv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
     { FOURCC_name,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
     { FOURCC_priv,  MP4_ReadBox_drms,           MP4_FreeBox_Common },
+    { FOURCC_frma,  MP4_ReadBox_frma,           MP4_FreeBox_Common },
+    { FOURCC_skcr,  MP4_ReadBox_skcr,           MP4_FreeBox_Common },
 
     /* found in udta */
     { FOURCC_0xa9nam,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
@@ -2603,6 +2768,14 @@ static const struct
     { FOURCC_0xa9url,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
     { FOURCC_0xa9ope,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
     { FOURCC_0xa9com,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9wrt,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9too,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9wrn,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9mak,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9mod,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9PRD,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9grp,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
+    { FOURCC_0xa9lyr,MP4_ReadBox_0xa9xxx,       MP4_FreeBox_0xa9xxx },
 
     { FOURCC_chpl,   MP4_ReadBox_chpl,          MP4_FreeBox_chpl },
 
@@ -2747,7 +2920,6 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
 
     if( i_result )
     {
-        MP4_Box_t *p_child;
         MP4_Box_t *p_moov;
         MP4_Box_t *p_cmov;
 
@@ -2769,7 +2941,7 @@ MP4_Box_t *MP4_BoxGetRoot( stream_t *s )
             p_moov->p_father = p_root;
 
             /* insert this new moov box as first child of p_root */
-            p_moov->p_next = p_child = p_root->p_first;
+            p_moov->p_next = p_root->p_first;
             p_root->p_first = p_moov;
         }
     }
@@ -2794,18 +2966,24 @@ static void __MP4_BoxDumpStructure( stream_t *s,
     }
     else
     {
-        char str[512];
         unsigned int i;
-        memset( str, (uint8_t)' ', 512 );
+
+        char str[512];
+        if( i_level >= (sizeof(str) - 1)/5 )
+            return;
+
+        memset( str, ' ', sizeof(str) );
         for( i = 0; i < i_level; i++ )
         {
             str[i*5] = '|';
         }
-        if MP4_BOX_TYPE_ASCII()
-            sprintf( str + i_level * 5, "+ %4.4s size %d",
+        if( MP4_BOX_TYPE_ASCII() )
+            snprintf( &str[i_level * 5], sizeof(str) - 5*i_level,
+                      "+ %4.4s size %d",
                         (char*)&p_box->i_type, (uint32_t)p_box->i_size );
         else
-            sprintf( str + i_level * 5, "+ c%3.3s size %d",
+            snprintf( &str[i_level * 5], sizeof(str) - 5*i_level,
+                      "+ c%3.3s size %d",
                         (char*)&p_box->i_type+1, (uint32_t)p_box->i_size );
         msg_Dbg( s, "%s", str );
     }
@@ -2885,7 +3063,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result,
                           MP4_Box_t *p_box, const char *psz_fmt, va_list args)
 {
     char *psz_dup;
-    char    *psz_path;
+    char *psz_path;
 
     if( !p_box )
     {
@@ -2898,7 +3076,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result,
 
     if( !psz_path || !psz_path[0] )
     {
-        FREENULL( psz_path );
+        free( psz_path );
         *pp_result = NULL;
         return;
     }
@@ -2915,7 +3093,6 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result,
 //                 psz_path,psz_token,i_number );
         if( !psz_token )
         {
-            FREENULL( psz_token );
             free( psz_dup );
             *pp_result = p_box;
             return;
@@ -2981,7 +3158,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result,
             }
         }
         else
-        if( strlen( psz_token ) == 0 )
+        if( *psz_token == '\0' )
         {
             p_box = p_box->p_first;
             for( ; ; )