X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=003155ad49f6be53dd4d94da02754de632ce554f;hb=d6f0bd78c5aaae605b7894777d4d8eddb6fdaddb;hp=fda7c47a522b51f21fed03db45bfa3c5c379ce1f;hpb=a996e2cad8e232fc5c914fe3456fbd4951600203;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index fda7c47a52..003155ad49 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -137,6 +137,9 @@ struct decoder_owner_sys_t aout_buffer_t *p_audio; aout_buffer_t **pp_audio_next; + + block_t *p_block; + block_t **pp_block_next; } buffer; /* Flushing */ @@ -158,54 +161,88 @@ struct decoder_owner_sys_t #define DECODER_MAX_BUFFERING_AUDIO_DURATION (AOUT_MAX_PREPARE_TIME) #define DECODER_MAX_BUFFERING_VIDEO_DURATION (1*CLOCK_FREQ) +/* Pictures which are DECODER_BOGUS_VIDEO_DELAY or more in advance probably have + * a bogus PTS and won't be displayed */ +#define DECODER_BOGUS_VIDEO_DELAY ((mtime_t)(DEFAULT_PTS_DELAY * 30)) + +/* */ +#define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ)) + + /***************************************************************************** * Public functions *****************************************************************************/ +picture_t *decoder_NewPicture( decoder_t *p_decoder ) +{ + picture_t *p_picture = p_decoder->pf_vout_buffer_new( p_decoder ); + if( !p_picture ) + msg_Warn( p_decoder, "can't get output picture" ); + return p_picture; +} +void decoder_DeletePicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_vout_buffer_del( p_decoder, p_picture ); +} +void decoder_LinkPicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_picture_link( p_decoder, p_picture ); +} +void decoder_UnlinkPicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_picture_unlink( p_decoder, p_picture ); +} -/* decoder_GetInputAttachment: - */ -input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec, - const char *psz_name ) +aout_buffer_t *decoder_NewAudioBuffer( decoder_t *p_decoder, int i_size ) { - input_attachment_t *p_attachment; - if( input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENT, &p_attachment, psz_name ) ) + if( !p_decoder->pf_aout_buffer_new ) return NULL; - return p_attachment; + return p_decoder->pf_aout_buffer_new( p_decoder, i_size ); +} +void decoder_DeleteAudioBuffer( decoder_t *p_decoder, aout_buffer_t *p_buffer ) +{ + p_decoder->pf_aout_buffer_del( p_decoder, p_buffer ); } + +subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder ) +{ + subpicture_t *p_subpicture = p_decoder->pf_spu_buffer_new( p_decoder ); + if( !p_subpicture ) + msg_Warn( p_decoder, "can't get output subpicture" ); + return p_subpicture; +} +void decoder_DeleteSubpicture( decoder_t *p_decoder, subpicture_t *p_subpicture ) +{ + p_decoder->pf_spu_buffer_del( p_decoder, p_subpicture ); +} + /* decoder_GetInputAttachments: */ int decoder_GetInputAttachments( decoder_t *p_dec, input_attachment_t ***ppp_attachment, int *pi_attachment ) { - return input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENTS, - ppp_attachment, pi_attachment ); + if( !p_dec->pf_get_attachments ) + return VLC_EGENERIC; + + return p_dec->pf_get_attachments( p_dec, ppp_attachment, pi_attachment ); } /* decoder_GetDisplayDate: */ mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) { - decoder_owner_sys_t *p_owner = p_dec->p_owner; - - vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering || p_owner->b_paused ) - i_ts = 0; - vlc_mutex_unlock( &p_owner->lock ); - - if( !p_owner->p_clock || !i_ts ) - return i_ts; + if( !p_dec->pf_get_display_date ) + return 0; - return input_clock_GetTS( p_owner->p_clock, NULL, p_owner->p_input->i_pts_delay, i_ts ); + return p_dec->pf_get_display_date( p_dec, i_ts ); } /* decoder_GetDisplayRate: */ int decoder_GetDisplayRate( decoder_t *p_dec ) { - decoder_owner_sys_t *p_owner = p_dec->p_owner; - - if( !p_owner->p_clock ) + if( !p_dec->pf_get_display_rate ) return INPUT_RATE_DEFAULT; - return input_clock_GetRate( p_owner->p_clock ); + + return p_dec->pf_get_display_rate( p_dec ); } /** @@ -302,13 +339,8 @@ void input_DecoderDelete( decoder_t *p_dec ) } vlc_mutex_unlock( &p_owner->lock ); - /* Make sure the thread leaves the function */ - block_FifoWake( p_owner->p_fifo ); - vlc_thread_join( p_dec ); - - /* Don't module_unneed() here because of the dll loader that wants - * close() in the same thread than open()/decode() */ + module_unneed( p_dec, p_dec->p_module ); /* */ if( p_dec->p_owner->cc.b_supported ) @@ -327,6 +359,7 @@ void input_DecoderDelete( decoder_t *p_dec ) /** * Put a block_t in the decoder's fifo. + * Thread-safe w.r.t. the decoder. May be a cancellation point. * * \param p_dec the decoder object * \param p_block the data block @@ -337,17 +370,17 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block ) if( p_owner->p_input->p->b_out_pace_control ) { - /* FIXME !!!!! */ - while( vlc_object_alive( p_dec ) && - block_FifoCount( p_owner->p_fifo ) > 10 ) - { - msleep( 1000 ); - } + /* The fifo is not consummed when buffering and so will + * deadlock vlc. + * There is no need to lock as b_buffering is never modify + * inside decoder thread. */ + if( !p_owner->b_buffering ) + block_FifoPace( p_owner->p_fifo, 10, SIZE_MAX ); } else if( block_FifoSize( p_owner->p_fifo ) > 50000000 /* 50 MB */ ) { /* FIXME: ideally we would check the time amount of data - * in the fifo instead of its size. */ + * in the FIFO instead of its size. */ msg_Warn( p_dec, "decoder/packetizer fifo full (data not " "consumed quickly enough), resetting fifo!" ); block_FifoEmpty( p_owner->p_fifo ); @@ -488,7 +521,8 @@ void input_DecoderStartBuffering( decoder_t *p_dec ) p_owner->buffer.b_full = false; p_owner->buffer.i_count = 0; - assert( !p_owner->buffer.p_picture && !p_owner->buffer.p_subpic && !p_owner->buffer.p_audio ); + assert( !p_owner->buffer.p_picture && !p_owner->buffer.p_subpic && + !p_owner->buffer.p_audio && !p_owner->buffer.p_block ); p_owner->buffer.p_picture = NULL; p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; @@ -499,6 +533,10 @@ void input_DecoderStartBuffering( decoder_t *p_dec ) p_owner->buffer.p_audio = NULL; p_owner->buffer.pp_audio_next = &p_owner->buffer.p_audio; + p_owner->buffer.p_block = NULL; + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + + p_owner->b_buffering = true; vlc_cond_signal( &p_owner->wait ); @@ -560,6 +598,35 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) /***************************************************************************** * Internal functions *****************************************************************************/ +static int DecoderGetInputAttachments( decoder_t *p_dec, + input_attachment_t ***ppp_attachment, + int *pi_attachment ) +{ + return input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENTS, + ppp_attachment, pi_attachment ); +} +static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + vlc_mutex_lock( &p_owner->lock ); + if( p_owner->b_buffering || p_owner->b_paused ) + i_ts = 0; + vlc_mutex_unlock( &p_owner->lock ); + + if( !p_owner->p_clock || !i_ts ) + return i_ts; + + return input_clock_GetTS( p_owner->p_clock, NULL, p_owner->p_input->i_pts_delay, i_ts ); +} +static int DecoderGetDisplayRate( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + if( !p_owner->p_clock ) + return INPUT_RATE_DEFAULT; + return input_clock_GetRate( p_owner->p_clock ); +} /* */ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) @@ -642,6 +709,10 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->pf_picture_unlink = vout_unlink_picture; p_dec->pf_spu_buffer_new = spu_new_buffer; p_dec->pf_spu_buffer_del = spu_del_buffer; + /* */ + p_dec->pf_get_attachments = DecoderGetInputAttachments; + p_dec->pf_get_display_date = DecoderGetDisplayDate; + p_dec->pf_get_display_rate = DecoderGetDisplayRate; vlc_object_attach( p_dec, p_input ); @@ -713,6 +784,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_owner->buffer.p_picture = NULL; p_owner->buffer.p_subpic = NULL; p_owner->buffer.p_audio = NULL; + p_owner->buffer.p_block = NULL; p_owner->b_flushing = false; @@ -745,32 +817,24 @@ static void *DecoderThread( vlc_object_t *p_this ) decoder_t *p_dec = (decoder_t *)p_this; decoder_owner_sys_t *p_owner = p_dec->p_owner; - int canc = vlc_savecancel(); - /* The decoder's main loop */ - while( vlc_object_alive( p_dec ) ) + for( ;; ) { block_t *p_block = block_FifoGet( p_owner->p_fifo ); - + /* Make sure there is no cancellation point other than this one^^. + * If you need one, be sure to push cleanup of p_block. */ DecoderSignalBuffering( p_dec, p_block == NULL ); if( p_block ) { if( p_dec->b_error ) - { /* Trash all received PES packets */ block_Release( p_block ); - } - else if( DecoderProcess( p_dec, p_block ) != VLC_SUCCESS ) - break; + else + DecoderProcess( p_dec, p_block ); } } DecoderSignalBuffering( p_dec, true ); - - /* We do it here because of the dll loader that wants close() in the - * same thread than open()/decode() */ - module_unneed( p_dec, p_dec->p_module ); - vlc_restorecancel( canc ); return NULL; } @@ -1275,7 +1339,7 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, vlc_mutex_unlock( &p_owner->lock ); /* */ - const mtime_t i_max_date = mdate() + i_delay + VOUT_BOGUS_DELAY; + const mtime_t i_max_date = mdate() + i_delay + DECODER_BOGUS_VIDEO_DELAY; if( !p_picture->b_force && ( p_picture->date <= 0 || p_picture->date >= i_max_date ) ) b_reject = true; @@ -1469,18 +1533,69 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block, decoder_owner_sys_t *p_owner = p_dec->p_owner; assert( p_owner->p_clock ); + assert( !p_sout_block->p_next ); vlc_mutex_lock( &p_owner->lock ); - bool b_reject; - DecoderWaitUnblock( p_dec, &b_reject ); + if( p_owner->b_buffering || p_owner->buffer.p_block ) + { + block_ChainLastAppend( &p_owner->buffer.pp_block_next, p_sout_block ); - DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts, &p_sout_block->i_length, - &p_sout_block->i_rate, NULL, b_telx ); + p_owner->buffer.i_count++; + /* XXX it is important to be full after the first one */ + if( p_owner->buffer.i_count > 0 ) + { + p_owner->buffer.b_full = true; + vlc_cond_signal( &p_owner->wait ); + } + } - vlc_mutex_unlock( &p_owner->lock ); + for( ;; ) + { + bool b_has_more = false; + bool b_reject; + DecoderWaitUnblock( p_dec, &b_reject ); - sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); + if( p_owner->b_buffering ) + { + vlc_mutex_unlock( &p_owner->lock ); + return; + } + + /* */ + if( p_owner->buffer.p_block ) + { + p_sout_block = p_owner->buffer.p_block; + + p_owner->buffer.p_block = p_sout_block->p_next; + p_owner->buffer.i_count--; + + b_has_more = p_owner->buffer.p_block != NULL; + if( !b_has_more ) + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + } + p_sout_block->p_next = NULL; + + DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts, + &p_sout_block->i_length, + &p_sout_block->i_rate, NULL, b_telx ); + + vlc_mutex_unlock( &p_owner->lock ); + + if( !b_reject ) + sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); + else + block_Release( p_sout_block ); + + if( !b_has_more ) + break; + vlc_mutex_lock( &p_owner->lock ); + if( !p_owner->buffer.p_block ) + { + vlc_mutex_unlock( &p_owner->lock ); + break; + } + } } /* */ @@ -1527,6 +1642,14 @@ static void DecoderFlushBuffering( decoder_t *p_dec ) if( !p_owner->buffer.p_subpic ) p_owner->buffer.pp_subpic_next = &p_owner->buffer.p_subpic; } + if( p_owner->buffer.p_block ) + { + block_ChainRelease( p_owner->buffer.p_block ); + + p_owner->buffer.i_count = 0; + p_owner->buffer.p_block = NULL; + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + } } /* This function process a block for sout @@ -1755,6 +1878,7 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) return VLC_SUCCESS; } + int canc = vlc_savecancel(); #ifdef ENABLE_SOUT if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) { @@ -1806,6 +1930,7 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) DecoderSignalFlushed( p_dec ); } + vlc_restorecancel( canc ); return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS; } @@ -1848,7 +1973,7 @@ static void DeleteDecoder( decoder_t * p_dec ) /* We are about to die. Reattach video output to p_vlc. */ vout_Request( p_dec, p_owner->p_vout, NULL ); - var_SetBool( p_owner->p_input, "intf-change-vout", true ); + input_SendEventVout( p_owner->p_input ); } #ifdef ENABLE_SOUT @@ -1932,10 +2057,11 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) p_owner->audio = p_dec->fmt_out.audio; memcpy( &format, &p_owner->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 && + (format.i_original_channels&AOUT_CHAN_PHYSMASK) == + (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) ) { - if ( i_force_dolby == 1 ) + if( i_force_dolby == 1 ) { format.i_original_channels = format.i_original_channels | AOUT_CHAN_DOLBYSTEREO; @@ -2062,7 +2188,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) p_owner->p_vout = p_vout; vlc_mutex_unlock( &p_owner->lock ); - var_SetBool( p_owner->p_input, "intf-change-vout", true ); + input_SendEventVout( p_owner->p_input ); if( p_vout == NULL ) { msg_Err( p_dec, "failed to create video output" ); @@ -2144,7 +2270,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) if( p_vout ) break; - msleep( VOUT_DISPLAY_DELAY ); + msleep( DECODER_SPU_VOUT_WAIT_DURATION ); } if( !p_vout )