* libmp4.c : LibMP4 library for mp4 module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: libmp4.c,v 1.4 2002/08/13 11:59:36 sam Exp $
+ * $Id: libmp4.c,v 1.11 2002/12/18 14:17:10 sam Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
+#include <stdarg.h>
#include <string.h> /* strdup() */
#include <errno.h>
#include <sys/types.h>
dst = GetDWBE( p_peek ); p_peek += 4; i_read -= 4
#define MP4_GETFOURCC( dst ) \
- dst = GetDWLE( p_peek ); p_peek += 4; i_read -= 4
+ 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_READBOX_ENTER( MP4_Box_data_TYPE_t ) \
- s64 i_read = p_box->i_size; \
- u8 *p_peek, *p_buff; \
+ int64_t i_read = p_box->i_size; \
+ uint8_t *p_peek, *p_buff; \
i_read = p_box->i_size; \
if( !( p_peek = p_buff = malloc( i_read ) ) ) \
{ \
return( 0 ); \
}
-
#define MP4_READBOX_EXIT( i_code ) \
- if( !i_code ) \
free( p_buff ); \
if( i_read < 0 ) \
{ \
*/
/* Some functions to manipulate memory */
-static u16 GetWLE( u8 *p_buff )
+static uint16_t GetWLE( uint8_t *p_buff )
{
return( (p_buff[0]) + ( p_buff[1] <<8 ) );
}
-static u32 GetDWLE( u8 *p_buff )
+static uint32_t GetDWLE( uint8_t *p_buff )
{
return( p_buff[0] + ( p_buff[1] <<8 ) +
( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
}
-static u16 GetWBE( u8 *p_buff )
+static uint16_t GetWBE( uint8_t *p_buff )
{
return( (p_buff[0]<<8) + p_buff[1] );
}
-static u32 Get24bBE( u8 *p_buff )
+static uint32_t Get24bBE( uint8_t *p_buff )
{
return( ( p_buff[0] <<16 ) + ( p_buff[1] <<8 ) + p_buff[2] );
}
-static u32 GetDWBE( u8 *p_buff )
+static uint32_t GetDWBE( uint8_t *p_buff )
{
return( (p_buff[0] << 24) + ( p_buff[1] <<16 ) +
( p_buff[2] <<8 ) + p_buff[3] );
}
-static u64 GetQWBE( u8 *p_buff )
+static uint64_t GetQWBE( uint8_t *p_buff )
{
- return( ( (u64)GetDWBE( p_buff ) << 32 )|( (u64)GetDWBE( p_buff + 4 ) ) );
+ return( ( (uint64_t)GetDWBE( p_buff ) << 32 )|( (uint64_t)GetDWBE( p_buff + 4 ) ) );
}
-static void GetUUID( UUID_t *p_uuid, u8 *p_buff )
+static void GetUUID( UUID_t *p_uuid, uint8_t *p_buff )
{
memcpy( p_uuid,
p_buff,
16 );
}
-static void CreateUUID( UUID_t *p_uuid, u32 i_fourcc )
+static void CreateUUID( UUID_t *p_uuid, uint32_t i_fourcc )
{
/* made by 0xXXXXXXXX-0011-0010-8000-00aa00389b71
where XXXXXXXX is the fourcc */
/* some functions for mp4 encoding of variables */
-void MP4_ConvertDate2Str( char *psz, u64 i_date )
+void MP4_ConvertDate2Str( char *psz, uint64_t i_date )
{
int i_day;
int i_hour;
vlc_mutex_lock( &p_input->stream.stream_lock );
- i_pos= p_input->stream.p_selected_area->i_tell -
- ( p_input->p_last_data - p_input->p_current_data );
+ i_pos= p_input->stream.p_selected_area->i_tell;
+// ( p_input->p_last_data - p_input->p_current_data );
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/* return 1 if success, 0 if fail */
-int MP4_ReadData( input_thread_t *p_input, u8 *p_buff, int i_size )
+int MP4_ReadData( input_thread_t *p_input, uint8_t *p_buff, int i_size )
{
data_packet_t *p_data;
*
****************************************************************************/
MP4_Stream_t *MP4_MemoryStream( input_thread_t *p_input,
- int i_size, u8 *p_buffer )
+ int i_size, uint8_t *p_buffer )
{
MP4_Stream_t *p_stream;
* MP4_ReadStream read from a MP4_Stream_t
*
****************************************************************************/
-int MP4_ReadStream( MP4_Stream_t *p_stream, u8 *p_buff, int i_size )
+int MP4_ReadStream( MP4_Stream_t *p_stream, uint8_t *p_buff, int i_size )
{
if( p_stream->b_memory )
{
* MP4_PeekStream peek from a MP4_Stream_t
*
****************************************************************************/
-int MP4_PeekStream( MP4_Stream_t *p_stream, u8 **pp_peek, int i_size )
+int MP4_PeekStream( MP4_Stream_t *p_stream, uint8_t **pp_peek, int i_size )
{
if( p_stream->b_memory )
{
int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
int i_read;
- u8 *p_peek;
+ uint8_t *p_peek;
if( ( ( i_read = MP4_PeekStream( p_stream, &p_peek, 32 ) ) < 8 ) )
{
CreateUUID( &p_box->i_uuid, p_box->i_type );
}
#ifdef MP4_VERBOSE
- /* FIXME how to write u64 ??? */
+ /* FIXME how to write uint64_t ??? */
if( p_box->i_size )
{
msg_Dbg( p_stream->p_input, "Found Box: %c%c%c%c size %d",
(p_box->i_type)&0xff, (p_box->i_type>>8)&0xff,
(p_box->i_type>>16)&0xff, (p_box->i_type>>24)&0xff,
- (u32)p_box->i_size );
+ (uint32_t)p_box->i_size );
}
#endif
MP4_Box_t *p_box;
if( MP4_TellStream( p_stream ) + 8 >
- p_container->i_pos + p_container->i_size )
+ (off_t)(p_container->i_pos + p_container->i_size) )
{
/* there is no box to load */
return( 0 );
int MP4_ReadBoxContainer( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
{
- if( p_container->i_size <= MP4_BOX_HEADERSIZE(p_container ) + 8 )
+ if( p_container->i_size <= (size_t)MP4_BOX_HEADERSIZE(p_container ) + 8 )
{
/* container is empty, 8 stand for the first header in this box */
return( 1 );
if( ( p_box->data.p_ftyp->i_compatible_brands_count = i_read / 4 ) )
{
- int i;
+ unsigned int i;
p_box->data.p_ftyp->i_compatible_brands =
- calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(u32));
+ calloc( p_box->data.p_ftyp->i_compatible_brands_count, sizeof(uint32_t));
for( i =0; i < p_box->data.p_ftyp->i_compatible_brands_count; i++ )
{
int MP4_ReadBox_mvhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
#ifdef MP4_VERBOSE
char s_creation_time[128];
char s_modification_time[128];
msg_Dbg( p_stream->p_input, "Read Box: \"mvhd\" creation %s modification %s time scale %d duration %s rate %f volume %f next track id %d",
s_creation_time,
s_modification_time,
- (u32)p_box->data.p_mvhd->i_timescale,
+ (uint32_t)p_box->data.p_mvhd->i_timescale,
s_duration,
(float)p_box->data.p_mvhd->i_rate / (1<<16 ),
(float)p_box->data.p_mvhd->i_volume / 256 ,
- (u32)p_box->data.p_mvhd->i_next_track_id );
+ (uint32_t)p_box->data.p_mvhd->i_next_track_id );
#endif
MP4_READBOX_EXIT( 1 );
}
int MP4_ReadBox_tkhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
#ifdef MP4_VERBOSE
char s_creation_time[128];
char s_modification_time[128];
int MP4_ReadBox_tref( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- if( p_box->i_size < MP4_BOX_HEADERSIZE(p_box ) + 8 )
+ if( p_box->i_size < (size_t)MP4_BOX_HEADERSIZE(p_box ) + 8 )
{
/* container is empty, 8 stand for the first header in this box */
return( 1 );
int MP4_ReadBox_mdhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
- u16 i_language;
+ unsigned int i;
+ uint16_t i_language;
#ifdef MP4_VERBOSE
char s_creation_time[128];
char s_modification_time[128];
msg_Dbg( p_stream->p_input, "Read Box: \"mdhd\" creation %s modification %s time scale %d duration %s language %c%c%c",
s_creation_time,
s_modification_time,
- (u32)p_box->data.p_mdhd->i_timescale,
+ (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],
int MP4_ReadBox_vmhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_vmhd_t );
int MP4_ReadBox_stts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stts_t );
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( sizeof( u32 ), p_box->data.p_stts->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
p_box->data.p_stts->i_sample_delta =
- calloc( sizeof( u32 ), p_box->data.p_stts->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stts->i_entry_count );
for( i = 0; (i < p_box->data.p_stts->i_entry_count )&&( i_read >=8 ); i++ )
{
int MP4_ReadBox_ctts( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_ctts_t );
MP4_GETVERSIONFLAGS( p_box->data.p_ctts );
MP4_GET4BYTES( p_box->data.p_ctts->i_entry_count );
p_box->data.p_ctts->i_sample_count =
- calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
p_box->data.p_ctts->i_sample_offset =
- calloc( sizeof( u32 ), p_box->data.p_ctts->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_ctts->i_entry_count );
for( i = 0; (i < p_box->data.p_ctts->i_entry_count )&&( i_read >=8 ); i++ )
{
FREE( p_box->data.p_ctts->i_sample_offset );
}
-static int MP4_ReadLengthDescriptor( u8 **pp_peek, s64 *i_read )
+static int MP4_ReadLengthDescriptor( uint8_t **pp_peek, int64_t *i_read )
{
- int i_b;
- int i_len = 0;
+ unsigned int i_b;
+ unsigned int i_len = 0;
do
{
i_b = **pp_peek;
int MP4_ReadBox_esds( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
#define es_descriptor p_box->data.p_esds->es_descriptor
- int i_len;
- int i_flags;
- int i_type;
+ unsigned int i_len;
+ unsigned int i_flags;
+ unsigned int i_type;
MP4_READBOX_ENTER( MP4_Box_data_esds_t );
}
if( es_descriptor.b_url )
{
- int i_len;
+ unsigned int i_len;
MP4_GET1BYTE( i_len );
es_descriptor.psz_URL = calloc( sizeof(char), i_len + 1 );
int MP4_ReadBox_sample_soun( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_sample_soun_t );
#if 0
int MP4_ReadBox_sample_mp4a( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_sample_mp4a_t );
int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_sample_vide_t );
int MP4_ReadBox_stsz( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stsz_t );
MP4_GET4BYTES( p_box->data.p_stsz->i_sample_count );
p_box->data.p_stsz->i_entry_size =
- calloc( sizeof( u32 ), p_box->data.p_stsz->i_sample_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsz->i_sample_count );
if( !p_box->data.p_stsz->i_sample_size )
{
int MP4_ReadBox_stsc( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stsc_t );
MP4_GET4BYTES( p_box->data.p_stsc->i_entry_count );
p_box->data.p_stsc->i_first_chunk =
- calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
p_box->data.p_stsc->i_samples_per_chunk =
- calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
p_box->data.p_stsc->i_sample_description_index =
- calloc( sizeof( u32 ), p_box->data.p_stsc->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsc->i_entry_count );
for( i = 0; (i < p_box->data.p_stsc->i_entry_count )&&( i_read >= 12 );i++ )
{
int MP4_ReadBox_stco_co64( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_co64_t );
MP4_GET4BYTES( p_box->data.p_co64->i_entry_count );
p_box->data.p_co64->i_chunk_offset =
- calloc( sizeof( u64 ), p_box->data.p_co64->i_entry_count );
+ calloc( sizeof( uint64_t ), p_box->data.p_co64->i_entry_count );
- for( i = 0; (i < p_box->data.p_co64->i_entry_count )&&( i_read >= 8 ); i++ )
+ for( i = 0; i < p_box->data.p_co64->i_entry_count; i++ )
{
if( p_box->i_type == FOURCC_stco )
{
+ if( i_read < 4 )
+ {
+ break;
+ }
MP4_GET4BYTES( p_box->data.p_co64->i_chunk_offset[i] );
}
else
{
+ if( i_read < 8 )
+ {
+ break;
+ }
MP4_GET8BYTES( p_box->data.p_co64->i_chunk_offset[i] );
}
}
int MP4_ReadBox_stss( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stss_t );
MP4_GET4BYTES( p_box->data.p_stss->i_entry_count );
p_box->data.p_stss->i_sample_number =
- calloc( sizeof( u32 ), p_box->data.p_stss->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stss->i_entry_count );
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]--;
}
int MP4_ReadBox_stsh( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stsh_t );
MP4_GET4BYTES( p_box->data.p_stsh->i_entry_count );
p_box->data.p_stsh->i_shadowed_sample_number =
- calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
p_box->data.p_stsh->i_sync_sample_number =
- calloc( sizeof( u32 ), p_box->data.p_stsh->i_entry_count );
+ calloc( sizeof( uint32_t ), p_box->data.p_stsh->i_entry_count );
for( i = 0; (i < p_box->data.p_stss->i_entry_count )&&( i_read >= 8 ); i++ )
int MP4_ReadBox_stdp( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_stdp_t );
MP4_GETVERSIONFLAGS( p_box->data.p_stdp );
p_box->data.p_stdp->i_priority =
- calloc( sizeof( u16 ), i_read / 2 );
+ calloc( sizeof( uint16_t ), i_read / 2 );
for( i = 0; i < i_read / 2 ; i++ )
{
#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d",
+ msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count "I64Fd,
i_read / 2 );
#endif
int MP4_ReadBox_padb( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_padb_t );
MP4_GET4BYTES( p_box->data.p_padb->i_sample_count );
p_box->data.p_padb->i_reserved1 =
- calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+ calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
p_box->data.p_padb->i_pad2 =
- calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+ calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
p_box->data.p_padb->i_reserved2 =
- calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+ calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
p_box->data.p_padb->i_pad1 =
- calloc( sizeof( u16 ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
+ calloc( sizeof( uint16_t ), ( p_box->data.p_padb->i_sample_count + 1 ) / 2 );
for( i = 0; i < i_read / 2 ; i++ )
#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count %d",
+ msg_Dbg( p_stream->p_input, "Read Box: \"stdp\" entry-count "I64Fd,
i_read / 2 );
#endif
int MP4_ReadBox_elst( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_padb_t );
MP4_GET4BYTES( p_box->data.p_elst->i_entry_count );
p_box->data.p_elst->i_segment_duration =
- calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count );
+ calloc( sizeof( uint64_t ), p_box->data.p_elst->i_entry_count );
p_box->data.p_elst->i_media_time =
- calloc( sizeof( u64 ), p_box->data.p_elst->i_entry_count );
+ calloc( sizeof( uint64_t ), p_box->data.p_elst->i_entry_count );
p_box->data.p_elst->i_media_rate_integer =
- calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count );
+ calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
p_box->data.p_elst->i_media_rate_fraction=
- calloc( sizeof( u16 ), p_box->data.p_elst->i_entry_count );
+ calloc( sizeof( uint16_t ), p_box->data.p_elst->i_entry_count );
for( i = 0; i < p_box->data.p_elst->i_entry_count; i++ )
#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "Read Box: \"elst\" entry-count %d",
+ msg_Dbg( p_stream->p_input, "Read Box: \"elst\" entry-count "I64Fd,
i_read / 2 );
#endif
int MP4_ReadBox_cprt( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i_language;
- int i;
+ unsigned int i_language;
+ unsigned int i;
MP4_READBOX_ENTER( MP4_Box_data_cprt_t );
#ifdef HAVE_ZLIB_H
z_stream z_data;
#endif
- u8 *p_data;
+ uint8_t *p_data;
int i_result;
static struct
{
- u32 i_type;
+ uint32_t i_type;
int (*MP4_ReadBox_function )( MP4_Stream_t *p_stream, MP4_Box_t *p_box );
void (*MP4_FreeBox_function )( input_thread_t *p_input, MP4_Box_t *p_box );
} MP4_Box_Function [] =
int MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box, MP4_Box_t *p_father )
{
int i_result;
- int i_index;
+ unsigned int i_index;
if( !MP4_ReadBoxCommon( p_stream, p_box ) )
{
}
return( i_result );
}
+#if 0
+/*****************************************************************************
+ * MP4_CountBox: given a box, count how many child have the requested type
+ * FIXME : support GUUID
+ *****************************************************************************/
+int MP4_CountBox( MP4_Box_t *p_box, uint32_t i_type )
+{
+ unsigned int i_count;
+ MP4_Box_t *p_child;
+
+ if( !p_box )
+ {
+ return( 0 );
+ }
+
+ i_count = 0;
+ p_child = p_box->p_first;
+ while( p_child )
+ {
+ if( p_child->i_type == i_type )
+ {
+ i_count++;
+ }
+ p_child = p_child->p_next;
+ }
+
+ return( i_count );
+}
+#endif
+
+/*****************************************************************************
+ * MP4_FindBox: find first box with i_type child of p_box
+ * return NULL if not found
+ *****************************************************************************/
+
+MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, uint32_t i_type )
+{
+ MP4_Box_t *p_child;
+
+ if( !p_box )
+ {
+ return( NULL );
+ }
+
+ p_child = p_box->p_first;
+ while( p_child )
+ {
+ if( p_child->i_type == i_type )
+ {
+ return( p_child );
+ }
+ p_child = p_child->p_next;
+ }
+
+ return( NULL );
+}
+
+
+#if 0
+/*****************************************************************************
+ * MP4_FindNextBox: find next box with thesame type and at the same level
+ * than p_box
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box )
+{
+ MP4_Box_t *p_next;
+
+ if( !p_box )
+ {
+ return( NULL );
+ }
+
+ p_next = p_box->p_next;
+ while( p_next )
+ {
+ if( p_next->i_type == p_box->i_type )
+ {
+ return( p_next );
+ }
+ p_next = p_next->p_next;
+ }
+ return( NULL );
+}
+/*****************************************************************************
+ * MP4_FindNbBox: find the box i_number
+ *****************************************************************************/
+MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, uint32_t i_number )
+{
+ MP4_Box_t *p_child = p_box->p_first;
+
+ if( !p_child )
+ {
+ return( NULL );
+ }
+
+ while( i_number )
+ {
+ if( !( p_child = p_child->p_next ) )
+ {
+ return( NULL );
+ }
+ i_number--;
+ }
+ return( p_child );
+}
+#endif
/*****************************************************************************
* MP4_FreeBox : free memory after read with MP4_ReadBox and all
* the children
*****************************************************************************/
-void MP4_FreeBox( input_thread_t *p_input, MP4_Box_t *p_box )
+void MP4_BoxFree( input_thread_t *p_input, MP4_Box_t *p_box )
{
- int i_index;
+ unsigned int i_index;
MP4_Box_t *p_child;
MP4_Box_t *p_next;
while( p_child )
{
p_next = p_child->p_next;
- MP4_FreeBox( p_input, p_child );
+ MP4_BoxFree( p_input, p_child );
/* MP4_FreeBoxChildren have free all data expect p_child itself */
free( p_child );
p_child = p_next;
}
/*****************************************************************************
- * MP4_ReadRoot : Parse the entire file, and create all boxes in memory
+ * MP4_BoxGetRoot : Parse the entire file, and create all boxes in memory
*****************************************************************************
* The first box is a virtual box "root" and is the father for all first
* level boxes for the file, a sort of virtual contener
*****************************************************************************/
-int MP4_ReadBoxRoot( input_thread_t *p_input, MP4_Box_t *p_root )
+int MP4_BoxGetRoot( input_thread_t *p_input, MP4_Box_t *p_root )
{
MP4_Stream_t *p_stream;
}
-static void __MP4_DumpBoxStructure( input_thread_t *p_input,
- MP4_Box_t *p_box, int i_level )
+static void __MP4_BoxDumpStructure( input_thread_t *p_input,
+ MP4_Box_t *p_box, unsigned int i_level )
{
MP4_Box_t *p_child;
else
{
char str[512];
- int i;
- memset( str, (u8)' ', 512 );
+ unsigned int i;
+ memset( str, (uint8_t)' ', 512 );
for( i = 0; i < i_level; i++ )
{
str[i*5] = '|';
(p_box->i_type>>8 ) &0xff,
(p_box->i_type>>16 ) &0xff,
(p_box->i_type>>24 ) &0xff,
- (u32)p_box->i_size );
+ (uint32_t)p_box->i_size );
msg_Dbg( p_input, "%s", str );
}
p_child = p_box->p_first;
while( p_child )
{
- __MP4_DumpBoxStructure( p_input, p_child, i_level + 1 );
+ __MP4_BoxDumpStructure( p_input, p_child, i_level + 1 );
p_child = p_child->p_next;
}
}
-void MP4_DumpBoxStructure( input_thread_t *p_input, MP4_Box_t *p_box )
+void MP4_BoxDumpStructure( input_thread_t *p_input, MP4_Box_t *p_box )
{
- __MP4_DumpBoxStructure( p_input, p_box, 0 );
+ __MP4_BoxDumpStructure( p_input, p_box, 0 );
}
+
/*****************************************************************************
- * MP4_CountBox: given a box, count how many child have the requested type
- * FIXME : support GUUID
+ *****************************************************************************
+ **
+ ** High level methods to acces an MP4 file
+ **
+ *****************************************************************************
*****************************************************************************/
-int MP4_CountBox( MP4_Box_t *p_box, u32 i_type )
+static void __get_token( char **ppsz_path, char **ppsz_token, int *pi_number )
{
- int i_count;
- MP4_Box_t *p_child;
-
- if( !p_box )
+ size_t i_len ;
+ if( !*ppsz_path[0] )
{
- return( 0 );
+ *ppsz_token = NULL;
+ *pi_number = 0;
+ return;
+ }
+ i_len = 0;
+ while( (*ppsz_path)[i_len] &&
+ (*ppsz_path)[i_len] != '/' && (*ppsz_path)[i_len] != '[' )
+ {
+ i_len++;
+ }
+ if( !i_len && **ppsz_path == '/' )
+ {
+ i_len = 1;
}
+ *ppsz_token = malloc( i_len + 1 );
+
+ memcpy( *ppsz_token, *ppsz_path, i_len );
- i_count = 0;
- p_child = p_box->p_first;
- while( p_child )
+ (*ppsz_token)[i_len] = '\0';
+
+ *ppsz_path += i_len;
+
+ if( **ppsz_path == '[' )
{
- if( p_child->i_type == i_type )
- {
- i_count++;
+ (*ppsz_path)++;
+ *pi_number = strtol( *ppsz_path, NULL, 10 );
+ while( **ppsz_path && **ppsz_path != ']' )
+ {
+ (*ppsz_path)++;
+ }
+ if( **ppsz_path == ']' )
+ {
+ (*ppsz_path)++;
}
- p_child = p_child->p_next;
}
-
- return( i_count );
+ else
+ {
+ *pi_number = 0;
+ }
+ while( **ppsz_path == '/' )
+ {
+ (*ppsz_path)++;
+ }
}
-
-/*****************************************************************************
- * MP4_FindBox: find first box with i_type child of p_box
- * return NULL if not found
- *****************************************************************************/
-
-MP4_Box_t *MP4_FindBox( MP4_Box_t *p_box, u32 i_type )
+static void __MP4_BoxGet( MP4_Box_t **pp_result,
+ MP4_Box_t *p_box, char *psz_fmt, va_list args)
{
- MP4_Box_t *p_child;
+ char *psz_path;
+#if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN)
+ size_t i_size;
+#endif
+
if( !p_box )
{
- return( NULL );
+ *pp_result = NULL;
+ return;
}
- p_child = p_box->p_first;
- while( p_child )
+#if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN)
+ vasprintf( &psz_path, psz_fmt, args );
+#else
+ i_size = strlen( psz_fmt ) + 1024;
+ psz_path = calloc( i_size, sizeof( char ) );
+ vsnprintf( psz_path, i_size, psz_fmt, args );
+ psz_path[i_size - 1] = 0;
+#endif
+
+ if( !psz_path || !psz_path[0] )
{
- if( p_child->i_type == i_type )
- {
- return( p_child );
+ FREE( 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 */
+ for( ; ; )
+ {
+ char *psz_token;
+ int i_number;
+
+ __get_token( &psz_path, &psz_token, &i_number );
+// fprintf( stderr, "path:'%s', token:'%s' n:%d\n",
+// psz_path,psz_token,i_number );
+ if( !psz_token )
+ {
+ FREE( psz_token );
+ free( psz_fmt );
+ *pp_result = p_box;
+ return;
}
- p_child = p_child->p_next;
+ else
+ if( !strcmp( psz_token, "/" ) )
+ {
+ /* Find root box */
+ while( p_box && p_box->i_type != VLC_FOURCC( 'r', 'o', 'o', 't' ) )
+ {
+ p_box = p_box->p_father;
+ }
+ if( !p_box )
+ {
+ free( psz_token );
+ free( psz_fmt );
+ *pp_result = NULL;
+ return;
+ }
+ }
+ else
+ if( !strcmp( psz_token, "." ) )
+ {
+ /* Do nothing */
+ }
+ else
+ if( !strcmp( psz_token, ".." ) )
+ {
+ p_box = p_box->p_father;
+ if( !p_box )
+ {
+ free( psz_token );
+ free( psz_fmt );
+ *pp_result = NULL;
+ return;
+ }
+ }
+ else
+ if( strlen( psz_token ) == 4 )
+ {
+ uint32_t i_fourcc;
+ i_fourcc = VLC_FOURCC( psz_token[0], psz_token[1],
+ psz_token[2], psz_token[3] );
+ p_box = p_box->p_first;
+ for( ; ; )
+ {
+ if( !p_box )
+ {
+ free( psz_token );
+ free( psz_fmt );
+ *pp_result = NULL;
+ return;
+ }
+ if( p_box->i_type == i_fourcc )
+ {
+ if( !i_number )
+ {
+ break;
+ }
+ i_number--;
+ }
+ p_box = p_box->p_next;
+ }
+ }
+ else
+ if( strlen( psz_token ) == 0 )
+ {
+ p_box = p_box->p_first;
+ for( ; ; )
+ {
+ if( !p_box )
+ {
+ free( psz_token );
+ free( psz_fmt );
+ *pp_result = NULL;
+ return;
+ }
+ if( !i_number )
+ {
+ break;
+ }
+ i_number--;
+ p_box = p_box->p_next;
+ }
+ }
+ else
+ {
+// fprintf( stderr, "Argg malformed token \"%s\"",psz_token );
+ FREE( psz_token );
+ free( psz_fmt );
+ *pp_result = NULL;
+ return;
+ }
+
+ free( psz_token );
}
- return( NULL );
}
-
/*****************************************************************************
- * MP4_FindNextBox: find next box with thesame type and at the same level
- * than p_box
+ * MP4_BoxGet: find a box given a path relative to p_box
+ *****************************************************************************
+ * Path Format: . .. / as usual
+ * [number] to specifie box number ex: trak[12]
+ *
+ * ex: /moov/trak[12]
+ * ../mdia
*****************************************************************************/
-MP4_Box_t *MP4_FindNextBox( MP4_Box_t *p_box )
+MP4_Box_t *MP4_BoxGet( MP4_Box_t *p_box, char *psz_fmt, ... )
{
- MP4_Box_t *p_next;
-
- if( !p_box )
- {
- return( NULL );
- }
+ va_list args;
+ MP4_Box_t *p_result;
- p_next = p_box->p_next;
- while( p_next )
- {
- if( p_next->i_type == p_box->i_type )
- {
- return( p_next );
- }
- p_next = p_next->p_next;
- }
- return( NULL );
+ va_start( args, psz_fmt );
+ __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
+ va_end( args );
+
+ return( p_result );
}
/*****************************************************************************
- * MP4_FindNbBox: find the box i_number
+ * MP4_BoxCount: count box given a path relative to p_box
+ *****************************************************************************
+ * Path Format: . .. / as usual
+ * [number] to specifie box number ex: trak[12]
+ *
+ * ex: /moov/trak[12]
+ * ../mdia
*****************************************************************************/
-MP4_Box_t *MP4_FindNbBox( MP4_Box_t *p_box, u32 i_number )
+int MP4_BoxCount( MP4_Box_t *p_box, char *psz_fmt, ... )
{
- MP4_Box_t *p_child = p_box->p_first;
-
- if( !p_child )
+ va_list args;
+ int i_count;
+ MP4_Box_t *p_result, *p_next;
+
+ va_start( args, psz_fmt );
+ __MP4_BoxGet( &p_result, p_box, psz_fmt, args );
+ va_end( args );
+ if( !p_result )
{
- return( NULL );
+ return( 0 );
}
-
- while( i_number )
+
+ i_count = 1;
+ for( p_next = p_result->p_next; p_next != NULL; p_next = p_next->p_next)
{
- if( !( p_child = p_child->p_next ) )
+ if( p_next->i_type == p_result->i_type)
{
- return( NULL );
+ i_count++;
}
- i_number--;
}
- return( p_child );
+ return( i_count );
}