* libmp4.c : LibMP4 library for mp4 module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: libmp4.c,v 1.17 2003/03/11 18:57:50 fenrir Exp $
+ * $Id: libmp4.c,v 1.27 2003/05/10 11:05:52 hartman Exp $
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 ) \
+ ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
-#define MP4_BOX_DESCEND( p_box ) \
- MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) )
-
#define MP4_GET1BYTE( dst ) \
dst = *p_peek; p_peek++; i_read--
{ \
return( 0 ); \
} \
- if( !MP4_ReadStream( p_stream, p_peek, i_read ) )\
+ if( MP4_ReadStream( p_stream, p_peek, i_read ) )\
{ \
free( p_buff ); \
return( 0 ); \
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 );
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
int MP4_SeekAbsolute( input_thread_t *p_input,
- off_t i_pos)
+ off_t i_pos)
{
off_t i_filepos;
- if( i_pos >= p_input->stream.p_selected_area->i_size )
+ //msg_Warn( p_input, "seek to %lld/%lld", i_pos, p_input->stream.p_selected_area->i_size );
+
+ if( p_input->stream.p_selected_area->i_size > 0 &&
+ i_pos >= p_input->stream.p_selected_area->i_size )
{
- return( 0 );
+ msg_Warn( p_input, "seek:after end of file" );
+ return VLC_EGENERIC;
}
i_filepos = MP4_TellAbsolute( p_input );
- if( i_pos != i_filepos )
+
+ if( i_filepos == i_pos )
+ {
+ return VLC_SUCCESS;
+ }
+
+ if( p_input->stream.b_seekable &&
+ ( p_input->stream.i_method == INPUT_METHOD_FILE ||
+ i_pos - i_filepos < 0 ||
+ i_pos - i_filepos > 1024 ) )
{
input_AccessReinit( p_input );
p_input->pf_seek( p_input, i_pos );
+ return VLC_SUCCESS;
+ }
+ else if( i_pos - i_filepos > 0 )
+ {
+ data_packet_t *p_data;
+ int i_skip = i_pos - i_filepos;
+
+ msg_Warn( p_input, "will skip %d bytes, slow", i_skip );
+
+ while (i_skip > 0 )
+ {
+ int i_read;
+
+ i_read = input_SplitBuffer( p_input, &p_data,
+ __MIN( 4096, i_skip ) );
+ if( i_read < 0 )
+ {
+ msg_Warn( p_input, "seek:cannot read" );
+ return VLC_EGENERIC;
+ }
+ i_skip -= i_read;
+
+ input_DeletePacket( p_input->p_method_data, p_data );
+ if( i_read == 0 && i_skip > 0 )
+ {
+ msg_Warn( p_input, "seek:cannot read" );
+ return VLC_EGENERIC;
+ }
+ }
+ return VLC_SUCCESS;
+ }
+ else
+ {
+ msg_Warn( p_input, "seek:failed" );
+ return VLC_EGENERIC;
}
- return( 1 );
}
/* return 1 if success, 0 if fail */
if( !i_size )
{
- return( 1 );
+ return( VLC_SUCCESS );
}
do
i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
if( i_read <= 0 )
{
- return( 0 );
+ return( VLC_EGENERIC );
}
memcpy( p_buff, p_data->p_payload_start, i_read );
input_DeletePacket( p_input->p_method_data, p_data );
} while( i_size );
- return( 1 );
+ return( VLC_SUCCESS );
}
/*****************************************************************************
{
if( i_size > p_stream->i_stop - p_stream->i_start )
{
- return( 0 );
+ return( VLC_EGENERIC );
}
memcpy( p_buff,
p_stream->p_buffer + p_stream->i_start,
i_size );
p_stream->i_start += i_size;
- return( 1 );
+ return( VLC_SUCCESS );
}
else
{
}
else
{
+
+ if( p_stream->p_input->stream.p_selected_area->i_size > 0 )
+ {
+ int64_t i_max =
+ p_stream->p_input->stream.p_selected_area->i_size - MP4_TellAbsolute( p_stream->p_input );
+ if( i_size > i_max )
+ {
+ i_size = i_max;
+ }
+ }
return( input_Peek( p_stream->p_input, pp_peek, i_size ) );
}
}
if( i_pos < p_stream->i_stop )
{
p_stream->i_start = i_pos;
- return( 1 );
+ return( VLC_SUCCESS );
}
else
{
- return( 0 );
+ return( VLC_EGENERIC );
}
}
else
*****************************************************************************/
int MP4_ReadBoxCommon( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- int i_read;
+ int i_read;
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 uint64_t ??? */
if( p_box->i_size )
{
- msg_Dbg( p_stream->p_input, "Found Box: %4.4s size %d",
+ msg_Dbg( p_stream->p_input, "Found Box: %4.4s size "I64Fd,
(char*)&p_box->i_type,
- (uint32_t)p_box->i_size );
+ p_box->i_size );
}
#endif
return( 0 ); /* out of bound */
}
}
- return( MP4_SeekStream( p_stream, p_box->i_size + p_box->i_pos ) );
+ return( MP4_SeekStream( p_stream, p_box->i_size + p_box->i_pos ) ? 0 : 1 );
}
/*****************************************************************************
* MP4_MP4_GotoBox : Go to this particular box
*****************************************************************************/
int MP4_GotoBox( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
- return( MP4_SeekStream( p_stream, p_box->i_pos ) );
+ return( MP4_SeekStream( p_stream, p_box->i_pos ) ? 0 : 1 );
}
int MP4_ReadBoxContainer( MP4_Stream_t *p_stream, MP4_Box_t *p_container )
{
-
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 */
}
/* enter box */
- MP4_BOX_DESCEND( p_container );
+ MP4_SeekStream( p_stream, p_container->i_pos + MP4_BOX_HEADERSIZE( p_container ) );
return( MP4_ReadBoxContainerRaw( p_stream, p_container ) );
}
int MP4_ReadBoxSkip( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
+ /* XXX sometime moov is hiden in a free box */
+ if( p_box->p_father && p_box->p_father->i_type == VLC_FOURCC( 'r', 'o', 'o', 't' )&&
+ p_box->i_type == FOURCC_free )
+ {
+ uint8_t *p_peek;
+ int i_read;
+ vlc_fourcc_t i_fcc;
+
+ i_read = MP4_PeekStream( p_stream, &p_peek, 44 );
+
+ p_peek += MP4_BOX_HEADERSIZE( p_box ) + 4;
+ i_read -= MP4_BOX_HEADERSIZE( p_box ) + 4;
+
+ if( i_read >= 8 )
+ {
+ i_fcc = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
+
+ if( i_fcc == FOURCC_cmov || i_fcc == FOURCC_mvhd )
+ {
+ msg_Warn( p_stream->p_input, "Detected moov hidden in a free box ..." );
+
+ p_box->i_type = FOURCC_foov;
+ return MP4_ReadBoxContainer( p_stream, p_box );
+ }
+ }
+ }
/* Nothing to do */
#ifdef MP4_VERBOSE
msg_Dbg( p_stream->p_input, "Skip box: \"%4.4s\"",
MP4_READBOX_EXIT( 1 );
}
-int MP4_ReadBox_tref( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
-{
-
- 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 );
- }
-
- if( !MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) ) )
- {
- return( 0 );
- }
-
- MP4_ReadBoxContainerRaw( p_stream, p_box );
-
-#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "Read Box: \"tref\" " );
-
-#endif
- return( 1 );
-}
-
-
int MP4_ReadBox_mdhd( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
MP4_GET2BYTES( p_box->data.p_sample_soun->i_data_reference_index );
+ /*
+ * XXX hack -> produce a copy of the nearly complete chunk
+ */
+ if( i_read > 0 )
+ {
+ p_box->data.p_sample_soun->i_qt_description = i_read;
+ p_box->data.p_sample_soun->p_qt_description = malloc( i_read );
+ memcpy( p_box->data.p_sample_soun->p_qt_description,
+ p_peek,
+ i_read );
+ }
+ else
+ {
+ p_box->data.p_sample_soun->i_qt_description = 0;
+ p_box->data.p_sample_soun->p_qt_description = NULL;
+ }
+
MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_version );
MP4_GET2BYTES( p_box->data.p_sample_soun->i_qt_revision_level );
MP4_GET4BYTES( p_box->data.p_sample_soun->i_qt_vendor );
-#if 0
- for( i = 0; i < 2 ; i++ )
- {
- MP4_GET4BYTES( p_box->data.p_sample_soun->i_reserved2[i] );
- }
-#endif
-
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_GET4BYTES( p_box->data.p_sample_soun->i_bytes_per_sample );
#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "" );
msg_Dbg( p_stream->p_input,
"Read Box: \"soun\" qt3+ sample/packet=%d bytes/packet=%d bytes/frame=%d bytes/sample=%d",
p_box->data.p_sample_soun->i_sample_per_packet, p_box->data.p_sample_soun->i_bytes_per_packet,
p_box->data.p_sample_soun->i_bytes_per_frame, p_box->data.p_sample_soun->i_bytes_per_sample );
- msg_Dbg( p_stream->p_input, "" );
#endif
MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 44 );
}
p_box->data.p_sample_soun->i_bytes_per_frame = 0;
p_box->data.p_sample_soun->i_bytes_per_sample = 0;
- msg_Dbg( p_stream->p_input, "" );
- msg_Dbg( p_stream->p_input, "Read Box: \"soun\" mp4 or qt1/2 (rest=%d)", i_read );
- msg_Dbg( p_stream->p_input, "" );
+ msg_Dbg( p_stream->p_input, "Read Box: \"soun\" mp4 or qt1/2 (rest="I64Fd")", i_read );
MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
}
MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
MP4_READBOX_EXIT( 1 );
}
-#if 0
-int MP4_ReadBox_sample_mp4a( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
-{
- unsigned int i;
-
- MP4_READBOX_ENTER( MP4_Box_data_sample_mp4a_t );
-
- for( i = 0; i < 6 ; i++ )
- {
- MP4_GET1BYTE( p_box->data.p_sample_mp4a->i_reserved1[i] );
- }
-
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_data_reference_index );
-
- for( i = 0; i < 2 ; i++ )
- {
- MP4_GET4BYTES( p_box->data.p_sample_mp4a->i_reserved2[i] );
- }
-
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_channelcount );
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_samplesize );
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_predefined );
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_reserved3 );
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratehi );
- MP4_GET2BYTES( p_box->data.p_sample_mp4a->i_sampleratelo );
-
- MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 28 );
- MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
-
-#ifdef MP4_VERBOSE
- msg_Dbg( p_stream->p_input, "Read Box: \"mp4a\" in stsd channel %d sample size %d sampl rate %f",
- p_box->data.p_sample_mp4a->i_channelcount,
- p_box->data.p_sample_mp4a->i_samplesize,
- (float)p_box->data.p_sample_mp4a->i_sampleratehi +
- (float)p_box->data.p_sample_mp4a->i_sampleratelo / 65536 );
-
-#endif
- MP4_READBOX_EXIT( 1 );
-}
-#endif
int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
MP4_GET2BYTES( p_box->data.p_sample_vide->i_data_reference_index );
- MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined1 );
- MP4_GET2BYTES( p_box->data.p_sample_vide->i_reserved2 );
-
- for( i = 0; i < 3 ; i++ )
+ /*
+ * XXX hack -> produce a copy of the nearly complete chunk
+ */
+ if( i_read > 0 )
+ {
+ p_box->data.p_sample_vide->i_qt_image_description = i_read;
+ p_box->data.p_sample_vide->p_qt_image_description = malloc( i_read );
+ memcpy( p_box->data.p_sample_vide->p_qt_image_description,
+ p_peek,
+ i_read );
+ }
+ else
{
- MP4_GET4BYTES( p_box->data.p_sample_vide->i_predefined2[i] );
+ p_box->data.p_sample_vide->i_qt_image_description = 0;
+ p_box->data.p_sample_vide->p_qt_image_description = NULL;
}
+ MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_version );
+ MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_revision_level );
+ MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_vendor );
+
+ MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_temporal_quality );
+ MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_spatial_quality );
+
MP4_GET2BYTES( p_box->data.p_sample_vide->i_width );
MP4_GET2BYTES( p_box->data.p_sample_vide->i_height );
MP4_GET4BYTES( p_box->data.p_sample_vide->i_horizresolution );
MP4_GET4BYTES( p_box->data.p_sample_vide->i_vertresolution );
- MP4_GET4BYTES( p_box->data.p_sample_vide->i_reserved3 );
- MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined3 );
+ MP4_GET4BYTES( p_box->data.p_sample_vide->i_qt_data_size );
+ MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_frame_count );
memcpy( &p_box->data.p_sample_vide->i_compressorname, p_peek, 32 );
p_peek += 32; i_read -= 32;
MP4_GET2BYTES( p_box->data.p_sample_vide->i_depth );
- MP4_GET2BYTES( p_box->data.p_sample_vide->i_predefined4 );
+ MP4_GET2BYTES( p_box->data.p_sample_vide->i_qt_color_table );
MP4_SeekStream( p_stream, p_box->i_pos + MP4_BOX_HEADERSIZE( p_box ) + 78);
MP4_ReadBoxContainerRaw( p_stream, p_box );
}
memset( p_box->data.p_cmov, 0, sizeof( MP4_Box_data_cmov_t ) );
- if( !( p_box->p_father )||
- ( p_box->p_father->i_type != FOURCC_moov ) )
+ if( !p_box->p_father ||
+ ( p_box->p_father->i_type != FOURCC_moov && p_box->p_father->i_type != FOURCC_foov) )
{
msg_Warn( p_stream->p_input, "Read box: \"cmov\" box alone" );
return( 1 );
if( i_len > 0 )
{
uint32_t i;
- p_box->data.p_rdrf->psz_ref = malloc( i_len );
+ p_box->data.p_rdrf->psz_ref = malloc( i_len + 1);
for( i = 0; i < i_len; i++ )
{
MP4_GET1BYTE( p_box->data.p_rdrf->psz_ref[i] );
{ FOURCC_hnti, MP4_ReadBoxContainer, MP4_FreeBox_Common },
{ FOURCC_rmra, MP4_ReadBoxContainer, MP4_FreeBox_Common },
{ FOURCC_rmda, MP4_ReadBoxContainer, MP4_FreeBox_Common },
+ { FOURCC_tref, MP4_ReadBoxContainer, MP4_FreeBox_Common },
/* specific box */
{ FOURCC_ftyp, MP4_ReadBox_ftyp, MP4_FreeBox_ftyp },
{ FOURCC_cmov, MP4_ReadBox_cmov, MP4_FreeBox_Common },
{ FOURCC_mvhd, MP4_ReadBox_mvhd, MP4_FreeBox_Common },
{ FOURCC_tkhd, MP4_ReadBox_tkhd, MP4_FreeBox_Common },
- { FOURCC_tref, MP4_ReadBox_tref, MP4_FreeBox_Common },
{ FOURCC_mdhd, MP4_ReadBox_mdhd, MP4_FreeBox_Common },
{ FOURCC_hdlr, MP4_ReadBox_hdlr, MP4_FreeBox_hdlr },
{ FOURCC_vmhd, MP4_ReadBox_vmhd, MP4_FreeBox_Common },
{ FOURCC_raw, MP4_ReadBox_sample_soun, MP4_FreeBox_Common },
{ FOURCC_MAC3, MP4_ReadBox_sample_soun, MP4_FreeBox_Common },
{ FOURCC_MAC6, MP4_ReadBox_sample_soun, MP4_FreeBox_Common },
+ { FOURCC_Qclp, MP4_ReadBox_sample_soun, MP4_FreeBox_Common },
+ { FOURCC_samr, MP4_ReadBox_sample_soun, MP4_FreeBox_Common },
{ FOURCC_vide, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_mp4v, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_SVQ1, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_SVQ3, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_ZyGo, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_DIVX, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_h263, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_s263, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_cvid, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_3IV1, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3iv1, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_3IV2, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3iv2, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3IVD, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3ivd, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3VID, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_3vid, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_mjpa, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_mjpb, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_mjqt, NULL, NULL }, /* found in mjpa/b */
{ FOURCC_mjht, NULL, NULL },
{ FOURCC_dvc, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_dvp, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_VP31, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
+ { FOURCC_vp31, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
{ FOURCC_jpeg, MP4_ReadBox_sample_vide, MP4_FreeBox_Common },
(MP4_Box_Function[i_index].MP4_ReadBox_function)( p_stream, p_box );
}
- if( !MP4_GotoBox( p_stream, p_box ) )
- {
- return( 0 );
- }
return( i_result );
}
+
#if 0
/*****************************************************************************
* MP4_CountBox: given a box, count how many child have the requested type
/* check if there is a cmov, if so replace
compressed moov by uncompressed one */
- if( ( p_moov = MP4_FindBox( p_root, FOURCC_moov ) )&&
- ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) )
+ if( ( ( p_moov = MP4_FindBox( p_root, FOURCC_moov ) )&&
+ ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) ) ||
+ ( ( p_moov = MP4_FindBox( p_root, FOURCC_foov ) )&&
+ ( p_cmov = MP4_FindBox( p_moov, FOURCC_cmov ) ) ) )
{
/* rename the compressed moov as a box to skip */
p_moov->i_type = FOURCC_skip;
MP4_Box_t *p_box, char *psz_fmt, va_list args)
{
char *psz_path;
-#if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN)
+#if !defined(HAVE_VASPRINTF) || defined(SYS_DARWIN) || defined(SYS_BEOS)
size_t i_size;
#endif
return;
}
-#if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN)
+#if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined(SYS_BEOS)
vasprintf( &psz_path, psz_fmt, args );
#else
i_size = strlen( psz_fmt ) + 1024;