X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput_dec.c;h=ca5b6921be06310f841d38d6e50ef12f0bf11af9;hb=291bf7393437338c337e1a8654cfaa06ce2f8cba;hp=2b10010eea37a8a2f4f7af774ad3dbcef8b67bf1;hpb=89fd537f7dbd6775d9fd3b6295e4a3bf1a61bbf7;p=vlc diff --git a/src/input/input_dec.c b/src/input/input_dec.c index 2b10010eea..ca5b6921be 100644 --- a/src/input/input_dec.c +++ b/src/input/input_dec.c @@ -1,8 +1,8 @@ /***************************************************************************** * input_dec.c: Functions for the management of decoders ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: input_dec.c,v 1.79 2003/11/24 23:22:01 gbazin Exp $ + * Copyright (C) 1999-2004 VideoLAN + * $Id: input_dec.c,v 1.93 2004/03/03 11:12:08 massiot Exp $ * * Authors: Christophe Massiot * Gildas Bazin @@ -43,6 +43,7 @@ static void input_NullPacket( input_thread_t *, es_descriptor_t * ); static decoder_t * CreateDecoder( input_thread_t *, es_descriptor_t *, int ); static int DecoderThread( decoder_t * ); +static int DecoderDecode( decoder_t * p_dec, block_t *p_block ); static void DeleteDecoder( decoder_t * ); /* Buffers allocation callbacks for the decoders */ @@ -58,12 +59,15 @@ static es_format_t null_es_format = {0}; struct decoder_owner_sys_t { + vlc_bool_t b_own_thread; + aout_instance_t *p_aout; aout_input_t *p_aout_input; vout_thread_t *p_vout; - sout_packetizer_input_t *p_sout; + sout_instance_t *p_sout; + sout_packetizer_input_t *p_sout_input; /* Current format in use by the output */ video_format_t video; @@ -75,47 +79,34 @@ struct decoder_owner_sys_t /* */ input_buffers_t *p_method_data; + es_descriptor_t *p_es_descriptor; }; -/***************************************************************************** - * input_RunDecoder: spawns a new decoder thread - *****************************************************************************/ +/** + * Spawns a new decoder thread + * + * \param p_input the input thread + * \param p_es the es descriptor + * \return the spawned decoder object + */ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) { decoder_t *p_dec = NULL; vlc_value_t val; - int i_priority; /* If we are in sout mode, search for packetizer module */ - var_Get( p_input, "sout", &val ); - if( !p_es->b_force_decoder && val.psz_string && *val.psz_string ) + if( !p_es->b_force_decoder && p_input->stream.p_sout ) { - free( val.psz_string ); - val.b_bool = VLC_TRUE; - - if( p_es->i_cat == AUDIO_ES ) - { - var_Get( p_input, "sout-audio", &val ); - } - else if( p_es->i_cat == VIDEO_ES ) + /* Create the decoder configuration structure */ + p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_PACKETIZER ); + if( p_dec == NULL ) { - var_Get( p_input, "sout-video", &val ); + msg_Err( p_input, "could not create packetizer" ); + return NULL; } - if( val.b_bool ) - { - /* Create the decoder configuration structure */ - p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_PACKETIZER ); - if( p_dec == NULL ) - { - msg_Err( p_input, "could not create packetizer" ); - return NULL; - } - - p_dec->p_module = - module_Need( p_dec, "packetizer", "$packetizer" ); - } + p_dec->p_module = module_Need( p_dec, "packetizer", "$packetizer" ); } else { @@ -129,11 +120,9 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) /* default Get a suitable decoder module */ p_dec->p_module = module_Need( p_dec, "decoder", "$codec" ); - - if( val.psz_string ) free( val.psz_string ); } - if( !p_dec || !p_dec->p_module ) + if( !p_dec->p_module ) { msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n" "VLC probably does not support this sound or video format.", @@ -144,25 +133,32 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) return NULL; } - if ( p_es->i_cat == AUDIO_ES ) - { - i_priority = VLC_THREAD_PRIORITY_AUDIO; - } - else - { - i_priority = VLC_THREAD_PRIORITY_VIDEO; - } + var_Get( p_input, "minimize-threads", &val ); + p_dec->p_owner->b_own_thread = val.b_bool ? VLC_FALSE : VLC_TRUE; - /* Spawn the decoder thread */ - if( vlc_thread_create( p_dec, "decoder", DecoderThread, - i_priority, VLC_FALSE ) ) + if( p_dec->p_owner->b_own_thread ) { - msg_Err( p_dec, "cannot spawn decoder thread \"%s\"", - p_dec->p_module->psz_object_name ); - module_Unneed( p_dec, p_dec->p_module ); - DeleteDecoder( p_dec ); - vlc_object_destroy( p_dec ); - return NULL; + int i_priority; + if ( p_es->i_cat == AUDIO_ES ) + { + i_priority = VLC_THREAD_PRIORITY_AUDIO; + } + else + { + i_priority = VLC_THREAD_PRIORITY_VIDEO; + } + + /* Spawn the decoder thread */ + if( vlc_thread_create( p_dec, "decoder", DecoderThread, + i_priority, VLC_FALSE ) ) + { + msg_Err( p_dec, "cannot spawn decoder thread \"%s\"", + p_dec->p_module->psz_object_name ); + module_Unneed( p_dec, p_dec->p_module ); + DeleteDecoder( p_dec ); + vlc_object_destroy( p_dec ); + return NULL; + } } p_input->stream.b_changed = 1; @@ -170,9 +166,13 @@ decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) return p_dec; } -/***************************************************************************** - * input_EndDecoder: kills a decoder thread and waits until it's finished - *****************************************************************************/ +/** + * Kills a decoder thread and waits until it's finished + * + * \param p_input the input thread + * \param p_es the es descriptor + * \return nothing + */ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) { decoder_t *p_dec = p_es->p_dec; @@ -180,31 +180,37 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) p_dec->b_die = VLC_TRUE; - /* Make sure the thread leaves the NextDataPacket() function by - * sending it a few null packets. */ - for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ ) + if( p_dec->p_owner->b_own_thread ) { - input_NullPacket( p_input, p_es ); - } - - if( p_es->p_pes != NULL ) - { - input_DecodePES( p_es->p_dec, p_es->p_pes ); - } + /* Make sure the thread leaves the NextDataPacket() function by + * sending it a few null packets. */ + for( i_dummy = 0; i_dummy < PADDING_PACKET_NUMBER; i_dummy++ ) + { + input_NullPacket( p_input, p_es ); + } - /* Waiting for the thread to exit */ - /* I thought that unlocking was better since thread join can be long - * but it actually creates late pictures and freezes --stef */ - /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */ - vlc_thread_join( p_dec ); - /* vlc_mutex_lock( &p_input->stream.stream_lock ); */ + if( p_es->p_pes != NULL ) + { + input_DecodePES( p_es->p_dec, p_es->p_pes ); + } + /* Waiting for the thread to exit */ + /* I thought that unlocking was better since thread join can be long + * but it actually creates late pictures and freezes --stef */ + /* vlc_mutex_unlock( &p_input->stream.stream_lock ); */ + vlc_thread_join( p_dec ); + /* vlc_mutex_lock( &p_input->stream.stream_lock ); */ #if 0 - /* XXX We don't do it here because of dll loader that want close in the - * same thread than open/decode */ - /* Unneed module */ - module_Unneed( p_dec, p_dec->p_module ); + /* XXX We don't do it here because of dll loader that want close in the + * same thread than open/decode */ + /* Unneed module */ + module_Unneed( p_dec, p_dec->p_module ); #endif + } + else + { + module_Unneed( p_dec, p_dec->p_module ); + } /* Delete decoder configuration */ DeleteDecoder( p_dec ); @@ -218,11 +224,13 @@ void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es ) p_input->stream.b_changed = 1; } -/***************************************************************************** - * input_DecodePES - ***************************************************************************** +/** * Put a PES in the decoder's fifo. - *****************************************************************************/ + * + * \param p_dec the decoder object + * \param p_pes the pes packet + * \return nothing + */ void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes ) { data_packet_t *p_data; @@ -249,44 +257,68 @@ void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes ) } p_block->i_pts = p_pes->i_pts; p_block->i_dts = p_pes->i_dts; - p_block->b_discontinuity = p_pes->b_discontinuity; + if( p_pes->b_discontinuity ) + p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY; + p_block->i_rate = p_pes->i_rate; - block_FifoPut( p_dec->p_owner->p_fifo, p_block ); + input_DecodeBlock( p_dec, p_block ); } } input_DeletePES( p_dec->p_owner->p_method_data, p_pes ); } -/***************************************************************************** - * input_DecodeBlock - ***************************************************************************** + +/** * Put a block_t in the decoder's fifo. - *****************************************************************************/ + * + * \param p_dec the decoder object + * \param p_block the data block + */ void input_DecodeBlock( decoder_t * p_dec, block_t *p_block ) { - block_FifoPut( p_dec->p_owner->p_fifo, p_block ); + if( p_dec->p_owner->b_own_thread ) + { + block_FifoPut( p_dec->p_owner->p_fifo, p_block ); + } + else + { + if( p_dec->b_error || p_block->i_buffer <= 0 ) + { + block_Release( p_block ); + } + else + { + DecoderDecode( p_dec, p_block ); + } + } } -/***************************************************************************** +/** * Create a NULL packet for padding in case of a data loss - *****************************************************************************/ + * + * \param p_input the input thread + * \param p_es es descriptor + * \return nothing + */ static void input_NullPacket( input_thread_t * p_input, es_descriptor_t * p_es ) { block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE ); - if( p_block ) { memset( p_block->p_buffer, 0, PADDING_PACKET_SIZE ); - p_block->b_discontinuity = 1; + p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY; block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block ); } } -/***************************************************************************** - * input_EscapeDiscontinuity: send a NULL packet to the decoders - *****************************************************************************/ +/** + * Send a NULL packet to the decoders + * + * \param p_input the input thread + * \return nothing + */ void input_EscapeDiscontinuity( input_thread_t * p_input ) { unsigned int i_es, i; @@ -305,9 +337,12 @@ void input_EscapeDiscontinuity( input_thread_t * p_input ) } } -/***************************************************************************** - * input_EscapeAudioDiscontinuity: send a NULL packet to the audio decoders - *****************************************************************************/ +/** + * Send a NULL packet to the audio decoders + * + * \param p_input the input thread + * \return nothing + */ void input_EscapeAudioDiscontinuity( input_thread_t * p_input ) { unsigned int i_es, i; @@ -326,9 +361,14 @@ void input_EscapeAudioDiscontinuity( input_thread_t * p_input ) } } -/***************************************************************************** - * CreateDecoder: create a decoder object - *****************************************************************************/ +/** + * Create a decoder object + * + * \param p_input the input thread + * \param p_es the es descriptor + * \param i_object_type Object type as define in include/vlc_objects.h + * \return the decoder object + */ static decoder_t * CreateDecoder( input_thread_t * p_input, es_descriptor_t * p_es, int i_object_type ) { @@ -421,10 +461,13 @@ static decoder_t * CreateDecoder( input_thread_t * p_input, msg_Err( p_dec, "out of memory" ); return NULL; } + p_dec->p_owner->b_own_thread = VLC_TRUE; p_dec->p_owner->p_aout = NULL; p_dec->p_owner->p_aout_input = NULL; p_dec->p_owner->p_vout = NULL; - p_dec->p_owner->p_sout = NULL; + p_dec->p_owner->p_sout = p_input->stream.p_sout; + p_dec->p_owner->p_sout_input = NULL; + p_dec->p_owner->p_es_descriptor = p_es; /* decoder fifo */ if( ( p_dec->p_owner->p_fifo = block_FifoNew( p_dec ) ) == NULL ) { @@ -446,9 +489,12 @@ static decoder_t * CreateDecoder( input_thread_t * p_input, return p_dec; } -/***************************************************************************** - * DecoderThread: the decoding main loop - *****************************************************************************/ +/** + * The decoding main loop + * + * \param p_dec the decoder + * \return 0 + */ static int DecoderThread( decoder_t * p_dec ) { block_t *p_block; @@ -461,117 +507,159 @@ static int DecoderThread( decoder_t * p_dec ) p_dec->b_error = 1; break; } + if( p_block->i_buffer <= 0 ) + { + block_Release( p_block ); + continue; + } + if( DecoderDecode( p_dec, p_block ) ) + { + break; + } + } - if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) + while( !p_dec->b_die ) + { + /* Trash all received PES packets */ + p_block = block_FifoGet( p_dec->p_owner->p_fifo ); + if( p_block ) { - block_t *p_sout_block; + block_Release( p_block ); + } + } - while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) ) - { - if( !p_dec->p_owner->p_sout ) - { - es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out ); + /* XXX We do it here because of dll loader that want close in the + * same thread than open/decode */ + /* Unneed module */ + module_Unneed( p_dec, p_dec->p_module ); - p_dec->p_owner->p_sout = - sout_InputNew( p_dec, &p_dec->p_owner->sout ); + return 0; +} - if( p_dec->p_owner->p_sout == NULL ) - { - msg_Err( p_dec, "cannot create packetizer output" ); - p_dec->b_error = VLC_TRUE; - - while( p_sout_block ) - { - block_t *p_next = p_sout_block->p_next; - block_Release( p_sout_block ); - p_sout_block = p_next; - } - break; - } +/** + * Decode a block + * + * \param p_dec the decoder object + * \param p_block the block to decode + * \return VLC_SUCCESS or an error code + */ +static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) +{ + if( p_block->i_buffer <= 0 ) + { + block_Release( p_block ); + return VLC_SUCCESS; + } + + if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) + { + block_t *p_sout_block; + + while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) ) + { + if( !p_dec->p_owner->p_sout_input ) + { + es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out ); + if( p_dec->p_owner->p_es_descriptor->p_pgrm ) + { + p_dec->p_owner->sout.i_group = + p_dec->p_owner->p_es_descriptor->p_pgrm->i_number; + } + p_dec->p_owner->sout.i_id = p_dec->p_owner->p_es_descriptor->i_id - 1; + if( p_dec->fmt_in.psz_language ) + { + p_dec->p_owner->sout.psz_language = strdup( p_dec->fmt_in.psz_language ); } - while( p_sout_block ) + p_dec->p_owner->p_sout_input = + sout_InputNew( p_dec->p_owner->p_sout, &p_dec->p_owner->sout ); + + if( p_dec->p_owner->p_sout_input == NULL ) { - block_t *p_next = p_sout_block->p_next; - sout_buffer_t *p_sout_buffer; + msg_Err( p_dec, "cannot create packetizer output" ); + p_dec->b_error = VLC_TRUE; - p_sout_buffer = - sout_BufferNew( p_dec->p_owner->p_sout->p_sout, - p_sout_block->i_buffer ); - if( p_sout_buffer == NULL ) + while( p_sout_block ) { - msg_Err( p_dec, "cannot get sout buffer" ); - break; + block_t *p_next = p_sout_block->p_next; + block_Release( p_sout_block ); + p_sout_block = p_next; } + break; + } + } + + while( p_sout_block ) + { + block_t *p_next = p_sout_block->p_next; + sout_buffer_t *p_sout_buffer; - memcpy( p_sout_buffer->p_buffer, p_sout_block->p_buffer, - p_sout_block->i_buffer ); + p_sout_buffer = + sout_BufferNew( p_dec->p_owner->p_sout_input->p_sout, + p_sout_block->i_buffer ); + if( p_sout_buffer == NULL ) + { + msg_Err( p_dec, "cannot get sout buffer" ); + break; + } - p_sout_buffer->i_pts = p_sout_block->i_pts; - p_sout_buffer->i_dts = p_sout_block->i_dts; - p_sout_buffer->i_length = p_sout_block->i_length; + memcpy( p_sout_buffer->p_buffer, p_sout_block->p_buffer, + p_sout_block->i_buffer ); - block_Release( p_sout_block ); + p_sout_buffer->i_pts = p_sout_block->i_pts; + p_sout_buffer->i_dts = p_sout_block->i_dts; + p_sout_buffer->i_length = p_sout_block->i_length; + p_sout_buffer->i_flags = + (p_sout_block->i_flags << SOUT_BUFFER_FLAGS_BLOCK_SHIFT) + & SOUT_BUFFER_FLAGS_BLOCK_MASK; - sout_InputSendBuffer( p_dec->p_owner->p_sout, p_sout_buffer ); + block_Release( p_sout_block ); - p_sout_block = p_next; - } - } - } - else if( p_dec->fmt_in.i_cat == AUDIO_ES ) - { - aout_buffer_t *p_aout_buf; + sout_InputSendBuffer( p_dec->p_owner->p_sout_input, p_sout_buffer ); - while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) - { - aout_DecPlay( p_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, p_aout_buf ); + p_sout_block = p_next; } } - else if( p_dec->fmt_in.i_cat == VIDEO_ES ) - { - picture_t *p_pic; + } + else if( p_dec->fmt_in.i_cat == AUDIO_ES ) + { + aout_buffer_t *p_aout_buf; - while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) ) - { - vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date ); - vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); - } - } - else if( p_dec->fmt_in.i_cat == SPU_ES ) + while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) { - p_dec->pf_decode_sub( p_dec, &p_block ); - } - else - { - msg_Err( p_dec, "unknown ES format !!" ); - p_dec->b_error = 1; - break; + aout_DecPlay( p_dec->p_owner->p_aout, + p_dec->p_owner->p_aout_input, p_aout_buf ); } } - - while( !p_dec->b_die ) + else if( p_dec->fmt_in.i_cat == VIDEO_ES ) { - /* Trash all received PES packets */ - p_block = block_FifoGet( p_dec->p_owner->p_fifo ); - if( p_block ) + picture_t *p_pic; + + while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) ) { - block_Release( p_block ); + vout_DatePicture( p_dec->p_owner->p_vout, p_pic, p_pic->date ); + vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); } } + else if( p_dec->fmt_in.i_cat == SPU_ES ) + { + p_dec->pf_decode_sub( p_dec, &p_block ); + } + else + { + msg_Err( p_dec, "unknown ES format" ); + p_dec->b_error = 1; + } - /* XXX We do it here because of dll loader that want close in the - * same thread than open/decode */ - /* Unneed module */ - module_Unneed( p_dec, p_dec->p_module ); - - return 0; + return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS; } -/***************************************************************************** - * DeleteDecoder: destroys a decoder object - *****************************************************************************/ +/** + * Destroys a decoder object + * + * \param p_dec the decoder object + * \return nothing + */ static void DeleteDecoder( decoder_t * p_dec ) { vlc_object_detach( p_dec ); @@ -609,8 +697,14 @@ static void DeleteDecoder( decoder_t * p_dec ) vout_Request( p_dec, p_dec->p_owner->p_vout, 0, 0, 0, 0 ); } - if( p_dec->p_owner->p_sout ) - sout_InputDelete( p_dec->p_owner->p_sout ); + if( p_dec->p_owner->p_sout_input ) + { + sout_InputDelete( p_dec->p_owner->p_sout_input ); + if( p_dec->p_owner->sout.i_extra ) free(p_dec->p_owner->sout.p_extra); + } + + if( p_dec->fmt_in.i_extra ) free( p_dec->fmt_in.p_extra ); + if( p_dec->fmt_out.i_extra ) free( p_dec->fmt_out.p_extra ); free( p_dec->p_owner ); } @@ -701,7 +795,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) /* Get a new picture */ while( !(p_pic = vout_CreatePicture( p_sys->p_vout, 0, 0, 0 ) ) ) { - int i_pic; + int i_pic, i_ready_pic = 0; if( p_dec->b_die || p_dec->b_error ) { @@ -713,14 +807,17 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures; i_pic++ ) { + if( p_pic->i_status == READY_PICTURE && i_ready_pic++ > 0 ) break; + if( p_pic->i_status != DISPLAYED_PICTURE && - p_pic->i_status != RESERVED_PICTURE ) break; + p_pic->i_status != RESERVED_PICTURE && + p_pic->i_status != READY_PICTURE ) break; if( !p_pic->i_refcount ) break; } if( i_pic == p_dec->p_owner->p_vout->render.i_pictures ) { - msg_Err( p_dec, "decoder is leaking pictures, reseting the heap" ); + msg_Err( p_dec, "decoder is leaking pictures, resetting the heap" ); /* Just free all the pictures */ for( i_pic = 0; i_pic < p_dec->p_owner->p_vout->render.i_pictures;