* libmp4.c : LibMP4 library for mp4 module for vlc
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: libmp4.c,v 1.35 2003/11/26 08:18:09 gbazin Exp $
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * $Id: libmp4.c,v 1.40 2004/01/05 12:37:52 jlj Exp $
+ *
+ * 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
#endif
#include "libmp4.h"
+#include "drms.h"
/*****************************************************************************
* Here are defined some macro to make life simpler but before using it
free( p_buff ); \
if( i_read < 0 ) \
{ \
- msg_Warn( p_stream->p_input, "Not enougth data" ); \
+ msg_Warn( p_stream->p_input, "Not enough data" ); \
} \
return( i_code )
int i_sec;
/* date begin at 1 jan 1904 */
- i_date += ((1904ULL * 365) + 17) * 24 * 60 * 60;
+ i_date += ((1904U * 365) + 17) * 24 * 60 * 60;
i_day = i_date / ( 60*60*24);
i_hour = ( i_date /( 60*60 ) ) % 60;
*****************************************************************************/
static MP4_Box_t *MP4_ReadBox( MP4_Stream_t *p_stream, MP4_Box_t *p_father );
-/*****************************************************************************
- * Some basic functions to manipulate stream more easily in vlc
- *
- * MP4_TellAbsolute get file position
- *
- * MP4_SeekAbsolute seek in the file
- *
- * MP4_ReadData read data from the file in a buffer
- *
- *****************************************************************************/
-static off_t MP4_TellAbsolute( input_thread_t *p_input )
-{
- off_t i_pos;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- i_pos= p_input->stream.p_selected_area->i_tell;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return( i_pos );
-}
-
-static int MP4_SeekAbsolute( input_thread_t *p_input, off_t i_pos)
-{
- off_t i_filepos;
-
- //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 )
- {
- msg_Warn( p_input, "seek:after end of file" );
- return VLC_EGENERIC;
- }
-
- i_filepos = MP4_TellAbsolute( p_input );
-
- 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 if success, 0 if fail */
-static int MP4_ReadData( input_thread_t *p_input, uint8_t *p_buff, int i_size )
-{
- data_packet_t *p_data;
-
- int i_read;
-
-
- if( !i_size )
- {
- return( VLC_SUCCESS );
- }
-
- do
- {
- i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 1024 ) );
- if( i_read <= 0 )
- {
- return( VLC_EGENERIC );
- }
- memcpy( p_buff, p_data->p_payload_start, i_read );
- input_DeletePacket( p_input->p_method_data, p_data );
-
- p_buff += i_read;
- i_size -= i_read;
-
- } while( i_size );
-
- return( VLC_SUCCESS );
-}
-
/*****************************************************************************
* Some basic functions to manipulate MP4_Stream_t, an abstraction o p_input
* in the way that you can read from a memory buffer or from an input
}
else
{
- return( MP4_ReadData( p_stream->p_input, p_buff, i_size ) );
+ return( stream_Read( p_stream->p_input->s, p_buff, i_size ) < i_size ? VLC_EGENERIC : VLC_SUCCESS);
}
}
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 );
+ p_stream->p_input->stream.p_selected_area->i_size - stream_Tell( p_stream->p_input->s );
if( i_size > i_max )
{
i_size = i_max;
}
}
- return( input_Peek( p_stream->p_input, pp_peek, i_size ) );
+ return( stream_Peek( p_stream->p_input->s, pp_peek, i_size ) );
}
}
}
else
{
- return( MP4_TellAbsolute( p_stream->p_input ) );
+ return( stream_Tell( p_stream->p_input->s ) );
}
}
}
else
{
- return( MP4_SeekAbsolute( p_stream->p_input, i_pos ) );
+ return( stream_Seek( p_stream->p_input->s, (int64_t)i_pos ) );
}
}
#ifdef MP4_VERBOSE
msg_Dbg( p_stream->p_input, "Found esds MPEG4ESDescr (%dBytes)",
- i_len );
+ i_len );
#endif
MP4_GET2BYTES( es_descriptor.i_ES_ID );
#ifdef MP4_VERBOSE
msg_Dbg( p_stream->p_input, "Found esds MP4DecConfigDescr (%dBytes)",
- i_len );
+ i_len );
#endif
es_descriptor.p_decConfigDescr =
#ifdef MP4_VERBOSE
msg_Dbg( p_stream->p_input, "Found esds MP4DecSpecificDescr (%dBytes)",
- i_len );
+ i_len );
#endif
es_descriptor.p_decConfigDescr->i_decoder_specific_info_len = i_len;
if( i_read < 28 )
{
i_read -= 30;
- MP4_READBOX_EXIT( 0 );
+ MP4_READBOX_EXIT( 1 );
}
for( i = 0; i < 6 ; i++ )
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 );
}
+
+ p_box->data.p_sample_soun->p_drms =
+ p_box->i_type == FOURCC_drms ? drms_alloc() : NULL;
+
+ if( p_box->data.p_sample_soun->p_drms )
+ {
+ FILE *file;
+ char *psz_homedir;
+ char *psz_filename;
+ uint32_t p_user_key[ 4 ];
+
+ int i_ret = 0;
+ vlc_bool_t b_key = VLC_FALSE;
+
+ psz_filename = NULL;
+ psz_homedir = p_stream->p_input->p_vlc->psz_homedir;
+
+#define DRMS_FILENAME "drms"
+
+ if( psz_homedir != NULL )
+ {
+ psz_filename = (char *)malloc( sizeof("/" CONFIG_DIR "/"
+ DRMS_FILENAME) +
+ strlen( psz_homedir ) );
+ if( psz_filename != NULL )
+ {
+ sprintf( psz_filename, "%s/" CONFIG_DIR "/" DRMS_FILENAME,
+ psz_homedir );
+
+ file = fopen( psz_filename, "r" );
+ if( file != NULL )
+ {
+ b_key = fread( p_user_key, sizeof(uint32_t),
+ 4, file ) == 4 ? VLC_TRUE : VLC_FALSE;
+ fclose( file );
+ }
+ }
+ }
+
+ if( b_key == VLC_FALSE )
+ {
+ i_ret = drms_get_user_key( NULL, p_user_key );
+ }
+
+ if( !i_ret )
+ {
+ if( b_key == VLC_FALSE && psz_filename != NULL )
+ {
+ file = fopen( psz_filename, "w" );
+ if( file != NULL )
+ {
+ fwrite( p_user_key, sizeof(uint32_t), 4, file );
+ fclose( file );
+ }
+ }
+
+ i_ret = drms_init( p_box->data.p_sample_soun->p_drms,
+ DRMS_INIT_UKEY, (uint8_t *)p_user_key,
+ sizeof(p_user_key) );
+ }
+
+ if( psz_filename != NULL )
+ {
+ free( (void *)psz_filename );
+ }
+
+ if( i_ret )
+ {
+ drms_free( p_box->data.p_sample_soun->p_drms );
+ p_box->data.p_sample_soun->p_drms = NULL;
+ }
+ }
+
MP4_ReadBoxContainerRaw( p_stream, p_box ); /* esds */
#ifdef MP4_VERBOSE
}
+static void MP4_FreeBox_sample_soun( MP4_Box_t *p_box )
+{
+ if( p_box->i_type == FOURCC_drms )
+ {
+ if( p_box->data.p_sample_soun->p_drms )
+ {
+ drms_free( p_box->data.p_sample_soun->p_drms );
+ }
+ }
+}
+
+
static int MP4_ReadBox_sample_vide( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
{
unsigned int i;
MP4_READBOX_EXIT( 1 );
}
+static int MP4_ReadBox_iviv( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_READBOX_ENTER( uint8_t );
+
+ if( i_read >= sizeof(uint32_t) * 4 )
+ {
+ MP4_Box_t *p_drms_box = p_box;
+
+ do
+ {
+ p_drms_box = p_drms_box->p_father;
+ } while( p_drms_box && p_drms_box->i_type != FOURCC_drms );
+
+ if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms )
+ {
+ if( drms_init( p_drms_box->data.p_sample_soun->p_drms,
+ DRMS_INIT_IVIV, p_peek, sizeof(uint32_t) * 4 ) )
+ {
+ drms_free( p_drms_box->data.p_sample_soun->p_drms );
+ p_drms_box->data.p_sample_soun->p_drms = NULL;
+ }
+ }
+ }
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_name( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_Box_t *p_drms_box = p_box;
+
+ 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 );
+
+ if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms )
+ {
+ if( drms_init( p_drms_box->data.p_sample_soun->p_drms,
+ DRMS_INIT_NAME, p_peek, strlen( p_peek ) ) )
+ {
+ drms_free( p_drms_box->data.p_sample_soun->p_drms );
+ p_drms_box->data.p_sample_soun->p_drms = NULL;
+ }
+ }
+
+ MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_priv( MP4_Stream_t *p_stream, MP4_Box_t *p_box )
+{
+ MP4_Box_t *p_drms_box = p_box;
+
+ 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 );
+
+ if( p_drms_box && p_drms_box->data.p_sample_soun->p_drms )
+ {
+ if( drms_init( p_drms_box->data.p_sample_soun->p_drms,
+ DRMS_INIT_PRIV, p_peek, i_read ) )
+ {
+ drms_free( p_drms_box->data.p_sample_soun->p_drms );
+ p_drms_box->data.p_sample_soun->p_drms = NULL;
+ }
+ }
+
+ MP4_READBOX_EXIT( 1 );
+}
+
/**** ------------------------------------------------------------------- ****/
/**** "Higher level" Functions ****/
/**** ------------------------------------------------------------------- ****/
{ FOURCC_rmqu, MP4_ReadBox_rmqu, MP4_FreeBox_Common },
{ FOURCC_rmvc, MP4_ReadBox_rmvc, MP4_FreeBox_Common },
+ { FOURCC_drms, MP4_ReadBox_sample_soun, MP4_FreeBox_sample_soun },
+ { FOURCC_sinf, MP4_ReadBoxContainer, MP4_FreeBox_Common },
+ { FOURCC_schi, MP4_ReadBoxContainer, MP4_FreeBox_Common },
+ { FOURCC_iviv, MP4_ReadBox_iviv, MP4_FreeBox_Common },
+ { FOURCC_name, MP4_ReadBox_name, MP4_FreeBox_Common },
+ { FOURCC_priv, MP4_ReadBox_priv, MP4_FreeBox_Common },
+
/* Last entry */
{ 0, NULL, NULL }
};