X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fdemux%2Fmp4%2Fmp4.c;h=f793b1e99c746e2737c1e1a93b0f1b5e07936f45;hb=96fd5143a83ad291b446dfd0401acb929fad83d7;hp=ce10a4e8347ede081a57251dc374d8b86f8bd031;hpb=fa94ffd58d793bd89a0b47e461285d2e9ca0fae2;p=vlc diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c index ce10a4e834..f793b1e99c 100644 --- a/modules/demux/mp4/mp4.c +++ b/modules/demux/mp4/mp4.c @@ -2,14 +2,14 @@ * mp4.c : MP4 file input module for vlc ***************************************************************************** * Copyright (C) 2001 VideoLAN - * $Id: mp4.c,v 1.6 2002/11/19 17:23:21 fenrir Exp $ + * $Id: mp4.c,v 1.14 2003/01/25 17:21:40 fenrir Exp $ * Authors: Laurent Aimar - * + * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -56,7 +56,7 @@ vlc_module_begin(); vlc_module_end(); /***************************************************************************** - * Declaration of local function + * Declaration of local function *****************************************************************************/ static int MP4_TrackSynchro( input_thread_t *p_input, track_data_mp4_t *p_track ); @@ -87,27 +87,26 @@ static int MP4_DecodeSample(); * MP4Init: check file and initializes MP4 structures *****************************************************************************/ static int MP4Init( vlc_object_t * p_this ) -{ +{ input_thread_t *p_input = (input_thread_t *)p_this; uint8_t *p_peek; - uint32_t i_type; - + demux_sys_t *p_demux; - + MP4_Box_t *p_ftyp; MP4_Box_t *p_mvhd; MP4_Box_t *p_trak; - int i; + unsigned int i; /* I need to seek */ if( !p_input->stream.b_seekable ) { msg_Warn( p_input, "MP4 plugin discarded (unseekable)" ); return( -1 ); - - } + + } /* Initialize access plug-in structures. */ if( p_input->i_mtu == 0 ) { @@ -123,18 +122,18 @@ static int MP4Init( vlc_object_t * p_this ) msg_Warn( p_input, "MP4 plugin discarded (cannot peek)" ); return( -1 ); } - i_type = ( p_peek[4] ) + ( p_peek[5] << 8 ) + - ( p_peek[6] << 16 ) + ( p_peek[7] << 24); - switch( i_type ) + + + switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) ) { case( FOURCC_ftyp ): case( FOURCC_moov ): case( FOURCC_moof ): case( FOURCC_mdat ): - case( FOURCC_udta ): + case( FOURCC_udta ): case( FOURCC_free ): case( FOURCC_skip ): - case( FOURCC_wide ): + case( FOURCC_wide ): break; default: msg_Warn( p_input, "MP4 plugin discarded (not a valid file)" ); @@ -142,7 +141,7 @@ static int MP4Init( vlc_object_t * p_this ) } /* create our structure that will contains all data */ - if( !( p_input->p_demux_data = + if( !( p_input->p_demux_data = p_demux = malloc( sizeof( demux_sys_t ) ) ) ) { msg_Err( p_input, "out of memory" ); @@ -150,7 +149,7 @@ static int MP4Init( vlc_object_t * p_this ) } memset( p_demux, 0, sizeof( demux_sys_t ) ); p_input->p_demux_data = p_demux; - + /* Now load all boxes ( except raw data ) */ if( !MP4_BoxGetRoot( p_input, &p_demux->box_root ) ) @@ -191,8 +190,8 @@ static int MP4Init( vlc_object_t * p_this ) msg_Err( p_input, "MP4 plugin discarded (%d moov box)", MP4_BoxCount( &p_demux->box_root, "/moov" ) ); - MP4End( p_input ); - return( -1 ); +// MP4End( p_input ); +// return( -1 ); } if( !(p_mvhd = MP4_BoxGet( &p_demux->box_root, "/moov/mvhd" ) ) ) @@ -206,7 +205,7 @@ static int MP4Init( vlc_object_t * p_this ) p_demux->i_timescale = p_mvhd->data.p_mvhd->i_timescale; p_demux->i_duration = p_mvhd->data.p_mvhd->i_duration; } - + if( !( p_demux->i_tracks = MP4_BoxCount( &p_demux->box_root, "/moov/trak" ) ) ) { @@ -242,7 +241,7 @@ static int MP4Init( vlc_object_t * p_this ) psz_cat = "unknown"; break; } - + msg_Dbg( p_input, "adding track[Id 0x%x] %s (%s) language %c%c%c", p_demux->track[i].i_track_ID, psz_cat, @@ -257,7 +256,7 @@ static int MP4Init( vlc_object_t * p_this ) } } - + /* create one program */ vlc_mutex_lock( &p_input->stream.stream_lock ); if( input_InitStream( p_input, 0 ) == -1) @@ -276,12 +275,19 @@ static int MP4Init( vlc_object_t * p_this ) } p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; /* XXX beurk and beurk, see MP4Demux and MP4Seek */ - p_input->stream.i_mux_rate = - p_input->stream.p_selected_area->i_size / 50 / - ( p_demux->i_duration / p_demux->i_timescale ); + if( p_demux->i_duration/p_demux->i_timescale > 0 ) + { + p_input->stream.i_mux_rate = + p_input->stream.p_selected_area->i_size / 50 / + ( p_demux->i_duration / p_demux->i_timescale ); + } + else + { + p_input->stream.i_mux_rate = 0; + } vlc_mutex_unlock( &p_input->stream.stream_lock ); - - + + for( i = 0; i < p_demux->i_tracks; i++ ) { /* start decoder for this track if enable by default*/ @@ -294,20 +300,20 @@ static int MP4Init( vlc_object_t * p_this ) vlc_mutex_lock( &p_input->stream.stream_lock ); p_input->stream.p_selected_program->b_is_ok = 1; vlc_mutex_unlock( &p_input->stream.stream_lock ); - - return( 0 ); + + return( 0 ); } /***************************************************************************** - * MP4Demux: read packet and send them to decoders + * MP4Demux: read packet and send them to decoders ***************************************************************************** * TODO check for newly selected track (ie audio upt to now ) *****************************************************************************/ static int MP4Demux( input_thread_t *p_input ) { demux_sys_t *p_demux = p_input->p_demux_data; - int i_track; + unsigned int i_track; /* XXX beurk, beuRK and BEURK, but only way I've found to detect seek from interface */ @@ -395,7 +401,7 @@ static int MP4Demux( input_thread_t *p_input ) static int MP4Seek ( input_thread_t *p_input, mtime_t i_date ) { demux_sys_t *p_demux = p_input->p_demux_data; - int i_track; + unsigned int i_track; /* First update update global time */ p_demux->i_time = i_date * p_demux->i_timescale / 1000000; @@ -414,19 +420,19 @@ static int MP4Seek ( input_thread_t *p_input, mtime_t i_date ) * MP4End: frees unused data *****************************************************************************/ static void __MP4End ( vlc_object_t * p_this ) -{ +{ #define FREE( p ) \ - if( p ) { free( p ); } - int i_track; + if( p ) { free( p ); } + unsigned int i_track; input_thread_t * p_input = (input_thread_t *)p_this; demux_sys_t *p_demux = p_input->p_demux_data; - + msg_Dbg( p_input, "Freeing all memory" ); MP4_BoxFree( p_input, &p_demux->box_root ); for( i_track = 0; i_track < p_demux->i_tracks; i_track++ ) { - int i_chunk; - for( i_chunk = 0; + unsigned int i_chunk; + for( i_chunk = 0; i_chunk < p_demux->track[i_track].i_chunk_count; i_chunk++ ) { if( p_demux->track[i_track].chunk ) @@ -435,6 +441,7 @@ static void __MP4End ( vlc_object_t * p_this ) FREE(p_demux->track[i_track].chunk[i_chunk].p_sample_delta_dts ); } } + FREE( p_demux->track[i_track].chunk ); if( !p_demux->track[i_track].i_sample_size ) { @@ -442,6 +449,8 @@ static void __MP4End ( vlc_object_t * p_this ) } } FREE( p_demux->track ); + + FREE( p_input->p_demux_data ); #undef FREE } @@ -459,7 +468,7 @@ static void __MP4End ( vlc_object_t * p_this ) static int MP4_TrackSynchro( input_thread_t *p_input, track_data_mp4_t *p_track ) { demux_sys_t *p_demux = p_input->p_demux_data; - int i_chunk_last; + unsigned int i_chunk_last; MP4_Box_t *p_stss; if( !p_track->b_ok || @@ -502,9 +511,9 @@ static int MP4_TrackSynchro( input_thread_t *p_input, track_data_mp4_t *p_track /* *** Try to find nearest sync points *** */ if( ( p_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) ) { - int i_index; - msg_Dbg( p_input, - "track[Id 0x%x] using Sync Sample Box (stss)", + unsigned int i_index; + msg_Dbg( p_input, + "track[Id 0x%x] using Sync Sample Box (stss)", p_track->i_track_ID ); for( i_index = 0; i_index < p_stss->data.p_stss->i_entry_count; i_index++ ) { @@ -568,7 +577,7 @@ static void MP4_ParseTrack( input_thread_t *p_input, track_data_mp4_t *p_demux_track, MP4_Box_t * p_trak ) { - int i; + unsigned int i; MP4_Box_t *p_tkhd = MP4_BoxGet( p_trak, "tkhd" ); MP4_Box_t *p_tref = MP4_BoxGet( p_trak, "tref" ); @@ -686,8 +695,8 @@ static int MP4_CreateChunksIndex( input_thread_t *p_input, MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */ MP4_Box_t *p_stsc; - int i_chunk; - int i_index, i_last; + unsigned int i_chunk; + unsigned int i_index, i_last; if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&& @@ -894,24 +903,26 @@ static int MP4_CreateSamplesIndex( input_thread_t *p_input, static void MP4_StartDecoder( input_thread_t *p_input, track_data_mp4_t *p_demux_track ) { - MP4_Box_t *p_sample; - int i; - int i_chunk; + MP4_Box_t * p_sample; + unsigned int i; + unsigned int i_chunk; + + unsigned int i_decoder_specific_info_len; + uint8_t * p_decoder_specific_info; + pes_packet_t *p_pes_init; - int i_decoder_specific_info_len; - uint8_t *p_decoder_specific_info; - uint8_t *p_init; BITMAPINFOHEADER *p_bih; + WAVEFORMATEX *p_wf; MP4_Box_t *p_esds; - + if( (!p_demux_track->b_ok )||( p_demux_track->i_cat == UNKNOWN_ES ) ) { return; } - + msg_Dbg( p_input, "Starting decoder for track[Id 0x%x]", p_demux_track->i_track_ID ); @@ -949,7 +960,7 @@ static void MP4_StartDecoder( input_thread_t *p_input, p_demux_track->p_es->psz_desc[i] = p_demux_track->i_language[i]; } p_demux_track->p_es->psz_desc[3] = '\0'; - + p_demux_track->p_es->i_stream_id = p_demux_track->i_track_ID; /* It's a little ugly but .. there are special cases */ @@ -963,11 +974,12 @@ static void MP4_StartDecoder( input_thread_t *p_input, p_demux_track->p_es->i_fourcc = p_sample->i_type; break; } - + p_demux_track->p_es->i_cat = p_demux_track->i_cat; - + i_decoder_specific_info_len = 0; p_decoder_specific_info = NULL; + p_pes_init = NULL; /* now see if esds is present and if so create a data packet with decoder_specific_info */ @@ -1038,9 +1050,9 @@ static void MP4_StartDecoder( input_thread_t *p_input, --> bitmapinfoheader_t : width and height --> waveformatex_t : channels, samplerate, bitspersample and at the end I add p_decoder_specific_info - + TODO set more values - + */ switch( p_demux_track->i_cat ) @@ -1048,7 +1060,8 @@ static void MP4_StartDecoder( input_thread_t *p_input, case( VIDEO_ES ): /* now create a bitmapinfoheader_t for decoder and add information found in p_esds */ - p_init = malloc( sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len ); + /* XXX XXX + 16 are for avoid segfault when ffmpeg access beyong the data */ + p_init = malloc( sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len + 16 ); p_bih = (BITMAPINFOHEADER*)p_init; p_bih->biSize = sizeof( BITMAPINFOHEADER ) + i_decoder_specific_info_len; @@ -1073,49 +1086,88 @@ static void MP4_StartDecoder( input_thread_t *p_input, // fall on display size p_bih->biHeight = p_demux_track->i_height; } - + if( i_decoder_specific_info_len ) { + data_packet_t *p_data; + memcpy( p_init + sizeof( BITMAPINFOHEADER ), p_decoder_specific_info, i_decoder_specific_info_len); + + /* If stream is mpeg4 video we send specific_info, + as it's needed to decode it (vol) */ + switch( p_demux_track->p_es->i_fourcc ) + { + case VLC_FOURCC( 'm','p','4','v' ): + case VLC_FOURCC( 'D','I','V','X' ): + case VLC_FOURCC( 'd','i','v','x' ): + p_pes_init = input_NewPES( p_input->p_method_data ); + p_data = input_NewPacket( p_input->p_method_data, + i_decoder_specific_info_len); + memcpy( p_data->p_payload_start, + p_decoder_specific_info, + i_decoder_specific_info_len ); + p_pes_init->i_dts = p_pes_init->i_pts = 0; + p_pes_init->p_first = p_pes_init->p_last = p_data; + p_pes_init->i_nb_data = 1; + p_pes_init->i_pes_size = i_decoder_specific_info_len; + break; + default: + break; + } + } break; case( AUDIO_ES ): - p_init = malloc( 18 + i_decoder_specific_info_len); - memset( p_init, 0, 18 + i_decoder_specific_info_len); - MP4_Set2BytesLE( p_init + 2, /* i_channel */ - p_sample->data.p_sample_soun->i_channelcount ); - MP4_Set4BytesLE( p_init + 4, /* samplepersec */ - p_sample->data.p_sample_soun->i_sampleratehi ); - MP4_Set4BytesLE( p_init + 8, /* avgbytespersec */ - p_sample->data.p_sample_soun->i_channelcount * - p_sample->data.p_sample_soun->i_sampleratehi * - (p_sample->data.p_sample_soun->i_samplesize/8) ); - MP4_Set2BytesLE( p_init + 14, /* bits/sample */ - p_sample->data.p_sample_soun->i_samplesize ); - - MP4_Set2BytesLE( p_init + 16, /* i_size, specific info len*/ - i_decoder_specific_info_len ); + p_init = malloc( sizeof( WAVEFORMATEX ) + i_decoder_specific_info_len + 16 ); + p_wf = (WAVEFORMATEX*)p_init; + + p_wf->wFormatTag = 0; + p_wf->nChannels = p_sample->data.p_sample_soun->i_channelcount; + p_wf->nSamplesPerSec = p_sample->data.p_sample_soun->i_sampleratehi; + p_wf->nAvgBytesPerSec = p_sample->data.p_sample_soun->i_channelcount * + p_sample->data.p_sample_soun->i_sampleratehi * + p_sample->data.p_sample_soun->i_samplesize / 8; + p_wf->nBlockAlign = 0; + p_wf->wBitsPerSample = p_sample->data.p_sample_soun->i_samplesize; + p_wf->cbSize = i_decoder_specific_info_len; + if( i_decoder_specific_info_len ) { - memcpy( p_init + 18, + memcpy( p_init + sizeof( WAVEFORMATEX ), p_decoder_specific_info, i_decoder_specific_info_len); } + break; default: p_init = NULL; break; } - - p_demux_track->p_es->p_demux_data = (es_sys_t *)p_init; + if( p_demux_track->i_cat == AUDIO_ES ) + { + p_demux_track->p_es->p_waveformatex = (void*)p_init; + } + else if( p_demux_track->i_cat == VIDEO_ES ) + { + p_demux_track->p_es->p_bitmapinfoheader = (void*)p_init; + } vlc_mutex_lock( &p_input->stream.stream_lock ); input_SelectES( p_input, p_demux_track->p_es ); vlc_mutex_unlock( &p_input->stream.stream_lock ); + if( !p_demux_track->p_es->p_decoder_fifo ) + { + msg_Warn( p_input, "cannot start decoder" ); + return; + } + if( p_pes_init != NULL ) + { + input_DecodePES( p_demux_track->p_es->p_decoder_fifo, p_pes_init ); + } p_demux_track->b_ok = 1; p_demux_track->b_selected = 1; } @@ -1136,7 +1188,7 @@ static int MP4_ReadSample( input_thread_t *p_input, track_data_mp4_t *p_demux_track, pes_packet_t **pp_pes ) { - int i_size; + size_t i_size; off_t i_pos; data_packet_t *p_data;