X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=be2509c2947aef1fa3e60c50301adefc705b1c87;hb=7a76a7a7c74fa76e06aedbf334957c5603a4295a;hp=0b0cdf2ea6434c9365c0063616314f31d13c1de8;hpb=86e636577ca6ade955c1f024ff7cf61670e9c8ab;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index 0b0cdf2ea6..be2509c294 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -54,30 +54,22 @@ #include "../video_output/vout_control.h" static decoder_t *CreateDecoder( vlc_object_t *, input_thread_t *, - es_format_t *, bool, input_resource_t *, + const es_format_t *, bool, input_resource_t *, sout_instance_t *p_sout ); static void DeleteDecoder( decoder_t * ); static void *DecoderThread( void * ); static void DecoderProcess( decoder_t *, block_t * ); -static void DecoderError( decoder_t *p_dec, block_t *p_block ); -static void DecoderOutputChangePause( decoder_t *, bool b_paused, mtime_t i_date ); static void DecoderFlush( decoder_t * ); -static void DecoderSignalBuffering( decoder_t *, bool ); -static void DecoderFlushBuffering( decoder_t * ); +static void DecoderSignalWait( decoder_t * ); static void DecoderUnsupportedCodec( decoder_t *, vlc_fourcc_t ); /* Buffers allocation callbacks for the decoders */ -static aout_buffer_t *aout_new_buffer( decoder_t *, int ); - +static int vout_update_format( decoder_t * ); static picture_t *vout_new_buffer( decoder_t * ); -static void vout_del_buffer( decoder_t *, picture_t * ); -static void vout_link_picture( decoder_t *, picture_t * ); -static void vout_unlink_picture( decoder_t *, picture_t * ); - +static int aout_update_format( decoder_t * ); static subpicture_t *spu_new_buffer( decoder_t *, const subpicture_updater_t * ); -static void spu_del_buffer( decoder_t *, subpicture_t * ); struct decoder_owner_sys_t { @@ -102,13 +94,10 @@ struct decoder_owner_sys_t bool b_packetizer; /* Current format in use by the output */ - video_format_t video; - audio_format_t audio; - es_format_t sout; + es_format_t fmt; /* */ bool b_fmt_description; - es_format_t fmt_description; vlc_meta_t *p_description; /* fifo */ @@ -135,26 +124,11 @@ struct decoder_owner_sys_t int i_ignore; } pause; - /* Buffering */ - bool b_buffering; - struct - { - bool b_first; - bool b_full; - int i_count; - - picture_t *p_picture; - picture_t **pp_picture_next; - - subpicture_t *p_subpic; - subpicture_t **pp_subpic_next; - - aout_buffer_t *p_audio; - aout_buffer_t **pp_audio_next; - - block_t *p_block; - block_t **pp_block_next; - } buffer; + /* Waiting */ + bool b_woken; + bool b_waiting; + bool b_first; + bool b_has_data; /* Flushing */ bool b_flushing; @@ -171,10 +145,6 @@ struct decoder_owner_sys_t mtime_t i_ts_delay; }; -#define DECODER_MAX_BUFFERING_COUNT (4) -#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)) @@ -188,29 +158,29 @@ struct decoder_owner_sys_t *****************************************************************************/ picture_t *decoder_NewPicture( decoder_t *p_decoder ) { + if( decoder_UpdateVideoFormat( p_decoder ) ) + return NULL; + 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 ); -} -aout_buffer_t *decoder_NewAudioBuffer( decoder_t *p_decoder, int i_size ) +block_t *decoder_NewAudioBuffer( decoder_t *dec, int samples ) { - if( !p_decoder->pf_aout_buffer_new ) + if( decoder_UpdateAudioFormat( dec ) ) return NULL; - return p_decoder->pf_aout_buffer_new( p_decoder, i_size ); + + size_t length = samples * dec->fmt_out.audio.i_bytes_per_frame + / dec->fmt_out.audio.i_frame_length; + block_t *block = block_Alloc( length ); + if( likely(block != NULL) ) + { + block->i_nb_samples = samples; + block->i_pts = block->i_length = 0; + } + return block; } subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder, @@ -222,11 +192,6 @@ subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder, 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, @@ -259,7 +224,7 @@ int decoder_GetDisplayRate( decoder_t *p_dec ) /* TODO: pass p_sout through p_resource? -- Courmisch */ static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input, - es_format_t *fmt, input_clock_t *p_clock, + const es_format_t *fmt, input_clock_t *p_clock, input_resource_t *p_resource, sout_instance_t *p_sout ) { @@ -326,7 +291,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, /** * Spawn a decoder thread outside of the input thread. */ -decoder_t *input_DecoderCreate( vlc_object_t *p_parent, es_format_t *fmt, +decoder_t *input_DecoderCreate( vlc_object_t *p_parent, const es_format_t *fmt, input_resource_t *p_resource ) { return decoder_New( p_parent, NULL, fmt, NULL, p_resource, NULL ); @@ -346,18 +311,16 @@ void input_DecoderDelete( decoder_t *p_dec ) vlc_cancel( p_owner->thread ); - /* Make sure we aren't paused/buffering/waiting/decoding anymore */ + /* Make sure we aren't paused/waiting/decoding anymore */ vlc_mutex_lock( &p_owner->lock ); - const bool b_was_paused = p_owner->b_paused; p_owner->b_paused = false; - p_owner->b_buffering = false; + p_owner->b_waiting = false; p_owner->b_flushing = true; p_owner->b_exit = true; vlc_cond_signal( &p_owner->wait_request ); vlc_mutex_unlock( &p_owner->lock ); vlc_join( p_owner->thread, NULL ); - p_owner->b_paused = b_was_paused; module_unneed( p_dec, p_dec->p_module ); @@ -384,44 +347,46 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block, bool b_do_pace ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - if( b_do_pace ) - { - /* 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 ); - } -#ifdef __arm__ - else if( block_FifoSize( p_owner->p_fifo ) > 50*1024*1024 /* 50 MiB */ ) -#else - else if( block_FifoSize( p_owner->p_fifo ) > 400*1024*1024 /* 400 MiB, ie ~ 50mb/s for 60s */ ) -#endif + vlc_fifo_Lock( p_owner->p_fifo ); + if( !b_do_pace ) { /* FIXME: ideally we would check the time amount of data * 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 ); + /* 400 MiB, i.e. ~ 50mb/s for 60s */ + if( vlc_fifo_GetBytes( p_owner->p_fifo ) > 400*1024*1024 ) + { + msg_Warn( p_dec, "decoder/packetizer fifo full (data not " + "consumed quickly enough), resetting fifo!" ); + block_ChainRelease( vlc_fifo_DequeueAllUnlocked( p_owner->p_fifo ) ); + } + } + else + if( !p_owner->b_waiting ) + { /* The FIFO is not consumed when waiting, so pacing would deadlock VLC. + * Locking is not necessary as b_waiting is only read, not written by + * the decoder thread. */ + while( vlc_fifo_GetCount( p_owner->p_fifo ) >= 10 ) + vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_acknowledge ); } - block_FifoPut( p_owner->p_fifo, p_block ); + vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block ); + vlc_fifo_Unlock( p_owner->p_fifo ); } bool input_DecoderIsEmpty( decoder_t * p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - assert( !p_owner->b_buffering ); + assert( !p_owner->b_waiting ); bool b_empty = block_FifoCount( p_dec->p_owner->p_fifo ) <= 0; + if( b_empty ) { vlc_mutex_lock( &p_owner->lock ); /* TODO subtitles support */ - if( p_dec->fmt_out.i_cat == VIDEO_ES && p_owner->p_vout ) + if( p_owner->fmt.i_cat == VIDEO_ES && p_owner->p_vout ) b_empty = vout_IsEmpty( p_owner->p_vout ); - else if( p_dec->fmt_out.i_cat == AUDIO_ES && p_owner->p_aout ) + else if( p_owner->fmt.i_cat == AUDIO_ES && p_owner->p_aout ) b_empty = aout_DecIsEmpty( p_owner->p_aout ); vlc_mutex_unlock( &p_owner->lock ); } @@ -459,8 +424,8 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) es_format_t fmt; es_format_Init( &fmt, SPU_ES, fcc[i_channel] ); - p_cc = CreateDecoder( VLC_OBJECT(p_dec), p_owner->p_input, &fmt, - false, p_owner->p_resource, p_owner->p_sout ); + p_cc = input_DecoderNew( p_owner->p_input, &fmt, + p_dec->p_owner->p_clock, p_owner->p_sout ); if( !p_cc ) { msg_Err( p_dec, "could not create decoder" ); @@ -471,7 +436,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) else if( !p_cc->p_module ) { DecoderUnsupportedCodec( p_dec, fcc[i_channel] ); - DeleteDecoder( p_cc ); + input_DecoderDelete(p_cc); return VLC_EGENERIC; } p_cc->p_owner->p_clock = p_owner->p_clock; @@ -490,10 +455,7 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) vlc_mutex_unlock( &p_owner->lock ); if( p_cc ) - { - module_unneed( p_cc, p_cc->p_module ); - DeleteDecoder( p_cc ); - } + input_DecoderDelete(p_cc); } return VLC_SUCCESS; } @@ -516,16 +478,30 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date ) decoder_owner_sys_t *p_owner = p_dec->p_owner; vlc_mutex_lock( &p_owner->lock ); - - assert( p_owner->b_paused != b_paused ); - - p_owner->b_paused = b_paused; - p_owner->pause.i_date = i_date; - p_owner->pause.i_ignore = 0; - vlc_cond_signal( &p_owner->wait_request ); - - DecoderOutputChangePause( p_dec, b_paused, i_date ); - + /* Normally, p_owner->b_paused != b_paused here. But if a track is added + * while the input is paused (e.g. add sub file), then b_paused is + * (incorrectly) false. */ + if( likely(p_owner->b_paused != b_paused) ) { + p_owner->b_paused = b_paused; + p_owner->pause.i_date = i_date; + p_owner->pause.i_ignore = 0; + vlc_cond_signal( &p_owner->wait_request ); + + /* XXX only audio and video output have to be paused. + * - for sout it is useless + * - for subs, it is done by the vout + */ + if( p_dec->fmt_out.i_cat == AUDIO_ES ) + { + if( p_owner->p_aout ) + aout_DecChangePause( p_owner->p_aout, b_paused, i_date ); + } + else if( p_dec->fmt_out.i_cat == VIDEO_ES ) + { + if( p_owner->p_vout ) + vout_ChangePause( p_owner->p_vout, b_paused, i_date ); + } + } vlc_mutex_unlock( &p_owner->lock ); } @@ -538,66 +514,60 @@ void input_DecoderChangeDelay( decoder_t *p_dec, mtime_t i_delay ) vlc_mutex_unlock( &p_owner->lock ); } -void input_DecoderStartBuffering( decoder_t *p_dec ) +/** + * Requests that the decoder immediately discard all pending buffers. + * This is useful at end of stream, when seeking or when deselecting a stream. + */ +void input_DecoderFlush( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; vlc_mutex_lock( &p_owner->lock ); - DecoderFlush( p_dec ); + vlc_mutex_unlock( &p_owner->lock ); +} - p_owner->buffer.b_first = true; - 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 && !p_owner->buffer.p_block ); - - p_owner->buffer.p_picture = NULL; - p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; - - p_owner->buffer.p_subpic = NULL; - p_owner->buffer.pp_subpic_next = &p_owner->buffer.p_subpic; - - 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; - +void input_DecoderStartWait( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; - p_owner->b_buffering = true; + assert( !p_owner->b_waiting ); + vlc_mutex_lock( &p_owner->lock ); + p_owner->b_first = true; + p_owner->b_has_data = false; + p_owner->b_waiting = true; vlc_cond_signal( &p_owner->wait_request ); - vlc_mutex_unlock( &p_owner->lock ); } -void input_DecoderStopBuffering( decoder_t *p_dec ) +void input_DecoderStopWait( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - vlc_mutex_lock( &p_owner->lock ); - - p_owner->b_buffering = false; + assert( p_owner->b_waiting ); + vlc_mutex_lock( &p_owner->lock ); + p_owner->b_waiting = false; vlc_cond_signal( &p_owner->wait_request ); - vlc_mutex_unlock( &p_owner->lock ); } -void input_DecoderWaitBuffering( decoder_t *p_dec ) +void input_DecoderWait( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - vlc_mutex_lock( &p_owner->lock ); + assert( p_owner->b_waiting ); - while( p_owner->b_buffering && !p_owner->buffer.b_full ) + vlc_mutex_lock( &p_owner->lock ); + while( !p_owner->b_has_data ) { - block_FifoWake( p_owner->p_fifo ); + vlc_fifo_Lock( p_owner->p_fifo ); + p_owner->b_woken = true; + vlc_fifo_Signal( p_owner->p_fifo ); + vlc_fifo_Unlock( p_owner->p_fifo ); vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock ); } - vlc_mutex_unlock( &p_owner->lock ); } @@ -608,7 +578,7 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) *pi_duration = 0; vlc_mutex_lock( &p_owner->lock ); - if( p_dec->fmt_out.i_cat == VIDEO_ES ) + if( p_owner->fmt.i_cat == VIDEO_ES ) { if( p_owner->b_paused && p_owner->p_vout ) { @@ -620,6 +590,7 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) else { /* TODO subtitle should not be flushed */ + p_owner->b_waiting = false; DecoderFlush( p_dec ); } vlc_mutex_unlock( &p_owner->lock ); @@ -634,8 +605,8 @@ bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_me b_changed = p_owner->b_fmt_description; if( b_changed ) { - if( p_fmt ) - es_format_Copy( p_fmt, &p_owner->fmt_description ); + if( p_fmt != NULL ) + es_format_Copy( p_fmt, &p_owner->fmt ); if( pp_meta ) { @@ -692,15 +663,17 @@ 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 ) + if( p_owner->b_waiting || p_owner->b_paused ) i_ts = VLC_TS_INVALID; vlc_mutex_unlock( &p_owner->lock ); if( !p_owner->p_clock || i_ts <= VLC_TS_INVALID ) return i_ts; - if( input_clock_ConvertTS( p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) + if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) { + msg_Err(p_dec, "Could not get display date for timestamp %"PRId64"", i_ts); return VLC_TS_INVALID; + } return i_ts; } @@ -716,13 +689,19 @@ static int DecoderGetDisplayRate( decoder_t *p_dec ) /* */ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) { - msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. " - "VLC probably does not support this sound or video format.", - (char*)&codec ); - dialog_Fatal( p_dec, _("No suitable decoder module"), - _("VLC does not support the audio or video format \"%4.4s\". " - "Unfortunately there is no way for you to fix this."), - (char*)&codec ); + if (codec != VLC_FOURCC('u','n','d','f')) { + const char *desc = vlc_fourcc_GetDescription(p_dec->fmt_in.i_cat, codec); + if (!desc || !*desc) + desc = N_("No description for this codec"); + msg_Err( p_dec, "Codec `%4.4s' (%s) is not supported.", (char*)&codec, desc ); + dialog_Fatal( p_dec, _("Codec not supported"), + _("VLC could not decode the format \"%4.4s\" (%s)"), + (char*)&codec, desc ); + } else { + msg_Err( p_dec, "could not identify codec" ); + dialog_Fatal( p_dec, _("Unidentified codec"), + _("VLC could not identify the audio or video codec" ) ); + } } @@ -736,7 +715,7 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) */ static decoder_t * CreateDecoder( vlc_object_t *p_parent, input_thread_t *p_input, - es_format_t *fmt, bool b_packetizer, + const es_format_t *fmt, bool b_packetizer, input_resource_t *p_resource, sout_instance_t *p_sout ) { @@ -783,8 +762,10 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent, p_owner->p_sout_input = NULL; p_owner->p_packetizer = NULL; p_owner->b_packetizer = b_packetizer; + es_format_Init( &p_owner->fmt, UNKNOWN_ES, 0 ); /* decoder fifo */ + p_owner->b_woken = false; p_owner->p_fifo = block_FifoNew(); if( unlikely(p_owner->p_fifo == NULL) ) { @@ -794,13 +775,10 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent, } /* Set buffers allocation callbacks for the decoders */ - p_dec->pf_aout_buffer_new = aout_new_buffer; + p_dec->pf_aout_format_update = aout_update_format; + p_dec->pf_vout_format_update = vout_update_format; p_dec->pf_vout_buffer_new = vout_new_buffer; - p_dec->pf_vout_buffer_del = vout_del_buffer; - p_dec->pf_picture_link = vout_link_picture; - 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; @@ -834,6 +812,7 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent, { es_format_Clean( &p_owner->p_packetizer->fmt_in ); vlc_object_release( p_owner->p_packetizer ); + p_owner->p_packetizer = NULL; } } } @@ -862,7 +841,6 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent, vlc_cond_init( &p_owner->wait_acknowledge ); p_owner->b_fmt_description = false; - es_format_Init( &p_owner->fmt_description, UNKNOWN_ES, 0 ); p_owner->p_description = NULL; p_owner->b_exit = false; @@ -871,14 +849,9 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent, p_owner->pause.i_date = VLC_TS_INVALID; p_owner->pause.i_ignore = 0; - p_owner->b_buffering = false; - p_owner->buffer.b_first = true; - p_owner->buffer.b_full = false; - p_owner->buffer.i_count = 0; - 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_waiting = false; + p_owner->b_first = true; + p_owner->b_has_data = false; p_owner->b_flushing = false; @@ -914,11 +887,29 @@ static void *DecoderThread( void *p_data ) /* The decoder's main loop */ for( ;; ) { - block_t *p_block = block_FifoGet( p_owner->p_fifo ); + block_t *p_block; + + vlc_fifo_Lock( p_owner->p_fifo ); + vlc_fifo_CleanupPush( p_owner->p_fifo ); + + while( vlc_fifo_IsEmpty( p_owner->p_fifo ) ) + { + if( p_owner->b_woken ) + break; + vlc_fifo_Wait( 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. */ + } + + p_block = vlc_fifo_DequeueUnlocked( p_owner->p_fifo ); + if( p_block != NULL ) + vlc_cond_signal( &p_owner->wait_acknowledge ); - /* 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 ); + p_owner->b_woken = false; + vlc_cleanup_run(); + + if( p_block == NULL || p_block->i_flags & BLOCK_FLAG_CORE_EOS ) + DecoderSignalWait( p_dec ); if( p_block ) { @@ -932,10 +923,7 @@ static void *DecoderThread( void *p_data ) p_block = NULL; } - if( p_dec->b_error ) - DecoderError( p_dec, p_block ); - else - DecoderProcess( p_dec, p_block ); + DecoderProcess( p_dec, p_block ); vlc_restorecancel( canc ); } @@ -981,16 +969,15 @@ static void DecoderFlush( decoder_t *p_dec ) vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock ); } -static void DecoderSignalBuffering( decoder_t *p_dec, bool b_full ) +static void DecoderSignalWait( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering ) + if( p_owner->b_waiting ) { - if( b_full ) - p_owner->buffer.b_full = true; + p_owner->b_has_data = true; vlc_cond_signal( &p_owner->wait_acknowledge ); } @@ -1011,7 +998,7 @@ static bool DecoderIsFlushing( decoder_t *p_dec ) return b_flushing; } -static void DecoderWaitUnblock( decoder_t *p_dec, bool *pb_reject ) +static bool DecoderWaitUnblock( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -1023,7 +1010,7 @@ static void DecoderWaitUnblock( decoder_t *p_dec, bool *pb_reject ) break; if( p_owner->b_paused ) { - if( p_owner->b_buffering && !p_owner->buffer.b_full ) + if( p_owner->b_waiting && !p_owner->b_has_data ) break; if( p_owner->pause.i_ignore > 0 ) { @@ -1033,37 +1020,15 @@ static void DecoderWaitUnblock( decoder_t *p_dec, bool *pb_reject ) } else { - if( !p_owner->b_buffering || !p_owner->buffer.b_full ) + if( !p_owner->b_waiting || !p_owner->b_has_data ) break; } vlc_cond_wait( &p_owner->wait_request, &p_owner->lock ); } - if( pb_reject ) - *pb_reject = p_owner->b_flushing; + return p_owner->b_flushing; } -static void DecoderOutputChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date ) -{ - decoder_owner_sys_t *p_owner = p_dec->p_owner; - - vlc_assert_locked( &p_owner->lock ); - - /* XXX only audio and video output have to be paused. - * - for sout it is useless - * - for subs, it is done by the vout - */ - if( p_dec->fmt_out.i_cat == AUDIO_ES ) - { - if( p_owner->p_aout ) - aout_DecChangePause( p_owner->p_aout, b_paused, i_date ); - } - else if( p_dec->fmt_out.i_cat == VIDEO_ES ) - { - if( p_owner->p_vout ) - vout_ChangePause( p_owner->p_vout, b_paused, i_date ); - } -} static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ) { if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) ) @@ -1095,8 +1060,14 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, *pi_ts0 += i_es_delay; if( pi_ts1 && *pi_ts1 > VLC_TS_INVALID ) *pi_ts1 += i_es_delay; - if( input_clock_ConvertTS( p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) + if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) { + if( pi_ts1 != NULL ) + msg_Err(p_dec, "Could not convert timestamps %"PRId64 + ", %"PRId64"", *pi_ts0, *pi_ts1); + else + msg_Err(p_dec, "Could not convert timestamp %"PRId64, *pi_ts0); *pi_ts0 = VLC_TS_INVALID; + } } else { @@ -1135,10 +1106,11 @@ static void DecoderWaitDate( decoder_t *p_dec, { decoder_owner_sys_t *p_owner = p_dec->p_owner; + vlc_assert_locked( &p_owner->lock ); + if( *pb_reject || i_deadline < 0 ) return; - vlc_mutex_lock( &p_owner->lock ); do { if( p_owner->b_flushing || p_owner->b_exit ) @@ -1149,106 +1121,77 @@ static void DecoderWaitDate( decoder_t *p_dec, } while( vlc_cond_timedwait( &p_owner->wait_request, &p_owner->lock, i_deadline ) == 0 ); - vlc_mutex_unlock( &p_owner->lock ); } -static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, +static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio, int *pi_played_sum, int *pi_lost_sum ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; audio_output_t *p_aout = p_owner->p_aout; /* */ - if( p_audio->i_pts <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify audio_output/* + if( p_audio && p_audio->i_pts <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify audio_output/* { msg_Warn( p_dec, "non-dated audio buffer received" ); *pi_lost_sum += 1; - aout_BufferFree( p_audio ); + block_Release( p_audio ); return; } /* */ vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering || p_owner->buffer.p_audio ) + if( p_audio && p_owner->b_waiting ) { - p_audio->p_next = NULL; - - *p_owner->buffer.pp_audio_next = p_audio; - p_owner->buffer.pp_audio_next = &p_audio->p_next; - - p_owner->buffer.i_count++; - if( p_owner->buffer.i_count > DECODER_MAX_BUFFERING_COUNT || - p_audio->i_pts - p_owner->buffer.p_audio->i_pts > DECODER_MAX_BUFFERING_AUDIO_DURATION ) - { - p_owner->buffer.b_full = true; - vlc_cond_signal( &p_owner->wait_acknowledge ); - } + p_owner->b_has_data = true; + vlc_cond_signal( &p_owner->wait_acknowledge ); } for( ;; ) { - bool b_has_more = false; - bool b_reject; - DecoderWaitUnblock( p_dec, &b_reject ); - - if( p_owner->b_buffering ) - break; + bool b_paused; - /* */ - if( p_owner->buffer.p_audio ) - { - p_audio = p_owner->buffer.p_audio; + bool b_reject = DecoderWaitUnblock( p_dec ); - p_owner->buffer.p_audio = p_audio->p_next; - p_owner->buffer.i_count--; + b_paused = p_owner->b_paused; - b_has_more = p_owner->buffer.p_audio != NULL; - if( !b_has_more ) - p_owner->buffer.pp_audio_next = &p_owner->buffer.p_audio; - } + if (!p_audio) + break; /* */ - const bool b_dated = p_audio->i_pts > VLC_TS_INVALID; int i_rate = INPUT_RATE_DEFAULT; DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length, &i_rate, AOUT_MAX_ADVANCE_TIME ); - vlc_mutex_unlock( &p_owner->lock ); - - if( !p_aout || - p_audio->i_pts <= VLC_TS_INVALID || - i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE || - i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) + if( p_audio->i_pts <= VLC_TS_INVALID + || i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE + || i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) b_reject = true; DecoderWaitDate( p_dec, &b_reject, p_audio->i_pts - AOUT_MAX_PREPARE_TIME ); + if( unlikely(p_owner->b_paused != b_paused) ) + continue; /* race with input thread? retry... */ + if( p_aout == NULL ) + b_reject = true; + if( !b_reject ) { + assert( !p_owner->b_paused ); if( !aout_DecPlay( p_aout, p_audio, i_rate ) ) *pi_played_sum += 1; *pi_lost_sum += aout_DecGetResetLost( p_aout ); } else { - if( b_dated ) - msg_Warn( p_dec, "received buffer in the future" ); - else - msg_Warn( p_dec, "non-dated audio buffer received" ); - + msg_Dbg( p_dec, "discarded audio buffer" ); *pi_lost_sum += 1; - aout_BufferFree( p_audio ); + block_Release( p_audio ); } - if( !b_has_more ) - return; - - vlc_mutex_lock( &p_owner->lock ); - if( !p_owner->buffer.p_audio ) - break; + break; } vlc_mutex_unlock( &p_owner->lock ); } @@ -1256,19 +1199,21 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - aout_buffer_t *p_aout_buf; + block_t *p_aout_buf; int i_decoded = 0; int i_lost = 0; int i_played = 0; - while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) + if (!p_block) { + /* Play a NULL block to output buffered frames */ + DecoderPlayAudio( p_dec, NULL, &i_played, &i_lost ); + } + else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) ) { - audio_output_t *p_aout = p_owner->p_aout; - if( DecoderIsExitRequested( p_dec ) ) { /* It prevent freezing VLC in case of broken decoder */ - aout_DecDeleteBuffer( p_aout, p_aout_buf ); + block_Release( p_aout_buf ); if( p_block ) block_Release( p_block ); break; @@ -1278,7 +1223,7 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) if( p_owner->i_preroll_end > VLC_TS_INVALID && p_aout_buf->i_pts < p_owner->i_preroll_end ) { - aout_DecDeleteBuffer( p_aout, p_aout_buf ); + block_Release( p_aout_buf ); continue; } @@ -1338,10 +1283,9 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) if( !p_owner->cc.pp_decoder[i] ) continue; - if( i_cc_decoder > 1 ) - DecoderProcess( p_owner->cc.pp_decoder[i], block_Duplicate( p_cc ) ); - else - DecoderProcess( p_owner->cc.pp_decoder[i], p_cc ); + block_FifoPut( p_owner->cc.pp_decoder[i]->p_owner->p_fifo, + (i_cc_decoder > 1) ? block_Duplicate(p_cc) : p_cc); + i_cc_decoder--; b_processed = true; } @@ -1356,122 +1300,72 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, { decoder_owner_sys_t *p_owner = p_dec->p_owner; vout_thread_t *p_vout = p_owner->p_vout; - bool b_first_buffered; if( p_picture->date <= VLC_TS_INVALID ) { msg_Warn( p_dec, "non-dated video buffer received" ); *pi_lost_sum += 1; - vout_ReleasePicture( p_vout, p_picture ); + picture_Release( p_picture ); return; } /* */ vlc_mutex_lock( &p_owner->lock ); - if( ( p_owner->b_buffering && !p_owner->buffer.b_first ) || p_owner->buffer.p_picture ) + if( p_owner->b_waiting && !p_owner->b_first ) { - p_picture->p_next = NULL; - - *p_owner->buffer.pp_picture_next = p_picture; - p_owner->buffer.pp_picture_next = &p_picture->p_next; - - p_owner->buffer.i_count++; - if( p_owner->buffer.i_count > DECODER_MAX_BUFFERING_COUNT || - p_picture->date - p_owner->buffer.p_picture->date > DECODER_MAX_BUFFERING_VIDEO_DURATION ) - { - p_owner->buffer.b_full = true; - vlc_cond_signal( &p_owner->wait_acknowledge ); - } + p_owner->b_has_data = true; + vlc_cond_signal( &p_owner->wait_acknowledge ); } - b_first_buffered = p_owner->buffer.p_picture != NULL; - - for( ;; b_first_buffered = false ) - { - bool b_has_more = false; + bool b_first_after_wait = p_owner->b_waiting && p_owner->b_has_data; - bool b_reject; + bool b_reject = DecoderWaitUnblock( p_dec ); - DecoderWaitUnblock( p_dec, &b_reject ); - - if( p_owner->b_buffering && !p_owner->buffer.b_first ) - { - vlc_mutex_unlock( &p_owner->lock ); - return; - } - bool b_buffering_first = p_owner->b_buffering; - - /* */ - if( p_owner->buffer.p_picture ) - { - p_picture = p_owner->buffer.p_picture; - - p_owner->buffer.p_picture = p_picture->p_next; - p_owner->buffer.i_count--; - - b_has_more = p_owner->buffer.p_picture != NULL; - if( !b_has_more ) - p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; - } - - /* */ - if( b_buffering_first ) - { - assert( p_owner->buffer.b_first ); - assert( !p_owner->buffer.i_count ); - msg_Dbg( p_dec, "Received first picture" ); - p_owner->buffer.b_first = false; - p_picture->b_force = true; - } + if( p_owner->b_waiting ) + { + assert( p_owner->b_first ); + msg_Dbg( p_dec, "Received first picture" ); + p_owner->b_first = false; + p_picture->b_force = true; + } - const bool b_dated = p_picture->date > VLC_TS_INVALID; - int i_rate = INPUT_RATE_DEFAULT; - DecoderFixTs( p_dec, &p_picture->date, NULL, NULL, - &i_rate, DECODER_BOGUS_VIDEO_DELAY ); + const bool b_dated = p_picture->date > VLC_TS_INVALID; + int i_rate = INPUT_RATE_DEFAULT; + DecoderFixTs( p_dec, &p_picture->date, NULL, NULL, + &i_rate, DECODER_BOGUS_VIDEO_DELAY ); - vlc_mutex_unlock( &p_owner->lock ); + vlc_mutex_unlock( &p_owner->lock ); - /* */ - if( !p_picture->b_force && p_picture->date <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify video_output/* - b_reject = true; + /* */ + if( !p_picture->b_force && p_picture->date <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify video_output/* + b_reject = true; - if( !b_reject ) + if( !b_reject ) + { + if( i_rate != p_owner->i_last_rate || b_first_after_wait ) { - if( i_rate != p_owner->i_last_rate || b_first_buffered ) - { - /* Be sure to not display old picture after our own */ - vout_Flush( p_vout, p_picture->date ); - p_owner->i_last_rate = i_rate; - } - vout_PutPicture( p_vout, p_picture ); + /* Be sure to not display old picture after our own */ + vout_Flush( p_vout, p_picture->date ); + p_owner->i_last_rate = i_rate; } + vout_PutPicture( p_vout, p_picture ); + } + else + { + if( b_dated ) + msg_Warn( p_dec, "early picture skipped" ); else - { - if( b_dated ) - msg_Warn( p_dec, "early picture skipped" ); - else - msg_Warn( p_dec, "non-dated video buffer received" ); - - *pi_lost_sum += 1; - vout_ReleasePicture( p_vout, p_picture ); - } - int i_tmp_display; - int i_tmp_lost; - vout_GetResetStatistic( p_vout, &i_tmp_display, &i_tmp_lost ); - - *pi_played_sum += i_tmp_display; - *pi_lost_sum += i_tmp_lost; - - if( !b_has_more || b_buffering_first ) - break; + msg_Warn( p_dec, "non-dated video buffer received" ); - vlc_mutex_lock( &p_owner->lock ); - if( !p_owner->buffer.p_picture ) - { - vlc_mutex_unlock( &p_owner->lock ); - break; - } + *pi_lost_sum += 1; + picture_Release( p_picture ); } + int i_tmp_display; + int i_tmp_lost; + vout_GetResetStatistic( p_vout, &i_tmp_display, &i_tmp_lost ); + + *pi_played_sum += i_tmp_display; + *pi_lost_sum += i_tmp_lost; } static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) @@ -1488,7 +1382,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) if( DecoderIsExitRequested( p_dec ) ) { /* It prevent freezing VLC in case of broken decoder */ - vout_ReleasePicture( p_vout, p_pic ); + picture_Release( p_pic ); if( p_block ) block_Release( p_block ); break; @@ -1498,7 +1392,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) if( p_owner->i_preroll_end > VLC_TS_INVALID && p_pic->date < p_owner->i_preroll_end ) { - vout_ReleasePicture( p_vout, p_pic ); + picture_Release( p_pic ); continue; } @@ -1548,77 +1442,32 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic ) /* */ vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering || p_owner->buffer.p_subpic ) + if( p_owner->b_waiting ) { - p_subpic->p_next = NULL; - - *p_owner->buffer.pp_subpic_next = p_subpic; - p_owner->buffer.pp_subpic_next = &p_subpic->p_next; - - 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_acknowledge ); - } + p_owner->b_has_data = true; + vlc_cond_signal( &p_owner->wait_acknowledge ); } - for( ;; ) - { - bool b_has_more = false; - bool b_reject; - DecoderWaitUnblock( p_dec, &b_reject ); - - if( p_owner->b_buffering ) - { - vlc_mutex_unlock( &p_owner->lock ); - return; - } - - /* */ - if( p_owner->buffer.p_subpic ) - { - p_subpic = p_owner->buffer.p_subpic; - - p_owner->buffer.p_subpic = p_subpic->p_next; - p_owner->buffer.i_count--; + bool b_reject = DecoderWaitUnblock( p_dec ); - b_has_more = p_owner->buffer.p_subpic != NULL; - if( !b_has_more ) - p_owner->buffer.pp_subpic_next = &p_owner->buffer.p_subpic; - } + DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL, + NULL, INT64_MAX ); - /* */ - DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL, - NULL, INT64_MAX ); - - vlc_mutex_unlock( &p_owner->lock ); - - if( p_subpic->i_start <= VLC_TS_INVALID ) - b_reject = true; - - DecoderWaitDate( p_dec, &b_reject, - p_subpic->i_start - SPU_MAX_PREPARE_TIME ); + if( p_subpic->i_start <= VLC_TS_INVALID ) + b_reject = true; - if( !b_reject ) - vout_PutSubpicture( p_vout, p_subpic ); - else - subpicture_Delete( p_subpic ); + DecoderWaitDate( p_dec, &b_reject, + p_subpic->i_start - SPU_MAX_PREPARE_TIME ); + vlc_mutex_unlock( &p_owner->lock ); - if( !b_has_more ) - break; - vlc_mutex_lock( &p_owner->lock ); - if( !p_owner->buffer.p_subpic ) - { - vlc_mutex_unlock( &p_owner->lock ); - break; - } - } + if( !b_reject ) + vout_PutSubpicture( p_vout, p_subpic ); + else + subpicture_Delete( p_subpic ); } #ifdef ENABLE_SOUT -static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block ) +static int DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -1627,122 +1476,31 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block ) vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering || p_owner->buffer.p_block ) - { - block_ChainLastAppend( &p_owner->buffer.pp_block_next, p_sout_block ); - - 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_acknowledge ); - } - } - - for( ;; ) + if( p_owner->b_waiting ) { - bool b_has_more = false; - bool b_reject; - DecoderWaitUnblock( p_dec, &b_reject ); - - 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, NULL, INT64_MAX ); - - vlc_mutex_unlock( &p_owner->lock ); - - if( !b_reject ) - sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); // FIXME --VLC_TS_INVALID inspect stream_output/* - 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; - } + p_owner->b_has_data = true; + vlc_cond_signal( &p_owner->wait_acknowledge ); } -} -#endif - -/* */ -static void DecoderFlushBuffering( decoder_t *p_dec ) -{ - decoder_owner_sys_t *p_owner = p_dec->p_owner; - vlc_assert_locked( &p_owner->lock ); - - while( p_owner->buffer.p_picture ) - { - picture_t *p_picture = p_owner->buffer.p_picture; + bool b_reject = DecoderWaitUnblock( p_dec ); - p_owner->buffer.p_picture = p_picture->p_next; - p_owner->buffer.i_count--; - - if( p_owner->p_vout ) - { - vout_ReleasePicture( p_owner->p_vout, p_picture ); - } + DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts, + &p_sout_block->i_length, NULL, INT64_MAX ); - if( !p_owner->buffer.p_picture ) - p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; - } - while( p_owner->buffer.p_audio ) - { - aout_buffer_t *p_audio = p_owner->buffer.p_audio; - - p_owner->buffer.p_audio = p_audio->p_next; - p_owner->buffer.i_count--; - - aout_BufferFree( p_audio ); + vlc_mutex_unlock( &p_owner->lock ); - if( !p_owner->buffer.p_audio ) - p_owner->buffer.pp_audio_next = &p_owner->buffer.p_audio; - } - while( p_owner->buffer.p_subpic ) + if( !b_reject ) { - subpicture_t *p_subpic = p_owner->buffer.p_subpic; - - p_owner->buffer.p_subpic = p_subpic->p_next; - p_owner->buffer.i_count--; - - subpicture_Delete( p_subpic ); - - if( !p_owner->buffer.p_subpic ) - p_owner->buffer.pp_subpic_next = &p_owner->buffer.p_subpic; + /* FIXME --VLC_TS_INVALID inspect stream_output*/ + return sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); } - if( p_owner->buffer.p_block ) + else { - 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; + block_Release( p_sout_block ); + return VLC_EGENERIC; } } +#endif #ifdef ENABLE_SOUT /* This function process a block for sout @@ -1755,35 +1513,31 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block ) while( ( p_sout_block = p_dec->pf_packetize( p_dec, p_block ? &p_block : NULL ) ) ) { - if( !p_owner->p_sout_input ) + if( p_owner->p_sout_input == NULL ) { - es_format_Copy( &p_owner->sout, &p_dec->fmt_out ); + assert( !p_owner->b_fmt_description ); // no need for owner lock + es_format_Clean( &p_owner->fmt ); + es_format_Copy( &p_owner->fmt, &p_dec->fmt_out ); - p_owner->sout.i_group = p_dec->fmt_in.i_group; - p_owner->sout.i_id = p_dec->fmt_in.i_id; + p_owner->fmt.i_group = p_dec->fmt_in.i_group; + p_owner->fmt.i_id = p_dec->fmt_in.i_id; if( p_dec->fmt_in.psz_language ) { - free( p_owner->sout.psz_language ); - p_owner->sout.psz_language = + free( p_owner->fmt.psz_language ); + p_owner->fmt.psz_language = strdup( p_dec->fmt_in.psz_language ); } p_owner->p_sout_input = - sout_InputNew( p_owner->p_sout, - &p_owner->sout ); + sout_InputNew( p_owner->p_sout, &p_owner->fmt ); if( p_owner->p_sout_input == NULL ) { msg_Err( p_dec, "cannot create packetizer output (%4.4s)", - (char *)&p_owner->sout.i_codec ); + (char *)&p_owner->fmt.i_codec ); p_dec->b_error = true; - while( p_sout_block ) - { - block_t *p_next = p_sout_block->p_next; - block_Release( p_sout_block ); - p_sout_block = p_next; - } + block_ChainRelease(p_sout_block); break; } } @@ -1794,7 +1548,16 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block ) p_sout_block->p_next = NULL; - DecoderPlaySout( p_dec, p_sout_block ); + if( DecoderPlaySout( p_dec, p_sout_block ) == VLC_EGENERIC ) + { + msg_Err( p_dec, "cannot continue streaming due to errors" ); + + p_dec->b_error = true; + + /* Cleanup */ + block_ChainRelease( p_next ); + return; + } p_sout_block = p_next; } @@ -1821,6 +1584,21 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus es_format_Clean( &p_dec->fmt_in ); es_format_Copy( &p_dec->fmt_in, &p_packetizer->fmt_out ); } + + /* If the packetizer provides aspect ratio information, pass it + * to the decoder as a hint if the decoder itself can't provide + * it. Copy it regardless of the current value of the decoder input + * format aspect ratio, to properly propagate changes in aspect + * ratio. */ + if( p_packetizer->fmt_out.video.i_sar_num > 0 && + p_packetizer->fmt_out.video.i_sar_den > 0) + { + p_dec->fmt_in.video.i_sar_num = + p_packetizer->fmt_out.video.i_sar_num; + p_dec->fmt_in.video.i_sar_den= + p_packetizer->fmt_out.video.i_sar_den; + } + if( p_packetizer->pf_get_cc ) DecoderGetCc( p_dec, p_packetizer ); @@ -1843,7 +1621,7 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus DecoderDecodeVideo( p_dec, p_null ); } } - else if( p_block ) + else { DecoderDecodeVideo( p_dec, p_block ); } @@ -1891,7 +1669,7 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus DecoderDecodeAudio( p_dec, p_null ); } } - else if( p_block ) + else { DecoderDecodeAudio( p_dec, p_block ); } @@ -1960,7 +1738,6 @@ static void DecoderProcessOnFlush( decoder_t *p_dec ) decoder_owner_sys_t *p_owner = p_dec->p_owner; vlc_mutex_lock( &p_owner->lock ); - DecoderFlushBuffering( p_dec ); if( p_owner->b_flushing ) { @@ -1982,6 +1759,13 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block ) decoder_owner_sys_t *p_owner = (decoder_owner_sys_t *)p_dec->p_owner; const bool b_flush_request = p_block && (p_block->i_flags & BLOCK_FLAG_CORE_FLUSH); + if( p_dec->b_error ) + { + if( p_block ) + block_Release( p_block ); + goto flush; + } + if( p_block && p_block->i_buffer <= 0 ) { assert( !b_flush_request ); @@ -2032,23 +1816,11 @@ static void DecoderProcess( decoder_t *p_dec, block_t *p_block ) } /* */ +flush: if( b_flush_request ) DecoderProcessOnFlush( p_dec ); } -static void DecoderError( decoder_t *p_dec, block_t *p_block ) -{ - const bool b_flush_request = p_block && (p_block->i_flags & BLOCK_FLAG_CORE_FLUSH); - - /* */ - if( p_block ) - block_Release( p_block ); - - if( b_flush_request ) - DecoderProcessOnFlush( p_dec ); -} - - /** * Destroys a decoder object * @@ -2064,21 +1836,15 @@ static void DeleteDecoder( decoder_t * p_dec ) (unsigned)block_FifoCount( p_owner->p_fifo ) ); /* Free all packets still in the decoder fifo. */ - block_FifoEmpty( p_owner->p_fifo ); block_FifoRelease( p_owner->p_fifo ); - /* */ - vlc_mutex_lock( &p_owner->lock ); - DecoderFlushBuffering( p_dec ); - vlc_mutex_unlock( &p_owner->lock ); - /* Cleanup */ if( p_owner->p_aout ) { /* TODO: REVISIT gap-less audio */ aout_DecFlush( p_owner->p_aout ); aout_DecDelete( p_owner->p_aout ); - input_resource_RequestAout( p_owner->p_resource, p_owner->p_aout ); + input_resource_PutAout( p_owner->p_resource, p_owner->p_aout ); if( p_owner->p_input != NULL ) input_SendEventAout( p_owner->p_input ); } @@ -2099,15 +1865,13 @@ static void DeleteDecoder( decoder_t * p_dec ) if( p_owner->p_sout_input ) { sout_InputDelete( p_owner->p_sout_input ); - es_format_Clean( &p_owner->sout ); } #endif + es_format_Clean( &p_owner->fmt ); if( p_dec->fmt_out.i_cat == SPU_ES ) { - vout_thread_t *p_vout; - - p_vout = input_resource_HoldVout( p_owner->p_resource ); + vout_thread_t *p_vout = input_resource_HoldVout( p_owner->p_resource ); if( p_vout ) { if( p_owner->p_spu_vout == p_vout ) @@ -2120,7 +1884,6 @@ static void DeleteDecoder( decoder_t * p_dec ) es_format_Clean( &p_dec->fmt_out ); if( p_dec->p_description ) vlc_meta_Delete( p_dec->p_description ); - es_format_Clean( &p_owner->fmt_description ); if( p_owner->p_description ) vlc_meta_Delete( p_owner->p_description ); @@ -2155,10 +1918,6 @@ static void DecoderUpdateFormatLocked( decoder_t *p_dec ) p_owner->b_fmt_description = true; - /* Copy es_format */ - es_format_Clean( &p_owner->fmt_description ); - es_format_Copy( &p_owner->fmt_description, &p_dec->fmt_out ); - /* Move p_description */ if( p_owner->p_description && p_dec->p_description ) vlc_meta_Delete( p_owner->p_description ); @@ -2180,39 +1939,33 @@ static vout_thread_t *aout_request_vout( void *p_private, return p_vout; } -static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) +static int aout_update_format( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - aout_buffer_t *p_buffer; if( p_owner->p_aout - && !AOUT_FMTS_IDENTICAL(&p_dec->fmt_out.audio, &p_owner->audio) ) + && !AOUT_FMTS_IDENTICAL(&p_dec->fmt_out.audio, &p_owner->fmt.audio) ) { audio_output_t *p_aout = p_owner->p_aout; /* Parameters changed, restart the aout */ vlc_mutex_lock( &p_owner->lock ); - DecoderFlushBuffering( p_dec ); - aout_DecDelete( p_owner->p_aout ); p_owner->p_aout = NULL; vlc_mutex_unlock( &p_owner->lock ); - input_resource_RequestAout( p_owner->p_resource, p_aout ); + input_resource_PutAout( p_owner->p_resource, p_aout ); } if( p_owner->p_aout == NULL ) { - const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" ); - audio_sample_format_t format; - audio_output_t *p_aout; - aout_request_vout_t request_vout; - p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec; - p_owner->audio = p_dec->fmt_out.audio; - memcpy( &format, &p_owner->audio, sizeof( audio_sample_format_t ) ); + audio_sample_format_t format = p_dec->fmt_out.audio; + aout_FormatPrepare( &format ); + + const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" ); if( i_force_dolby && (format.i_original_channels&AOUT_CHAN_PHYSMASK) == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) ) @@ -2229,19 +1982,20 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) } } - request_vout.pf_request_vout = aout_request_vout; - request_vout.p_private = p_dec; + aout_request_vout_t request_vout = { + .pf_request_vout = aout_request_vout, + .p_private = p_dec, + }; + audio_output_t *p_aout; - assert( p_owner->p_aout == NULL ); - p_aout = input_resource_RequestAout( p_owner->p_resource, NULL ); + p_aout = input_resource_GetAout( p_owner->p_resource ); if( p_aout ) { - aout_FormatPrepare( &format ); if( aout_DecNew( p_aout, &format, &p_dec->fmt_out.audio_replay_gain, &request_vout ) ) { - input_resource_RequestAout( p_owner->p_resource, p_aout ); + input_resource_PutAout( p_owner->p_resource, p_aout ); p_aout = NULL; } } @@ -2249,8 +2003,15 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) vlc_mutex_lock( &p_owner->lock ); p_owner->p_aout = p_aout; + + es_format_Clean( &p_owner->fmt ); + es_format_Copy( &p_owner->fmt, &p_dec->fmt_out ); + aout_FormatPrepare( &p_owner->fmt.audio ); + DecoderUpdateFormatLocked( p_dec ); - if( unlikely(p_owner->b_paused) ) /* fake pause if needed */ + + if( unlikely(p_owner->b_paused) && p_aout != NULL ) + /* fake pause if needed */ aout_DecChangePause( p_aout, true, mdate() ); vlc_mutex_unlock( &p_owner->lock ); @@ -2262,31 +2023,32 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) { msg_Err( p_dec, "failed to create audio output" ); p_dec->b_error = true; - return NULL; + return -1; } + p_dec->fmt_out.audio.i_bytes_per_frame = - p_owner->audio.i_bytes_per_frame; + p_owner->fmt.audio.i_bytes_per_frame; + p_dec->fmt_out.audio.i_frame_length = + p_owner->fmt.audio.i_frame_length; } - - p_buffer = aout_DecNewBuffer( p_owner->p_aout, i_samples ); - - return p_buffer; + return 0; } -static picture_t *vout_new_buffer( decoder_t *p_dec ) +static int vout_update_format( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - if( p_owner->p_vout == NULL || - p_dec->fmt_out.video.i_width != p_owner->video.i_width || - p_dec->fmt_out.video.i_height != p_owner->video.i_height || - p_dec->fmt_out.video.i_visible_width != p_owner->video.i_visible_width || - p_dec->fmt_out.video.i_visible_height != p_owner->video.i_visible_height || - p_dec->fmt_out.video.i_x_offset != p_owner->video.i_x_offset || - p_dec->fmt_out.video.i_y_offset != p_owner->video.i_y_offset || - p_dec->fmt_out.i_codec != p_owner->video.i_chroma || - (int64_t)p_dec->fmt_out.video.i_sar_num * p_owner->video.i_sar_den != - (int64_t)p_dec->fmt_out.video.i_sar_den * p_owner->video.i_sar_num ) + if( p_owner->p_vout == NULL + || p_dec->fmt_out.video.i_width != p_owner->fmt.video.i_width + || p_dec->fmt_out.video.i_height != p_owner->fmt.video.i_height + || p_dec->fmt_out.video.i_visible_width != p_owner->fmt.video.i_visible_width + || p_dec->fmt_out.video.i_visible_height != p_owner->fmt.video.i_visible_height + || p_dec->fmt_out.video.i_x_offset != p_owner->fmt.video.i_x_offset + || p_dec->fmt_out.video.i_y_offset != p_owner->fmt.video.i_y_offset + || p_dec->fmt_out.i_codec != p_owner->fmt.video.i_chroma + || (int64_t)p_dec->fmt_out.video.i_sar_num * p_owner->fmt.video.i_sar_den != + (int64_t)p_dec->fmt_out.video.i_sar_den * p_owner->fmt.video.i_sar_num || + p_dec->fmt_out.video.orientation != p_owner->fmt.video.orientation ) { vout_thread_t *p_vout; @@ -2294,12 +2056,11 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) !p_dec->fmt_out.video.i_height ) { /* Can't create a new vout without display size */ - return NULL; + return -1; } video_format_t fmt = p_dec->fmt_out.video; fmt.i_chroma = p_dec->fmt_out.i_codec; - p_owner->video = fmt; if( vlc_fourcc_IsYUV( fmt.i_chroma ) ) { @@ -2355,8 +2116,6 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) vlc_mutex_lock( &p_owner->lock ); - DecoderFlushBuffering( p_dec ); - p_vout = p_owner->p_vout; p_owner->p_vout = NULL; vlc_mutex_unlock( &p_owner->lock ); @@ -2364,6 +2123,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) unsigned dpb_size; switch( p_dec->fmt_in.i_codec ) { + case VLC_CODEC_HEVC: case VLC_CODEC_H264: case VLC_CODEC_DIRAC: /* FIXME valid ? */ dpb_size = 18; @@ -2381,12 +2141,15 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) p_vout = input_resource_RequestVout( p_owner->p_resource, p_vout, &fmt, dpb_size + - p_dec->i_extra_picture_buffers + - 1 + DECODER_MAX_BUFFERING_COUNT, + p_dec->i_extra_picture_buffers + 1, true ); vlc_mutex_lock( &p_owner->lock ); p_owner->p_vout = p_vout; + es_format_Clean( &p_owner->fmt ); + es_format_Copy( &p_owner->fmt, &p_dec->fmt_out ); + p_owner->fmt.video.i_chroma = p_dec->fmt_out.i_codec; + DecoderUpdateFormatLocked( p_dec ); vlc_mutex_unlock( &p_owner->lock ); @@ -2397,12 +2160,16 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) { msg_Err( p_dec, "failed to create video output" ); p_dec->b_error = true; - return NULL; + return -1; } } + return 0; +} + +static picture_t *vout_new_buffer( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; - /* Get a new picture - */ for( ;; ) { if( DecoderIsExitRequested( p_dec ) || p_dec->b_error ) @@ -2416,7 +2183,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) return NULL; /* */ - DecoderSignalBuffering( p_dec, true ); + DecoderSignalWait( p_dec ); /* Check the decoder doesn't leak pictures */ vout_FixLeaks( p_owner->p_vout ); @@ -2426,21 +2193,6 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) } } -static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic ) -{ - vout_ReleasePicture( p_dec->p_owner->p_vout, p_pic ); -} - -static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic ) -{ - vout_HoldPicture( p_dec->p_owner->p_vout, p_pic ); -} - -static void vout_unlink_picture( decoder_t *p_dec, picture_t *p_pic ) -{ - vout_ReleasePicture( p_dec->p_owner->p_vout, p_pic ); -} - static subpicture_t *spu_new_buffer( decoder_t *p_dec, const subpicture_updater_t *p_updater ) { @@ -2451,7 +2203,8 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec, while( i_attempts-- ) { - if( DecoderIsExitRequested( p_dec ) || p_dec->b_error ) + if( DecoderIsExitRequested( p_dec ) || DecoderIsFlushing( p_dec ) + || p_dec->b_error ) break; p_vout = input_resource_HoldVout( p_owner->p_resource ); @@ -2469,12 +2222,6 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec, if( p_owner->p_spu_vout != p_vout ) { - vlc_mutex_lock( &p_owner->lock ); - - DecoderFlushBuffering( p_dec ); - - vlc_mutex_unlock( &p_owner->lock ); - p_owner->i_spu_channel = vout_RegisterSubpictureChannel( p_vout ); p_owner->i_spu_order = 0; p_owner->p_spu_vout = p_vout; @@ -2492,23 +2239,3 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec, return p_subpic; } - -static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic ) -{ - decoder_owner_sys_t *p_owner = p_dec->p_owner; - vout_thread_t *p_vout = NULL; - - p_vout = input_resource_HoldVout( p_owner->p_resource ); - if( !p_vout || p_owner->p_spu_vout != p_vout ) - { - if( p_vout ) - vlc_object_release( p_vout ); - msg_Warn( p_dec, "no vout found, leaking subpicture" ); - return; - } - - subpicture_Delete( p_subpic ); - - vlc_object_release( p_vout ); -} -