X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fmp4%2Flibmp4.c;h=d1a35bd88b64610ae9ccd6e567d9d1f328918145;hb=6ee1e193fd896ab9a4729fde14f009d9ce629815;hp=6d4a2dafbf3bb9bd4f5d5ba0c3a00b97933f3928;hpb=e97a64efe8e7e8f34c488126055191b996ab15ba;p=vlc diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c index 6d4a2dafbf..d1a35bd88b 100644 --- a/modules/demux/mp4/libmp4.c +++ b/modules/demux/mp4/libmp4.c @@ -20,10 +20,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#include /* malloc(), free() */ - #include -#include + + +#include #ifdef HAVE_ZLIB_H # include /* for compressed moov */ @@ -37,57 +37,53 @@ * *look* at the code. * *****************************************************************************/ -#define MP4_BOX_HEADERSIZE( p_box ) \ - ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \ +#define MP4_BOX_HEADERSIZE( p_box ) \ + ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \ + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) ) -#define MP4_GET1BYTE( dst ) \ - dst = *p_peek; p_peek++; i_read-- - -#define MP4_GET2BYTES( dst ) \ - dst = GetWBE( p_peek ); p_peek += 2; i_read -= 2 - -#define MP4_GET3BYTES( dst ) \ - dst = Get24bBE( p_peek ); p_peek += 3; i_read -= 3 - -#define MP4_GET4BYTES( dst ) \ - dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4 +#define MP4_GETX_PRIVATE(dst, code, size) do { \ + if( (i_read) >= (size) ) { dst = (code); p_peek += (size); } \ + else { dst = 0; } \ + i_read -= (size); \ + } while(0) -#define MP4_GETFOURCC( dst ) \ - dst = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] ); \ - p_peek += 4; i_read -= 4 - -#define MP4_GET8BYTES( dst ) \ - dst = GetQWBE( p_peek ); p_peek += 8; i_read -= 8 +#define MP4_GET1BYTE( dst ) MP4_GETX_PRIVATE( dst, *p_peek, 1 ) +#define MP4_GET2BYTES( dst ) MP4_GETX_PRIVATE( dst, GetWBE(p_peek), 2 ) +#define MP4_GET3BYTES( dst ) MP4_GETX_PRIVATE( dst, Get24bBE(p_peek), 3 ) +#define MP4_GET4BYTES( dst ) MP4_GETX_PRIVATE( dst, GetDWBE(p_peek), 4 ) +#define MP4_GET8BYTES( dst ) MP4_GETX_PRIVATE( dst, GetQWBE(p_peek), 8 ) +#define MP4_GETFOURCC( dst ) MP4_GETX_PRIVATE( dst, \ + VLC_FOURCC(p_peek[0],p_peek[1],p_peek[2],p_peek[3]), 4) #define MP4_GETVERSIONFLAGS( p_void ) \ MP4_GET1BYTE( p_void->i_version ); \ MP4_GET3BYTES( p_void->i_flags ) -#define MP4_GETSTRINGZ( p_str ) \ - if( ( i_read > 0 )&&(p_peek[0] ) ) \ - { \ - p_str = calloc( sizeof( char ), __MIN( strlen( p_peek ), i_read )+1);\ - memcpy( p_str, p_peek, __MIN( strlen( p_peek ), i_read ) ); \ - p_str[__MIN( strlen( p_peek ), i_read )] = 0; \ - p_peek += strlen( p_str ) + 1; \ - i_read -= strlen( p_str ) + 1; \ - } \ - else \ - { \ +#define MP4_GETSTRINGZ( p_str ) \ + if( (i_read > 0) && (p_peek[0]) ) \ + { \ + const int __i_copy__ = strnlen( (char*)p_peek, i_read-1 ); \ + p_str = calloc( sizeof(char), __i_copy__+1 ); \ + if( __i_copy__ > 0 ) memcpy( p_str, p_peek, __i_copy__ ); \ + p_str[__i_copy__] = 0; \ + p_peek += __i_copy__ + 1; \ + i_read -= __i_copy__ + 1; \ + } \ + else \ + { \ p_str = NULL; \ } - #define MP4_READBOX_ENTER( MP4_Box_data_TYPE_t ) \ int64_t i_read = p_box->i_size; \ uint8_t *p_peek, *p_buff; \ - i_read = p_box->i_size; \ + int i_actually_read; \ if( !( p_peek = p_buff = malloc( i_read ) ) ) \ { \ return( 0 ); \ } \ - if( stream_Read( p_stream, p_peek, i_read ) < i_read )\ + i_actually_read = stream_Read( p_stream, p_peek, i_read ); \ + if( i_actually_read < 0 || (int64_t)i_actually_read < i_read )\ { \ free( p_buff ); \ return( 0 ); \ @@ -108,22 +104,18 @@ } \ return( i_code ) -#define FREE( p ) \ - if( p ) {free( p ); p = NULL; } - - /* Some assumptions: * The input method HAVE to be seekable */ -static uint32_t Get24bBE( uint8_t *p ) +static uint32_t Get24bBE( const uint8_t *p ) { return( ( p[0] <<16 ) + ( p[1] <<8 ) + p[2] ); } -static void GetUUID( UUID_t *p_uuid, uint8_t *p_buff ) +static void GetUUID( UUID_t *p_uuid, const uint8_t *p_buff ) { memcpy( p_uuid, p_buff, 16 ); } @@ -171,7 +163,7 @@ static MP4_Box_t *MP4_ReadBox( stream_t *p_stream, MP4_Box_t *p_father ); int MP4_ReadBoxCommon( stream_t *p_stream, MP4_Box_t *p_box ) { int i_read; - uint8_t *p_peek; + const uint8_t *p_peek; if( ( ( i_read = stream_Peek( p_stream, &p_peek, 32 ) ) < 8 ) ) { @@ -244,11 +236,14 @@ static int MP4_NextBox( stream_t *p_stream, MP4_Box_t *p_box ) if( p_box->p_father ) { + const int i_box_end = p_box->i_size + p_box->i_pos; + const int i_father_end = p_box->p_father->i_size + p_box->p_father->i_pos; + /* check if it's within p-father */ - if( p_box->i_size + p_box->i_pos >= - p_box->p_father->i_size + p_box->p_father->i_pos ) + if( i_box_end >= i_father_end ) { - msg_Dbg( p_stream, "out of bound child" ); + if( i_box_end > i_father_end ) + msg_Dbg( p_stream, "out of bound child" ); return 0; /* out of bound */ } } @@ -318,7 +313,7 @@ static int MP4_ReadBoxSkip( stream_t *p_stream, MP4_Box_t *p_box ) p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' ) && p_box->i_type == FOURCC_free ) { - uint8_t *p_peek; + const uint8_t *p_peek; int i_read; vlc_fourcc_t i_fcc; @@ -376,7 +371,7 @@ static int MP4_ReadBox_ftyp( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_ftyp( MP4_Box_t *p_box ) { - FREE( p_box->data.p_ftyp->i_compatible_brands ); + FREENULL( p_box->data.p_ftyp->i_compatible_brands ); } @@ -619,7 +614,7 @@ static int MP4_ReadBox_hdlr( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_hdlr( MP4_Box_t *p_box ) { - FREE( p_box->data.p_hdlr->psz_name ); + FREENULL( p_box->data.p_hdlr->psz_name ); } static int MP4_ReadBox_vmhd( stream_t *p_stream, MP4_Box_t *p_box ) @@ -708,7 +703,7 @@ static int MP4_ReadBox_url( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_url( MP4_Box_t *p_box ) { - FREE( p_box->data.p_url->psz_location ) + FREENULL( p_box->data.p_url->psz_location ) } static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box ) @@ -729,8 +724,8 @@ static int MP4_ReadBox_urn( stream_t *p_stream, MP4_Box_t *p_box ) } static void MP4_FreeBox_urn( MP4_Box_t *p_box ) { - FREE( p_box->data.p_urn->psz_name ); - FREE( p_box->data.p_urn->psz_location ); + FREENULL( p_box->data.p_urn->psz_name ); + FREENULL( p_box->data.p_urn->psz_location ); } @@ -783,8 +778,8 @@ static int MP4_ReadBox_stts( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stts( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stts->i_sample_count ); - FREE( p_box->data.p_stts->i_sample_delta ); + FREENULL( p_box->data.p_stts->i_sample_count ); + FREENULL( p_box->data.p_stts->i_sample_delta ); } static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box ) @@ -817,8 +812,8 @@ static int MP4_ReadBox_ctts( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_ctts( MP4_Box_t *p_box ) { - FREE( p_box->data.p_ctts->i_sample_count ); - FREE( p_box->data.p_ctts->i_sample_offset ); + FREENULL( p_box->data.p_ctts->i_sample_count ); + FREENULL( p_box->data.p_ctts->i_sample_offset ); } static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t *i_read ) @@ -941,12 +936,12 @@ static int MP4_ReadBox_esds( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_esds( MP4_Box_t *p_box ) { - FREE( p_box->data.p_esds->es_descriptor.psz_URL ); + FREENULL( p_box->data.p_esds->es_descriptor.psz_URL ); if( p_box->data.p_esds->es_descriptor.p_decConfigDescr ) { - FREE( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info ); + FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr->p_decoder_specific_info ); } - FREE( p_box->data.p_esds->es_descriptor.p_decConfigDescr ); + FREENULL( p_box->data.p_esds->es_descriptor.p_decConfigDescr ); } static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box ) @@ -958,8 +953,11 @@ static int MP4_ReadBox_avcC( stream_t *p_stream, MP4_Box_t *p_box ) p_avcC = p_box->data.p_avcC; p_avcC->i_avcC = i_read; - p_avcC->p_avcC = malloc( p_avcC->i_avcC ); - memcpy( p_avcC->p_avcC, p_peek, i_read ); + if( p_avcC->i_avcC > 0 ) + { + p_avcC->p_avcC = malloc( p_avcC->i_avcC ); + memcpy( p_avcC->p_avcC, p_peek, i_read ); + } MP4_GET1BYTE( p_avcC->i_version ); MP4_GET1BYTE( p_avcC->i_profile ); @@ -1031,16 +1029,20 @@ static void MP4_FreeBox_avcC( MP4_Box_t *p_box ) MP4_Box_data_avcC_t *p_avcC = p_box->data.p_avcC; int i; + if( p_avcC->i_avcC > 0 ) FREENULL( p_avcC->p_avcC ); + for( i = 0; i < p_avcC->i_sps; i++ ) { - FREE( p_avcC->sps[i] ); + FREENULL( p_avcC->sps[i] ); } for( i = 0; i < p_avcC->i_pps; i++ ) { - FREE( p_avcC->pps[i] ); + FREENULL( p_avcC->pps[i] ); } - if( p_avcC->i_sps > 0 ) FREE( p_avcC->sps ); - if( p_avcC->i_pps > 0 ) FREE( p_avcC->pps ); + if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->sps ); + if( p_avcC->i_sps > 0 ) FREENULL( p_avcC->i_sps_length ); + if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->pps ); + if( p_avcC->i_pps > 0 ) FREENULL( p_avcC->i_pps_length ); } static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1115,10 +1117,12 @@ 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( (*(int64_t *)&f_sample_rate) ); + MP4_GET8BYTES( dummy ); + memcpy( &f_sample_rate, &dummy, 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; @@ -1149,7 +1153,7 @@ 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( p_stream->p_vlc->psz_homedir ); + drms_alloc( p_stream->p_libvlc->psz_homedir ); if( p_box->data.p_sample_soun->p_drms == NULL ) { @@ -1192,7 +1196,7 @@ static int MP4_ReadBox_sample_soun( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box ) { - FREE( p_box->data.p_sample_soun->p_qt_description ); + FREENULL( p_box->data.p_sample_soun->p_qt_description ); if( p_box->i_type == FOURCC_drms ) { @@ -1271,7 +1275,7 @@ int MP4_ReadBox_sample_vide( stream_t *p_stream, MP4_Box_t *p_box ) void MP4_FreeBox_sample_vide( MP4_Box_t *p_box ) { - FREE( p_box->data.p_sample_vide->p_qt_image_description ); + FREENULL( p_box->data.p_sample_vide->p_qt_image_description ); } static int MP4_ReadBox_sample_mp4s( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1368,7 +1372,7 @@ static int MP4_ReadBox_sample_tx3g( stream_t *p_stream, MP4_Box_t *p_box ) /* We can't easily call it, and anyway ~ 20 bytes lost isn't a real problem */ static void MP4_FreeBox_sample_text( MP4_Box_t *p_box ) { - FREE( p_box->data.p_sample_text->psz_text_name ); + FREENULL( p_box->data.p_sample_text->psz_text_name ); } #endif @@ -1429,7 +1433,7 @@ static int MP4_ReadBox_stsz( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stsz( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stsz->i_entry_size ); + FREENULL( p_box->data.p_stsz->i_entry_size ); } static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1466,9 +1470,9 @@ static int MP4_ReadBox_stsc( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stsc( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stsc->i_first_chunk ); - FREE( p_box->data.p_stsc->i_samples_per_chunk ); - FREE( p_box->data.p_stsc->i_sample_description_index ); + FREENULL( p_box->data.p_stsc->i_first_chunk ); + FREENULL( p_box->data.p_stsc->i_samples_per_chunk ); + FREENULL( p_box->data.p_stsc->i_sample_description_index ); } static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1514,7 +1518,7 @@ static int MP4_ReadBox_stco_co64( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stco_co64( MP4_Box_t *p_box ) { - FREE( p_box->data.p_co64->i_chunk_offset ); + FREENULL( p_box->data.p_co64->i_chunk_offset ); } static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1548,7 +1552,7 @@ static int MP4_ReadBox_stss( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stss( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stss->i_sample_number ) + FREENULL( p_box->data.p_stss->i_sample_number ) } static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1585,8 +1589,8 @@ static int MP4_ReadBox_stsh( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stsh( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stsh->i_shadowed_sample_number ) - FREE( p_box->data.p_stsh->i_sync_sample_number ) + FREENULL( p_box->data.p_stsh->i_shadowed_sample_number ) + FREENULL( p_box->data.p_stsh->i_sync_sample_number ) } @@ -1617,7 +1621,7 @@ static int MP4_ReadBox_stdp( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_stdp( MP4_Box_t *p_box ) { - FREE( p_box->data.p_stdp->i_priority ) + FREENULL( p_box->data.p_stdp->i_priority ) } static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1661,17 +1665,17 @@ static int MP4_ReadBox_padb( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_padb( MP4_Box_t *p_box ) { - FREE( p_box->data.p_padb->i_reserved1 ); - FREE( p_box->data.p_padb->i_pad2 ); - FREE( p_box->data.p_padb->i_reserved2 ); - FREE( p_box->data.p_padb->i_pad1 ); + FREENULL( p_box->data.p_padb->i_reserved1 ); + FREENULL( p_box->data.p_padb->i_pad2 ); + FREENULL( p_box->data.p_padb->i_reserved2 ); + FREENULL( p_box->data.p_padb->i_pad1 ); } static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box ) { unsigned int i; - MP4_READBOX_ENTER( MP4_Box_data_padb_t ); + MP4_READBOX_ENTER( MP4_Box_data_elst_t ); MP4_GETVERSIONFLAGS( p_box->data.p_elst ); @@ -1711,19 +1715,18 @@ static int MP4_ReadBox_elst( stream_t *p_stream, MP4_Box_t *p_box ) } #ifdef MP4_VERBOSE - msg_Dbg( p_stream, "read box: \"elst\" entry-count "I64Fd, - i_read / 2 ); - + msg_Dbg( p_stream, "read box: \"elst\" entry-count %lu", + (unsigned long)p_box->data.p_elst->i_entry_count ); #endif MP4_READBOX_EXIT( 1 ); } static void MP4_FreeBox_elst( MP4_Box_t *p_box ) { - FREE( p_box->data.p_elst->i_segment_duration ); - FREE( p_box->data.p_elst->i_media_time ); - FREE( p_box->data.p_elst->i_media_rate_integer ); - FREE( p_box->data.p_elst->i_media_rate_fraction ); + FREENULL( p_box->data.p_elst->i_segment_duration ); + FREENULL( p_box->data.p_elst->i_media_time ); + FREENULL( p_box->data.p_elst->i_media_rate_integer ); + FREENULL( p_box->data.p_elst->i_media_rate_fraction ); } static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box ) @@ -1757,7 +1760,7 @@ static int MP4_ReadBox_cprt( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_cprt( MP4_Box_t *p_box ) { - FREE( p_box->data.p_cprt->psz_notice ); + FREENULL( p_box->data.p_cprt->psz_notice ); } @@ -1804,7 +1807,7 @@ static int MP4_ReadBox_cmvd( stream_t *p_stream, MP4_Box_t *p_box ) } static void MP4_FreeBox_cmvd( MP4_Box_t *p_box ) { - FREE( p_box->data.p_cmvd->p_data ); + FREENULL( p_box->data.p_cmvd->p_data ); } @@ -1967,7 +1970,7 @@ static int MP4_ReadBox_rdrf( stream_t *p_stream, MP4_Box_t *p_box ) static void MP4_FreeBox_rdrf( MP4_Box_t *p_box ) { - FREE( p_box->data.p_rdrf->psz_ref ) + FREENULL( p_box->data.p_rdrf->psz_ref ) } @@ -2035,11 +2038,19 @@ static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box ) if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms ) { - int i_ret = drms_init( p_drms_box->data.p_sample_soun->p_drms, + int i_ret; + if( config_GetInt( p_stream, "france" ) ) + { + i_ret = -7; + } + else + { + i_ret= drms_init( p_drms_box->data.p_sample_soun->p_drms, p_box->i_type, p_peek, i_read ); + } if( i_ret ) { - char *psz_error; + const char *psz_error; switch( i_ret ) { @@ -2049,6 +2060,7 @@ static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box ) case -4: psz_error = "could not get SCI data"; break; case -5: psz_error = "no user key found in SCI data"; break; case -6: psz_error = "invalid user key"; break; + case -7: psz_error = "you live in France"; break; default: psz_error = "unknown error"; break; } @@ -2065,17 +2077,17 @@ static int MP4_ReadBox_drms( stream_t *p_stream, MP4_Box_t *p_box ) static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box ) { - int16_t i_length, i_dummy; + uint16_t i_length, i_dummy; MP4_READBOX_ENTER( MP4_Box_data_0xa9xxx_t ); p_box->data.p_0xa9xxx->psz_text = NULL; MP4_GET2BYTES( i_length ); - MP4_GET2BYTES( i_dummy ); if( i_length > 0 ) { + MP4_GET2BYTES( i_dummy ); if( i_length > i_read ) i_length = i_read; p_box->data.p_0xa9xxx->psz_text = malloc( i_length + 1 ); @@ -2086,17 +2098,173 @@ static int MP4_ReadBox_0xa9xxx( stream_t *p_stream, MP4_Box_t *p_box ) #ifdef MP4_VERBOSE msg_Dbg( p_stream, - "read box: \"%4.4s\" text=`%s'", - (char*)&p_box->i_type, + "read box: \"c%3.3s\" text=`%s'", + ((char*)&p_box->i_type + 1), + p_box->data.p_0xa9xxx->psz_text ); +#endif + } + else + { + /* try iTune/Quicktime format, rewind to start */ + p_peek -= 2; i_read += 2; + // we are expecting a 'data' box + uint32_t i_data_len; + uint32_t i_data_tag; + + 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 == VLC_FOURCC('d', 'a', 't', 'a')) ) + { + /* 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 ) + { + // the rest is the text + i_data_len -= 12; + p_box->data.p_0xa9xxx->psz_text = malloc( i_data_len + 1 ); + + memcpy( p_box->data.p_0xa9xxx->psz_text, + p_peek, i_data_len ); + p_box->data.p_0xa9xxx->psz_text[i_data_len] = '\0'; +#ifdef MP4_VERBOSE + msg_Dbg( p_stream, + "read box: \"c%3.3s\" text=`%s'", + ((char*)&p_box->i_type+1), p_box->data.p_0xa9xxx->psz_text ); #endif + } + else + { + // TODO: handle data values for ID3 tag values, track num or cover art,etc... + } + } } MP4_READBOX_EXIT( 1 ); } static void MP4_FreeBox_0xa9xxx( MP4_Box_t *p_box ) { - FREE( p_box->data.p_0xa9xxx->psz_text ); + FREENULL( p_box->data.p_0xa9xxx->psz_text ); +} + +/* Chapter support */ +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; + int i; + MP4_READBOX_ENTER( MP4_Box_data_chpl_t ); + + p_chpl = p_box->data.p_chpl; + + MP4_GETVERSIONFLAGS( p_chpl ); + + MP4_GET4BYTES( i_dummy ); + + MP4_GET1BYTE( p_chpl->i_chapter ); + + for( i = 0; i < p_chpl->i_chapter; i++ ) + { + uint64_t i_start; + uint8_t i_len; + int i_copy; + MP4_GET8BYTES( i_start ); + MP4_GET1BYTE( i_len ); + + p_chpl->chapter[i].psz_name = malloc( i_len + 1 ); + i_copy = __MIN( i_len, i_read ); + if( i_copy > 0 ) + memcpy( p_chpl->chapter[i].psz_name, p_peek, i_copy ); + p_chpl->chapter[i].psz_name[i_copy] = '\0'; + p_chpl->chapter[i].i_start = i_start; + + p_peek += i_copy; + i_read -= i_copy; + } + /* Bubble sort by increasing start date */ + do + { + for( i = 0; i < p_chpl->i_chapter - 1; i++ ) + { + if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start ) + { + char *psz = p_chpl->chapter[i+1].psz_name; + int64_t i64 = p_chpl->chapter[i+1].i_start; + + p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name; + p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start; + + p_chpl->chapter[i].psz_name = psz; + p_chpl->chapter[i].i_start = i64; + + i = -1; + break; + } + } + } while( i == -1 ); + +#ifdef MP4_VERBOSE + msg_Dbg( p_stream, "read box: \"chpl\" %d chapters", + p_chpl->i_chapter ); +#endif + MP4_READBOX_EXIT( 1 ); +} +static void MP4_FreeBox_chpl( MP4_Box_t *p_box ) +{ + MP4_Box_data_chpl_t *p_chpl = p_box->data.p_chpl; + int i; + for( i = 0; i < p_chpl->i_chapter; i++ ) + free( p_chpl->chapter[i].psz_name ); +} + +static int MP4_ReadBox_tref_generic( stream_t *p_stream, MP4_Box_t *p_box ) +{ + unsigned int i; + MP4_READBOX_ENTER( MP4_Box_data_tref_generic_t ); + + p_box->data.p_tref_generic->i_track_ID = NULL; + p_box->data.p_tref_generic->i_entry_count = i_read / sizeof(uint32_t); + if( p_box->data.p_tref_generic->i_entry_count > 0 ) + p_box->data.p_tref_generic->i_track_ID = malloc( p_box->data.p_tref_generic->i_entry_count * sizeof(uint32_t) ); + + for( i = 0; i < p_box->data.p_tref_generic->i_entry_count; i++ ) + { + MP4_GET4BYTES( p_box->data.p_tref_generic->i_track_ID[i] ); + } +#ifdef MP4_VERBOSE + msg_Dbg( p_stream, "read box: \"chap\" %d references", + p_box->data.p_tref_generic->i_entry_count ); +#endif + + MP4_READBOX_EXIT( 1 ); +} +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_meta( stream_t *p_stream, MP4_Box_t *p_box ) +{ + uint8_t meta_data[8]; + int i_actually_read; + + // skip over box header + i_actually_read = stream_Read( p_stream, meta_data, 8 ); + 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 ) + return 0; + + /* then it behaves like a container */ + return MP4_ReadBoxContainerRaw( p_stream, p_box ); } /* For generic */ @@ -2169,6 +2337,7 @@ static struct { FOURCC_tref, MP4_ReadBoxContainer, MP4_FreeBox_Common }, { FOURCC_gmhd, MP4_ReadBoxContainer, MP4_FreeBox_Common }, { FOURCC_wave, MP4_ReadBoxContainer, MP4_FreeBox_Common }, + { FOURCC_ilst, MP4_ReadBoxContainer, MP4_FreeBox_Common }, /* specific box */ { FOURCC_ftyp, MP4_ReadBox_ftyp, MP4_FreeBox_ftyp }, @@ -2268,6 +2437,9 @@ static struct { FOURCC_jpeg, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide }, { FOURCC_avc1, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide }, + { FOURCC_yv12, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide }, + { FOURCC_yuv2, MP4_ReadBox_sample_vide, MP4_FreeBox_sample_vide }, + { FOURCC_mp4s, MP4_ReadBox_sample_mp4s, MP4_FreeBox_Common }, /* XXX there is 2 box where we could find this entry stbl and tref*/ @@ -2277,6 +2449,7 @@ static struct { FOURCC_dpnd, MP4_ReadBox_default, NULL }, { FOURCC_ipir, MP4_ReadBox_default, NULL }, { FOURCC_mpod, MP4_ReadBox_default, NULL }, + { FOURCC_chap, MP4_ReadBox_tref_generic, MP4_FreeBox_tref_generic }, /* found in hnti */ { FOURCC_rtp, MP4_ReadBox_default, NULL }, @@ -2323,6 +2496,11 @@ static struct { FOURCC_0xa9ope,MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx }, { FOURCC_0xa9com,MP4_ReadBox_0xa9xxx, MP4_FreeBox_0xa9xxx }, + { FOURCC_chpl, MP4_ReadBox_chpl, MP4_FreeBox_chpl }, + + /* iTunes/Quicktime meta info */ + { FOURCC_meta, MP4_ReadBox_meta, MP4_FreeBox_Common }, + /* Last entry */ { 0, MP4_ReadBox_default, NULL } }; @@ -2583,8 +2761,9 @@ static void __get_token( char **ppsz_path, char **ppsz_token, int *pi_number ) } static void __MP4_BoxGet( MP4_Box_t **pp_result, - MP4_Box_t *p_box, char *psz_fmt, va_list args) + MP4_Box_t *p_box, const char *psz_fmt, va_list args) { + char *psz_dup; char *psz_path; if( !p_box ) @@ -2597,13 +2776,13 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, if( !psz_path || !psz_path[0] ) { - FREE( psz_path ); + FREENULL( psz_path ); *pp_result = NULL; return; } // fprintf( stderr, "path:'%s'\n", psz_path ); - psz_fmt = psz_path; /* keep this pointer, as it need to be unallocated */ + psz_dup = psz_path; /* keep this pointer, as it need to be unallocated */ for( ; ; ) { char *psz_token; @@ -2614,8 +2793,8 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, // psz_path,psz_token,i_number ); if( !psz_token ) { - FREE( psz_token ); - free( psz_fmt ); + FREENULL( psz_token ); + free( psz_dup ); *pp_result = p_box; return; } @@ -2630,7 +2809,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, if( !p_box ) { free( psz_token ); - free( psz_fmt ); + free( psz_dup ); *pp_result = NULL; return; } @@ -2647,7 +2826,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, if( !p_box ) { free( psz_token ); - free( psz_fmt ); + free( psz_dup ); *pp_result = NULL; return; } @@ -2664,7 +2843,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, if( !p_box ) { free( psz_token ); - free( psz_fmt ); + free( psz_dup ); *pp_result = NULL; return; } @@ -2688,7 +2867,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, if( !p_box ) { free( psz_token ); - free( psz_fmt ); + free( psz_dup ); *pp_result = NULL; return; } @@ -2703,8 +2882,8 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, else { // fprintf( stderr, "Argg malformed token \"%s\"",psz_token ); - FREE( psz_token ); - free( psz_fmt ); + FREENULL( psz_token ); + free( psz_dup ); *pp_result = NULL; return; } @@ -2722,7 +2901,7 @@ static void __MP4_BoxGet( MP4_Box_t **pp_result, * ex: /moov/trak[12] * ../mdia *****************************************************************************/ -MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, char *psz_fmt, ... ) +MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, const char *psz_fmt, ... ) { va_list args; MP4_Box_t *p_result; @@ -2743,7 +2922,7 @@ MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, char *psz_fmt, ... ) * ex: /moov/trak[12] * ../mdia *****************************************************************************/ -int MP4_BoxCount( MP4_Box_t *p_box, char *psz_fmt, ... ) +int MP4_BoxCount( MP4_Box_t *p_box, const char *psz_fmt, ... ) { va_list args; int i_count;