X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=21cff07c8e560bf328fb0748903aadda5e60a5ee;hb=31e0a13eb87875f0f121f63f9e92a07e24fecc31;hp=3592c0f7d7524a005c726665d9a567b3de4f14f9;hpb=9d3b03dec9f0f47b697abccbc3bab2ffb792f167;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index 3592c0f7d7..21cff07c8e 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -1,11 +1,11 @@ /***************************************************************************** * decoder.c: Functions for the management of decoders ***************************************************************************** - * Copyright (C) 1999-2004 VideoLAN + * Copyright (C) 1999-2004 the VideoLAN team * $Id$ * * Authors: Christophe Massiot - * Gildas Bazin + * Gildas Bazin * Laurent Aimar * * This program is free software; you can redistribute it and/or modify @@ -20,7 +20,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** @@ -60,6 +60,8 @@ struct decoder_owner_sys_t { vlc_bool_t b_own_thread; + int64_t i_preroll_end; + input_thread_t *p_input; aout_instance_t *p_aout; @@ -193,6 +195,9 @@ void input_DecoderDelete( decoder_t *p_dec ) } else { + /* Flush */ + input_DecoderDecode( p_dec, NULL ); + module_Unneed( p_dec, p_dec->p_module ); } @@ -235,9 +240,9 @@ void input_DecoderDecode( decoder_t * p_dec, block_t *p_block ) } else { - if( p_dec->b_error || p_block->i_buffer <= 0 ) + if( p_dec->b_error || (p_block && p_block->i_buffer <= 0) ) { - block_Release( p_block ); + if( p_block ) block_Release( p_block ); } else { @@ -273,6 +278,11 @@ vlc_bool_t input_DecoderEmpty( decoder_t * p_dec ) return VLC_TRUE; } +void input_DecoderPreroll( decoder_t *p_dec, int64_t i_preroll_end ) +{ + p_dec->p_owner->i_preroll_end = i_preroll_end; +} + #if 0 /** * Create a NULL packet for padding in case of a data loss @@ -374,7 +384,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->pf_decode_sub = 0; p_dec->pf_packetize = 0; - /* Initialize the decoder fifo */ + /* Initialize the decoder fifo */ p_dec->p_module = NULL; @@ -389,6 +399,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, return NULL; } p_dec->p_owner->b_own_thread = VLC_TRUE; + p_dec->p_owner->i_preroll_end = -1; p_dec->p_owner->p_input = p_input; p_dec->p_owner->p_aout = NULL; p_dec->p_owner->p_aout_input = NULL; @@ -418,6 +429,12 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, vlc_object_attach( p_dec, p_input ); + stats_Create( p_dec->p_parent, "decoded_audio", + VLC_VAR_INTEGER, STATS_COUNTER ); + stats_Create( p_dec->p_parent, "decoded_video", + VLC_VAR_INTEGER, STATS_COUNTER ); + stats_Create( p_dec->p_parent, "decoded_sub", + VLC_VAR_INTEGER, STATS_COUNTER ); /* Find a suitable decoder/packetizer module */ if( i_object_type == VLC_OBJECT_DECODER ) p_dec->p_module = module_Need( p_dec, "decoder", "$codec", 0 ); @@ -503,7 +520,9 @@ static int DecoderThread( decoder_t * p_dec ) */ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) { - if( p_block->i_buffer <= 0 ) + int i_rate = p_block ? p_block->i_rate : 1000; + + if( p_block && p_block->i_buffer <= 0 ) { block_Release( p_block ); return VLC_SUCCESS; @@ -513,16 +532,19 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) { block_t *p_sout_block; - while( (p_sout_block = p_dec->pf_packetize( p_dec, &p_block )) ) + while( ( p_sout_block = + p_dec->pf_packetize( p_dec, p_block ? &p_block : 0 ) ) ) { if( !p_dec->p_owner->p_sout_input ) { es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out ); - p_dec->p_owner->sout.i_group =p_dec->fmt_in.i_group; + p_dec->p_owner->sout.i_group = p_dec->fmt_in.i_group; p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id; if( p_dec->fmt_in.psz_language ) { + if( p_dec->p_owner->sout.psz_language ) + free( p_dec->p_owner->sout.psz_language ); p_dec->p_owner->sout.psz_language = strdup( p_dec->fmt_in.psz_language ); } @@ -533,7 +555,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) if( p_dec->p_owner->p_sout_input == NULL ) { - msg_Err( p_dec, "cannot create packetizer output" ); + msg_Err( p_dec, "cannot create packetizer output (%4.4s)", + (char *)&p_dec->p_owner->sout.i_codec ); p_dec->b_error = VLC_TRUE; while( p_sout_block ) @@ -548,9 +571,10 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) while( p_sout_block ) { - block_t *p_next = p_sout_block->p_next; + block_t *p_next = p_sout_block->p_next; p_sout_block->p_next = NULL; + p_sout_block->i_rate = i_rate; sout_InputSendBuffer( p_dec->p_owner->p_sout_input, p_sout_block ); @@ -585,17 +609,40 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) while( (p_packetized_block = p_packetizer->pf_packetize( p_packetizer, &p_block )) ) { + if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra ) + { + p_dec->fmt_in.i_extra = p_packetizer->fmt_out.i_extra; + p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra ); + memcpy( p_dec->fmt_in.p_extra, + p_packetizer->fmt_out.p_extra, + p_dec->fmt_in.i_extra ); + } + while( p_packetized_block ) { block_t *p_next = p_packetized_block->p_next; p_packetized_block->p_next = NULL; + p_packetized_block->i_rate = i_rate; while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_packetized_block )) ) { - aout_DecPlay( p_dec->p_owner->p_aout, - p_dec->p_owner->p_aout_input, - p_aout_buf ); + stats_UpdateInteger( p_dec->p_parent, "decoded_audio", 1 ); + /* FIXME the best would be to handle the case start_date < preroll < end_date + * but that's not easy with non raw audio stream */ + if( p_dec->p_owner->i_preroll_end > 0 && + p_aout_buf->start_date < p_dec->p_owner->i_preroll_end ) + { + aout_DecDeleteBuffer( p_dec->p_owner->p_aout, + p_dec->p_owner->p_aout_input, p_aout_buf ); + } + else + { + p_dec->p_owner->i_preroll_end = -1; + aout_DecPlay( p_dec->p_owner->p_aout, + p_dec->p_owner->p_aout_input, + p_aout_buf ); + } } p_packetized_block = p_next; @@ -604,8 +651,20 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) } else 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 ); + stats_UpdateInteger( p_dec->p_parent, "decoded_audio", 1 ); + if( p_dec->p_owner->i_preroll_end > 0 && + p_aout_buf->start_date < p_dec->p_owner->i_preroll_end ) + { + aout_DecDeleteBuffer( p_dec->p_owner->p_aout, + p_dec->p_owner->p_aout_input, p_aout_buf ); + } + else + { + p_dec->p_owner->i_preroll_end = -1; + aout_DecPlay( p_dec->p_owner->p_aout, + p_dec->p_owner->p_aout_input, + p_aout_buf ); + } } } else if( p_dec->fmt_in.i_cat == VIDEO_ES ) @@ -620,17 +679,38 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) while( (p_packetized_block = p_packetizer->pf_packetize( p_packetizer, &p_block )) ) { + if( p_packetizer->fmt_out.i_extra && !p_dec->fmt_in.i_extra ) + { + p_dec->fmt_in.i_extra = p_packetizer->fmt_out.i_extra; + p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra ); + memcpy( p_dec->fmt_in.p_extra, + p_packetizer->fmt_out.p_extra, + p_dec->fmt_in.i_extra ); + } + while( p_packetized_block ) { block_t *p_next = p_packetized_block->p_next; p_packetized_block->p_next = NULL; + p_packetized_block->i_rate = i_rate; while( (p_pic = p_dec->pf_decode_video( p_dec, &p_packetized_block )) ) { - vout_DatePicture( p_dec->p_owner->p_vout, p_pic, - p_pic->date ); - vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); + stats_UpdateInteger( p_dec->p_parent, "decoded_video", + 1 ); + if( p_dec->p_owner->i_preroll_end > 0 && + p_pic->date < p_dec->p_owner->i_preroll_end ) + { + vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic ); + } + else + { + p_dec->p_owner->i_preroll_end = -1; + vout_DatePicture( p_dec->p_owner->p_vout, p_pic, + p_pic->date ); + vout_DisplayPicture( p_dec->p_owner->p_vout, p_pic ); + } } p_packetized_block = p_next; @@ -639,8 +719,18 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) } else 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 ); + stats_UpdateInteger( p_dec->p_parent, "decoded_video", 1 ); + if( p_dec->p_owner->i_preroll_end > 0 && + p_pic->date < p_dec->p_owner->i_preroll_end ) + { + vout_DestroyPicture( p_dec->p_owner->p_vout, p_pic ); + } + else + { + p_dec->p_owner->i_preroll_end = -1; + 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 ) @@ -649,10 +739,20 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) subpicture_t *p_spu; while( (p_spu = p_dec->pf_decode_sub( p_dec, &p_block ) ) ) { + stats_UpdateInteger( p_dec->p_parent, "decoded_sub", 1 ); + if( p_dec->p_owner->i_preroll_end > 0 && + p_spu->i_start < p_dec->p_owner->i_preroll_end && + ( p_spu->i_stop <= 0 || p_spu->i_stop <= p_dec->p_owner->i_preroll_end ) ) + { + spu_DestroySubpicture( p_dec->p_owner->p_vout->p_spu, p_spu ); + continue; + } + + p_dec->p_owner->i_preroll_end = -1; p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_vout ) { - vout_DisplaySubPicture( p_vout, p_spu ); + spu_DisplaySubpicture( p_vout->p_spu, p_spu ); vlc_object_release( p_vout ); } } @@ -703,7 +803,7 @@ static void DeleteDecoder( decoder_t * p_dec ) #undef p_pic /* We are about to die. Reattach video output to p_vlc. */ - vout_Request( p_dec, p_dec->p_owner->p_vout, 0, 0, 0, 0 ); + vout_Request( p_dec, p_dec->p_owner->p_vout, 0 ); } if( p_dec->p_owner->p_sout_input ) @@ -719,7 +819,8 @@ static void DeleteDecoder( decoder_t * p_dec ) p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_vout ) { - vout_ClearOSDChannel( p_vout, p_dec->p_owner->i_spu_channel ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, + p_dec->p_owner->i_spu_channel ); vlc_object_release( p_vout ); } } @@ -764,10 +865,30 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) if( p_sys->p_aout_input == NULL ) { + audio_sample_format_t format; + int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" ); + p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec; p_sys->audio = p_dec->fmt_out.audio; + + memcpy( &format, &p_sys->audio, sizeof( audio_sample_format_t ) ); + if ( i_force_dolby && (format.i_original_channels&AOUT_CHAN_PHYSMASK) + == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) ) + { + if ( i_force_dolby == 1 ) + { + format.i_original_channels = format.i_original_channels | + AOUT_CHAN_DOLBYSTEREO; + } + else /* i_force_dolby == 2 */ + { + format.i_original_channels = format.i_original_channels & + ~AOUT_CHAN_DOLBYSTEREO; + } + } + p_sys->p_aout_input = - aout_DecNew( p_dec, &p_sys->p_aout, &p_sys->audio ); + aout_DecNew( p_dec, &p_sys->p_aout, &format ); if( p_sys->p_aout_input == NULL ) { msg_Err( p_dec, "failed to create audio output" ); @@ -808,21 +929,57 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) return NULL; } + if( !p_dec->fmt_out.video.i_visible_width || + !p_dec->fmt_out.video.i_visible_height ) + { + p_dec->fmt_out.video.i_visible_width = + p_dec->fmt_out.video.i_width; + p_dec->fmt_out.video.i_visible_height = + p_dec->fmt_out.video.i_height; + } + + if( p_dec->fmt_out.video.i_visible_height == 1088 && + var_CreateGetBool( p_dec, "hdtv-fix" ) ) + { + p_dec->fmt_out.video.i_visible_height = 1080; + p_dec->fmt_out.video.i_sar_num *= 135; + p_dec->fmt_out.video.i_sar_den *= 136; + msg_Warn( p_dec, "Fixing broken HDTV stream (display_height=1088)"); + } + + if( !p_dec->fmt_out.video.i_sar_num || + !p_dec->fmt_out.video.i_sar_den ) + { + p_dec->fmt_out.video.i_sar_num = p_dec->fmt_out.video.i_aspect * + p_dec->fmt_out.video.i_visible_height; + + p_dec->fmt_out.video.i_sar_den = VOUT_ASPECT_FACTOR * + p_dec->fmt_out.video.i_visible_width; + } + + vlc_ureduce( &p_dec->fmt_out.video.i_sar_num, + &p_dec->fmt_out.video.i_sar_den, + p_dec->fmt_out.video.i_sar_num, + p_dec->fmt_out.video.i_sar_den, 50000 ); + p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; p_sys->video = p_dec->fmt_out.video; p_sys->p_vout = vout_Request( p_dec, p_sys->p_vout, - p_sys->video.i_width, - p_sys->video.i_height, - p_sys->video.i_chroma, - p_sys->video.i_aspect ); - + &p_dec->fmt_out.video ); if( p_sys->p_vout == NULL ) { msg_Err( p_dec, "failed to create video output" ); p_dec->b_error = VLC_TRUE; return NULL; } + + if( p_sys->video.i_rmask ) + p_sys->p_vout->render.i_rmask = p_sys->video.i_rmask; + if( p_sys->video.i_gmask ) + p_sys->p_vout->render.i_gmask = p_sys->video.i_gmask; + if( p_sys->video.i_bmask ) + p_sys->p_vout->render.i_bmask = p_sys->video.i_bmask; } /* Get a new picture */ @@ -894,7 +1051,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) { decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner; vout_thread_t *p_vout = NULL; - subpicture_t *p_spu; + subpicture_t *p_subpic; int i_attempts = 30; while( i_attempts-- ) @@ -915,20 +1072,38 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) if( p_sys->p_spu_vout != p_vout ) { - p_sys->i_spu_channel = - vout_RegisterOSDChannel( p_vout ); + spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, + &p_sys->i_spu_channel ); p_sys->p_spu_vout = p_vout; } - p_spu = vout_CreateSubPicture( p_vout, p_sys->i_spu_channel, - MEMORY_SUBPICTURE ); + p_subpic = spu_CreateSubpicture( p_vout->p_spu ); + if( p_subpic ) + { + p_subpic->i_channel = p_sys->i_spu_channel; + } vlc_object_release( p_vout ); - return p_spu; + return p_subpic; } -static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_spu ) +static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic ) { - vout_DestroySubPicture( p_dec->p_owner->p_vout, p_spu ); + decoder_owner_sys_t *p_sys = (decoder_owner_sys_t *)p_dec->p_owner; + vout_thread_t *p_vout = NULL; + + p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + if( !p_vout || p_sys->p_spu_vout != p_vout ) + { + if( p_vout ) + vlc_object_release( p_vout ); + msg_Warn( p_dec, "no vout found, leaking subpicture" ); + return; + } + + spu_DestroySubpicture( p_vout->p_spu, p_subpic ); + + vlc_object_release( p_vout ); } +