X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=3f36282b89b9ed13af7546ad5c4f813dbe366d12;hb=0c5adb0ef5270e9c3b24c01fc92fbfa94ea38257;hp=003155ad49f6be53dd4d94da02754de632ce554f;hpb=d6f0bd78c5aaae605b7894777d4d8eddb6fdaddb;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index 003155ad49..3f36282b89 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -39,21 +39,26 @@ #include #include #include +#include +#include -#include #include "audio_output/aout_internal.h" #include "stream_output/stream_output.h" #include "input_internal.h" #include "clock.h" #include "decoder.h" +#include "event.h" +#include "resource.h" #include "../video_output/vout_control.h" -static decoder_t *CreateDecoder( input_thread_t *, es_format_t *, int, sout_instance_t *p_sout ); +static decoder_t *CreateDecoder( input_thread_t *, es_format_t *, bool, + sout_instance_t *p_sout ); static void DeleteDecoder( decoder_t * ); static void *DecoderThread( vlc_object_t * ); -static int DecoderProcess( decoder_t *, block_t * ); +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 ); @@ -73,8 +78,6 @@ static void vout_unlink_picture( decoder_t *, picture_t * ); static subpicture_t *spu_new_buffer( decoder_t * ); static void spu_del_buffer( decoder_t *, subpicture_t * ); -static es_format_t null_es_format; - struct decoder_owner_sys_t { int64_t i_preroll_end; @@ -92,18 +95,25 @@ struct decoder_owner_sys_t /* Some decoders require already packetized data (ie. not truncated) */ decoder_t *p_packetizer; + bool b_packetizer; /* Current format in use by the output */ video_format_t video; audio_format_t audio; es_format_t sout; + /* */ + bool b_fmt_description; + es_format_t fmt_description; + vlc_meta_t *p_description; + /* fifo */ block_fifo_t *p_fifo; /* Lock for communication with decoder thread */ vlc_mutex_t lock; - vlc_cond_t wait; + vlc_cond_t wait_request; + vlc_cond_t wait_acknowledge; /* -- These variables need locking on write(only) -- */ aout_instance_t *p_aout; @@ -231,7 +241,7 @@ int decoder_GetInputAttachments( decoder_t *p_dec, mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) { if( !p_dec->pf_get_display_date ) - return 0; + return VLC_TS_INVALID; return p_dec->pf_get_display_date( p_dec, i_ts ); } @@ -253,37 +263,22 @@ int decoder_GetDisplayRate( decoder_t *p_dec ) * \return the spawned decoder object */ decoder_t *input_DecoderNew( input_thread_t *p_input, - es_format_t *fmt, input_clock_t *p_clock, sout_instance_t *p_sout ) + es_format_t *fmt, input_clock_t *p_clock, + sout_instance_t *p_sout ) { decoder_t *p_dec = NULL; + const char *psz_type = p_sout ? N_("packetizer") : N_("decoder"); int i_priority; -#ifdef ENABLE_SOUT - /* If we are in sout mode, search for packetizer module */ - if( p_sout ) - { - /* Create the decoder configuration structure */ - p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER, p_sout ); - if( p_dec == NULL ) - { - msg_Err( p_input, "could not create packetizer" ); - intf_UserFatal( p_input, false, _("Streaming / Transcoding failed"), - _("VLC could not open the packetizer module.") ); - return NULL; - } - } - else -#endif + /* Create the decoder configuration structure */ + p_dec = CreateDecoder( p_input, fmt, p_sout != NULL, p_sout ); + if( p_dec == NULL ) { - /* Create the decoder configuration structure */ - p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER, p_sout ); - if( p_dec == NULL ) - { - msg_Err( p_input, "could not create decoder" ); - intf_UserFatal( p_input, false, _("Streaming / Transcoding failed"), - _("VLC could not open the decoder module.") ); - return NULL; - } + msg_Err( p_input, "could not create %s", psz_type ); + dialog_Fatal( p_input, _("Streaming / Transcoding failed"), + _("VLC could not open the %s module."), + vlc_gettext( psz_type ) ); + return NULL; } if( !p_dec->p_module ) @@ -291,25 +286,23 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, DecoderUnsupportedCodec( p_dec, fmt->i_codec ); DeleteDecoder( p_dec ); - vlc_object_release( p_dec ); return NULL; } p_dec->p_owner->p_clock = p_clock; + assert( p_dec->fmt_out.i_cat != UNKNOWN_ES ); - if( fmt->i_cat == AUDIO_ES ) + if( p_dec->fmt_out.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, false ) ) + if( vlc_thread_create( p_dec, "decoder", DecoderThread, i_priority ) ) { msg_Err( p_dec, "cannot spawn decoder thread" ); module_unneed( p_dec, p_dec->p_module ); DeleteDecoder( p_dec ); - vlc_object_release( p_dec ); return NULL; } @@ -329,17 +322,18 @@ void input_DecoderDelete( decoder_t *p_dec ) vlc_object_kill( p_dec ); - /* Make sure we aren't paused anymore */ + /* Make sure we aren't paused/buffering/waiting anymore */ vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_paused || p_owner->b_buffering ) - { - p_owner->b_paused = false; - p_owner->b_buffering = false; - vlc_cond_signal( &p_owner->wait ); - } + const bool b_was_paused = p_owner->b_paused; + p_owner->b_paused = false; + p_owner->b_buffering = false; + p_owner->b_flushing = true; + vlc_cond_signal( &p_owner->wait_request ); vlc_mutex_unlock( &p_owner->lock ); vlc_thread_join( p_dec ); + p_owner->b_paused = b_was_paused; + module_unneed( p_dec, p_dec->p_module ); /* */ @@ -350,11 +344,8 @@ void input_DecoderDelete( decoder_t *p_dec ) input_DecoderSetCcState( p_dec, false, i ); } - /* Delete decoder configuration */ + /* Delete decoder */ DeleteDecoder( p_dec ); - - /* Delete the decoder */ - vlc_object_release( p_dec ); } /** @@ -364,11 +355,11 @@ void input_DecoderDelete( decoder_t *p_dec ) * \param p_dec the decoder object * \param p_block the data block */ -void input_DecoderDecode( decoder_t *p_dec, block_t *p_block ) +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( p_owner->p_input->p->b_out_pace_control ) + if( b_do_pace ) { /* The fifo is not consummed when buffering and so will * deadlock vlc. @@ -377,7 +368,11 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block ) 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 */ ) +#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 { /* FIXME: ideally we would check the time amount of data * in the FIFO instead of its size. */ @@ -428,19 +423,18 @@ 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( p_owner->p_input, &fmt, VLC_OBJECT_DECODER, p_owner->p_sout ); + p_cc = CreateDecoder( p_owner->p_input, &fmt, false, p_owner->p_sout ); if( !p_cc ) { msg_Err( p_dec, "could not create decoder" ); - intf_UserFatal( p_dec, false, _("Streaming / Transcoding failed"), - _("VLC could not open the decoder module.") ); + dialog_Fatal( p_dec, _("Streaming / Transcoding failed"), "%s", + _("VLC could not open the decoder module.") ); return VLC_EGENERIC; } else if( !p_cc->p_module ) { DecoderUnsupportedCodec( p_dec, fcc[i_channel] ); DeleteDecoder( p_cc ); - vlc_object_release( p_cc ); return VLC_EGENERIC; } p_cc->p_owner->p_clock = p_owner->p_clock; @@ -463,7 +457,6 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) vlc_object_kill( p_cc ); module_unneed( p_cc, p_cc->p_module ); DeleteDecoder( p_cc ); - vlc_object_release( p_cc ); } } return VLC_SUCCESS; @@ -493,7 +486,7 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date ) 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 ); + vlc_cond_signal( &p_owner->wait_request ); DecoderOutputChangePause( p_dec, b_paused, i_date ); @@ -539,7 +532,7 @@ void input_DecoderStartBuffering( decoder_t *p_dec ) p_owner->b_buffering = true; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_request ); vlc_mutex_unlock( &p_owner->lock ); } @@ -552,7 +545,7 @@ void input_DecoderStopBuffering( decoder_t *p_dec ) p_owner->b_buffering = false; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_request ); vlc_mutex_unlock( &p_owner->lock ); } @@ -566,11 +559,12 @@ void input_DecoderWaitBuffering( decoder_t *p_dec ) while( vlc_object_alive( p_dec ) && p_owner->b_buffering && !p_owner->buffer.b_full ) { block_FifoWake( p_owner->p_fifo ); - vlc_cond_wait( &p_owner->wait, &p_owner->lock ); + vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock ); } vlc_mutex_unlock( &p_owner->lock ); } + void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -578,13 +572,13 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) *pi_duration = 0; vlc_mutex_lock( &p_owner->lock ); - if( p_dec->fmt_in.i_cat == VIDEO_ES ) + if( p_dec->fmt_out.i_cat == VIDEO_ES ) { if( p_owner->b_paused && p_owner->p_vout ) { vout_NextPicture( p_owner->p_vout, pi_duration ); p_owner->pause.i_ignore++; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_request ); } } else @@ -595,6 +589,54 @@ void input_DecoderFrameNext( decoder_t *p_dec, mtime_t *pi_duration ) vlc_mutex_unlock( &p_owner->lock ); } +bool input_DecoderHasFormatChanged( decoder_t *p_dec, es_format_t *p_fmt, vlc_meta_t **pp_meta ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + bool b_changed; + + vlc_mutex_lock( &p_owner->lock ); + b_changed = p_owner->b_fmt_description; + if( b_changed ) + { + if( p_fmt ) + es_format_Copy( p_fmt, &p_owner->fmt_description ); + + if( pp_meta ) + { + *pp_meta = NULL; + if( p_owner->p_description ) + { + *pp_meta = vlc_meta_New(); + if( *pp_meta ) + vlc_meta_Merge( *pp_meta, p_owner->p_description ); + } + } + p_owner->b_fmt_description = false; + } + vlc_mutex_unlock( &p_owner->lock ); + return b_changed; +} + +size_t input_DecoderGetFifoSize( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + return block_FifoSize( p_owner->p_fifo ); +} + +void input_DecoderGetObjects( decoder_t *p_dec, + vout_thread_t **pp_vout, aout_instance_t **pp_aout ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + vlc_mutex_lock( &p_owner->lock ); + if( pp_vout ) + *pp_vout = p_owner->p_vout ? vlc_object_hold( p_owner->p_vout ) : NULL; + if( pp_aout ) + *pp_aout = p_owner->p_aout ? vlc_object_hold( p_owner->p_aout ) : NULL; + vlc_mutex_unlock( &p_owner->lock ); +} + /***************************************************************************** * Internal functions *****************************************************************************/ @@ -611,13 +653,16 @@ static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) vlc_mutex_lock( &p_owner->lock ); if( p_owner->b_buffering || p_owner->b_paused ) - i_ts = 0; + i_ts = VLC_TS_INVALID; vlc_mutex_unlock( &p_owner->lock ); - if( !p_owner->p_clock || !i_ts ) + if( !p_owner->p_clock || i_ts <= VLC_TS_INVALID ) return i_ts; - return input_clock_GetTS( p_owner->p_clock, NULL, p_owner->p_input->i_pts_delay, i_ts ); + if( input_clock_ConvertTS( p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) + return VLC_TS_INVALID; + + return i_ts; } static int DecoderGetDisplayRate( decoder_t *p_dec ) { @@ -631,12 +676,13 @@ 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'.\n" + msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'. " "VLC probably does not support this sound or video format.", (char*)&codec ); - intf_UserFatal( p_dec, false, _("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 ); + 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 ); } @@ -645,17 +691,19 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) * * \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 + * \param b_packetizer instead of a decoder * \return the decoder object */ static decoder_t * CreateDecoder( input_thread_t *p_input, - es_format_t *fmt, int i_object_type, sout_instance_t *p_sout ) + es_format_t *fmt, bool b_packetizer, + sout_instance_t *p_sout ) { decoder_t *p_dec; decoder_owner_sys_t *p_owner; - int i; + es_format_t null_es_format; - p_dec = vlc_object_create( p_input, i_object_type ); + p_dec = vlc_custom_create( p_input, sizeof( *p_dec ), VLC_OBJECT_DECODER, + "decoder" ); if( p_dec == NULL ) return NULL; @@ -665,13 +713,15 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->pf_get_cc = NULL; p_dec->pf_packetize = NULL; - /* Initialize the decoder fifo */ + /* Initialize the decoder */ p_dec->p_module = NULL; memset( &null_es_format, 0, sizeof(es_format_t) ); es_format_Copy( &p_dec->fmt_in, fmt ); es_format_Copy( &p_dec->fmt_out, &null_es_format ); + p_dec->p_description = NULL; + /* Allocate our private structure for the decoder */ p_dec->p_owner = p_owner = malloc( sizeof( decoder_owner_sys_t ) ); if( p_dec->p_owner == NULL ) @@ -679,7 +729,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, vlc_object_release( p_dec ); return NULL; } - p_dec->p_owner->i_preroll_end = -1; + p_dec->p_owner->i_preroll_end = VLC_TS_INVALID; p_dec->p_owner->i_last_rate = INPUT_RATE_DEFAULT; p_dec->p_owner->p_input = p_input; p_dec->p_owner->p_aout = NULL; @@ -691,6 +741,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->p_owner->p_sout = p_sout; p_dec->p_owner->p_sout_input = NULL; p_dec->p_owner->p_packetizer = NULL; + p_dec->p_owner->b_packetizer = b_packetizer; /* decoder fifo */ if( ( p_dec->p_owner->p_fifo = block_FifoNew() ) == NULL ) @@ -717,17 +768,18 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, vlc_object_attach( p_dec, p_input ); /* Find a suitable decoder/packetizer module */ - if( i_object_type == VLC_OBJECT_DECODER ) - p_dec->p_module = module_need( p_dec, "decoder", "$codec", 0 ); + if( !b_packetizer ) + p_dec->p_module = module_need( p_dec, "decoder", "$codec", false ); else - p_dec->p_module = module_need( p_dec, "packetizer", "$packetizer", 0 ); + p_dec->p_module = module_need( p_dec, "packetizer", "$packetizer", false ); /* Check if decoder requires already packetized data */ - if( i_object_type == VLC_OBJECT_DECODER && + if( !b_packetizer && p_dec->b_need_packetized && !p_dec->fmt_in.b_packetized ) { p_dec->p_owner->p_packetizer = - vlc_object_create( p_input, VLC_OBJECT_PACKETIZER ); + vlc_custom_create( p_input, sizeof( decoder_t ), + VLC_OBJECT_DECODER, "packetizer" ); if( p_dec->p_owner->p_packetizer ) { es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in, @@ -740,12 +792,11 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->p_owner->p_packetizer->p_module = module_need( p_dec->p_owner->p_packetizer, - "packetizer", "$packetizer", 0 ); + "packetizer", "$packetizer", false ); if( !p_dec->p_owner->p_packetizer->p_module ) { es_format_Clean( &p_dec->p_owner->p_packetizer->fmt_in ); - vlc_object_detach( p_dec->p_owner->p_packetizer ); vlc_object_release( p_dec->p_owner->p_packetizer ); } } @@ -754,7 +805,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, /* Copy ourself the input replay gain */ if( fmt->i_cat == AUDIO_ES ) { - for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ ) + for( unsigned i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ ) { if( !p_dec->fmt_out.audio_replay_gain.pb_peak[i] ) { @@ -771,10 +822,15 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, /* */ vlc_mutex_init( &p_owner->lock ); - vlc_cond_init( &p_owner->wait ); + vlc_cond_init( &p_owner->wait_request ); + 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_paused = false; - p_owner->pause.i_date = 0; + p_owner->pause.i_date = VLC_TS_INVALID; p_owner->pause.i_ignore = 0; p_owner->b_buffering = false; @@ -790,7 +846,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, /* */ p_owner->cc.b_supported = false; - if( i_object_type == VLC_OBJECT_DECODER ) + if( !b_packetizer ) { if( p_owner->p_packetizer && p_owner->p_packetizer->pf_get_cc ) p_owner->cc.b_supported = true; @@ -798,7 +854,7 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_owner->cc.b_supported = true; } - for( i = 0; i < 4; i++ ) + for( unsigned i = 0; i < 4; i++ ) { p_owner->cc.pb_present[i] = false; p_owner->cc.pp_decoder[i] = NULL; @@ -821,27 +877,43 @@ static void *DecoderThread( vlc_object_t *p_this ) 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 ) { + int canc = vlc_savecancel(); + if( p_dec->b_error ) - block_Release( p_block ); + DecoderError( p_dec, p_block ); else DecoderProcess( p_dec, p_block ); + + vlc_restorecancel( canc ); } } - - DecoderSignalBuffering( p_dec, true ); return NULL; } +static block_t *DecoderBlockFlushNew() +{ + block_t *p_null = block_Alloc( 128 ); + if( !p_null ) + return NULL; + + p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY | + BLOCK_FLAG_CORRUPTED | + BLOCK_FLAG_CORE_FLUSH; + memset( p_null->p_buffer, 0, p_null->i_buffer ); + + return p_null; +} + static void DecoderFlush( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - block_t *p_null; vlc_assert_locked( &p_owner->lock ); @@ -850,38 +922,17 @@ static void DecoderFlush( decoder_t *p_dec ) /* Monitor for flush end */ p_owner->b_flushing = true; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_request ); /* Send a special block */ - p_null = block_New( p_dec, 128 ); + block_t *p_null = DecoderBlockFlushNew(); if( !p_null ) return; - p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY; - p_null->i_flags |= BLOCK_FLAG_CORE_FLUSH; - if( !p_dec->fmt_in.b_packetized ) - p_null->i_flags |= BLOCK_FLAG_CORRUPTED; - memset( p_null->p_buffer, 0, p_null->i_buffer ); - - input_DecoderDecode( p_dec, p_null ); + input_DecoderDecode( p_dec, p_null, false ); /* */ while( vlc_object_alive( p_dec ) && p_owner->b_flushing ) - vlc_cond_wait( &p_owner->wait, &p_owner->lock ); -} - -static void DecoderSignalFlushed( decoder_t *p_dec ) -{ - decoder_owner_sys_t *p_owner = p_dec->p_owner; - - vlc_mutex_lock( &p_owner->lock ); - - if( p_owner->b_flushing ) - { - p_owner->b_flushing = false; - vlc_cond_signal( &p_owner->wait ); - } - - vlc_mutex_unlock( &p_owner->lock ); + vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock ); } static void DecoderSignalBuffering( decoder_t *p_dec, bool b_full ) @@ -894,7 +945,7 @@ static void DecoderSignalBuffering( decoder_t *p_dec, bool b_full ) { if( b_full ) p_owner->buffer.b_full = true; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_acknowledge ); } vlc_mutex_unlock( &p_owner->lock ); @@ -937,7 +988,7 @@ static void DecoderWaitUnblock( decoder_t *p_dec, bool *pb_reject ) if( !p_owner->b_buffering || !p_owner->buffer.b_full ) break; } - vlc_cond_wait( &p_owner->wait, &p_owner->lock ); + vlc_cond_wait( &p_owner->wait_request, &p_owner->lock ); } if( pb_reject ) @@ -954,13 +1005,13 @@ static void DecoderOutputChangePause( decoder_t *p_dec, bool b_paused, mtime_t i * - for sout it is useless * - for subs, it is done by the vout */ - if( p_dec->fmt_in.i_cat == AUDIO_ES ) + if( p_dec->fmt_out.i_cat == AUDIO_ES ) { if( p_owner->p_aout && p_owner->p_aout_input ) aout_DecChangePause( p_owner->p_aout, p_owner->p_aout_input, b_paused, i_date ); } - else if( p_dec->fmt_in.i_cat == VIDEO_ES ) + 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 ); @@ -970,56 +1021,58 @@ static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ) { if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) ) *pi_preroll = INT64_MAX; - else if( p->i_pts > 0 ) - *pi_preroll = __MIN( *pi_preroll, p->i_pts ); - else if( p->i_dts > 0 ) + else if( p->i_dts > VLC_TS_INVALID ) *pi_preroll = __MIN( *pi_preroll, p->i_dts ); + else if( p->i_pts > VLC_TS_INVALID ) + *pi_preroll = __MIN( *pi_preroll, p->i_pts ); } -static mtime_t DecoderTeletextFixTs( mtime_t i_ts, mtime_t i_ts_delay ) +static mtime_t DecoderTeletextFixTs( mtime_t i_ts ) { mtime_t current_date = mdate(); /* FIXME I don't really like that, es_out SHOULD do it using the video pts */ - if( !i_ts || i_ts > current_date + 10000000 || i_ts < current_date ) + if( i_ts <= VLC_TS_INVALID || i_ts > current_date + 10000000 || i_ts < current_date ) { /* ETSI EN 300 472 Annex A : do not take into account the PTS * for teletext streams. */ - return current_date + 400000 + i_ts_delay; + return current_date + 400000; } return i_ts; } static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, - mtime_t *pi_duration, int *pi_rate, mtime_t *pi_delay, bool b_telx ) + mtime_t *pi_duration, int *pi_rate, mtime_t i_ts_bound, bool b_telx ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; input_clock_t *p_clock = p_owner->p_clock; - int i_rate = 0; vlc_assert_locked( &p_owner->lock ); - const mtime_t i_ts_delay = p_owner->p_input->i_pts_delay; const mtime_t i_es_delay = p_owner->i_ts_delay; if( p_clock ) { const bool b_ephemere = pi_ts1 && *pi_ts0 == *pi_ts1; + int i_rate; - if( *pi_ts0 > 0 ) - *pi_ts0 = input_clock_GetTS( p_clock, &i_rate, i_ts_delay, - *pi_ts0 + i_es_delay ); - if( pi_ts1 && *pi_ts1 > 0 ) - *pi_ts1 = input_clock_GetTS( p_clock, &i_rate, i_ts_delay, - *pi_ts1 + i_es_delay ); + if( *pi_ts0 > VLC_TS_INVALID ) + { + *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 ) ) + *pi_ts0 = VLC_TS_INVALID; + } + else + { + i_rate = input_clock_GetRate( p_clock ); + } /* Do not create ephemere data because of rounding errors */ if( !b_ephemere && pi_ts1 && *pi_ts0 == *pi_ts1 ) *pi_ts1 += 1; - if( i_rate <= 0 ) - i_rate = input_clock_GetRate( p_clock ); - if( pi_duration ) *pi_duration = ( *pi_duration * i_rate + INPUT_RATE_DEFAULT-1 ) / INPUT_RATE_DEFAULT; @@ -1029,15 +1082,39 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, if( b_telx ) { - *pi_ts0 = DecoderTeletextFixTs( *pi_ts0, i_ts_delay ); - if( pi_ts1 && *pi_ts1 <= 0 ) + *pi_ts0 = DecoderTeletextFixTs( *pi_ts0 ); + if( pi_ts1 && *pi_ts1 <= VLC_TS_INVALID ) *pi_ts1 = *pi_ts0; } } - if( pi_delay ) +} + +/** + * If *pb_reject, it does nothing, otherwise it waits for the given + * deadline or a flush request (in which case it set *pi_reject to true. + */ +static void DecoderWaitDate( decoder_t *p_dec, + bool *pb_reject, mtime_t i_deadline ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + if( *pb_reject || i_deadline < 0 ) + return; + + for( ;; ) { - const int r = i_rate > 0 ? i_rate : INPUT_RATE_DEFAULT; - *pi_delay = i_ts_delay + i_es_delay * r / INPUT_RATE_DEFAULT; + vlc_mutex_lock( &p_owner->lock ); + if( p_owner->b_flushing || p_dec->b_die ) + { + *pb_reject = true; + vlc_mutex_unlock( &p_owner->lock ); + break; + } + int i_ret = vlc_cond_timedwait( &p_owner->wait_request, &p_owner->lock, + i_deadline ); + vlc_mutex_unlock( &p_owner->lock ); + if( i_ret ) + break; } } @@ -1049,7 +1126,7 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, aout_input_t *p_aout_input = p_owner->p_aout_input; /* */ - if( p_audio->start_date <= 0 ) + if( 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; @@ -1069,10 +1146,10 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, p_owner->buffer.i_count++; if( p_owner->buffer.i_count > DECODER_MAX_BUFFERING_COUNT || - p_audio->start_date - p_owner->buffer.p_audio->start_date > DECODER_MAX_BUFFERING_AUDIO_DURATION ) + 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 ); + vlc_cond_signal( &p_owner->wait_acknowledge ); } } @@ -1102,44 +1179,36 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, } /* */ + const bool b_dated = p_audio->i_pts > VLC_TS_INVALID; int i_rate = INPUT_RATE_DEFAULT; - mtime_t i_delay; - DecoderFixTs( p_dec, &p_audio->start_date, &p_audio->end_date, NULL, - &i_rate, &i_delay, false ); + DecoderFixTs( p_dec, &p_audio->i_pts, NULL, &p_audio->i_length, + &i_rate, AOUT_MAX_ADVANCE_TIME, false ); vlc_mutex_unlock( &p_owner->lock ); - /* */ - const mtime_t i_max_date = mdate() + i_delay + AOUT_MAX_ADVANCE_TIME; - if( !p_aout || !p_aout_input || - p_audio->start_date <= 0 || p_audio->start_date > i_max_date || + 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( !b_reject ) { - /* Wait if we are too early - * FIXME that's plain ugly to do it here */ - mwait( p_audio->start_date - AOUT_MAX_PREPARE_TIME ); - if( !aout_DecPlay( p_aout, p_aout_input, p_audio, i_rate ) ) *pi_played_sum += 1; *pi_lost_sum += aout_DecGetResetLost( p_aout, p_aout_input ); } else { - if( p_audio->start_date <= 0 ) - { + if( b_dated ) + msg_Warn( p_aout, "received buffer in the future" ); + else msg_Warn( p_dec, "non-dated audio buffer received" ); - } - else if( p_audio->start_date > i_max_date ) - { - msg_Warn( p_aout, "received buffer in the future (%"PRId64")", - p_audio->start_date - mdate() ); - } + *pi_lost_sum += 1; aout_BufferFree( p_audio ); } @@ -1169,8 +1238,6 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) { aout_instance_t *p_aout = p_owner->p_aout; aout_input_t *p_aout_input = p_owner->p_aout_input; - int i_lost = 0; - int i_played; if( p_dec->b_die ) { @@ -1182,19 +1249,20 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) } i_decoded++; - if( p_aout_buf->start_date < p_owner->i_preroll_end ) + 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_input, p_aout_buf ); continue; } - if( p_owner->i_preroll_end > 0 ) + if( p_owner->i_preroll_end > VLC_TS_INVALID ) { msg_Dbg( p_dec, "End of audio preroll" ); if( p_owner->p_aout && p_owner->p_aout_input ) aout_DecFlush( p_owner->p_aout, p_owner->p_aout_input ); /* */ - p_owner->i_preroll_end = -1; + p_owner->i_preroll_end = VLC_TS_INVALID; } DecoderPlayAudio( p_dec, p_aout_buf, &i_played, &i_lost ); @@ -1220,6 +1288,7 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) decoder_owner_sys_t *p_owner = p_dec->p_owner; block_t *p_cc; bool pb_present[4]; + bool b_processed = false; int i; int i_cc_decoder; @@ -1251,8 +1320,12 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) else DecoderProcess( p_owner->cc.pp_decoder[i], p_cc ); i_cc_decoder--; + b_processed = true; } vlc_mutex_unlock( &p_owner->lock ); + + if( !b_processed ) + block_Release( p_cc ); } static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, @@ -1262,13 +1335,14 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, vout_thread_t *p_vout = p_owner->p_vout; bool b_first_buffered; - if( p_picture->date <= 0 ) + if( p_picture->date <= VLC_TS_INVALID ) { msg_Warn( p_vout, "non-dated video buffer received" ); *pi_lost_sum += 1; - vout_DropPicture( p_vout, p_picture ); + vout_ReleasePicture( p_vout, p_picture ); return; } + vout_HoldPicture( p_vout, p_picture ); /* */ vlc_mutex_lock( &p_owner->lock ); @@ -1285,7 +1359,7 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, 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 ); + vlc_cond_signal( &p_owner->wait_acknowledge ); } } b_first_buffered = p_owner->buffer.p_picture != NULL; @@ -1319,9 +1393,6 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, } /* */ - int i_rate = INPUT_RATE_DEFAULT; - mtime_t i_delay; - if( b_buffering_first ) { assert( p_owner->buffer.b_first ); @@ -1329,19 +1400,17 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, msg_Dbg( p_dec, "Received first picture" ); p_owner->buffer.b_first = false; p_picture->b_force = true; - i_delay = 0; - if( p_owner->p_clock ) - i_rate = input_clock_GetRate( p_owner->p_clock ); } + + 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, &i_delay, false ); + &i_rate, DECODER_BOGUS_VIDEO_DELAY, false ); vlc_mutex_unlock( &p_owner->lock ); /* */ - 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 ) ) + if( !p_picture->b_force && p_picture->date <= VLC_TS_INVALID ) // FIXME --VLC_TS_INVALID verify video_output/* b_reject = true; if( !b_reject ) @@ -1352,21 +1421,19 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, vout_Flush( p_vout, p_picture->date ); p_owner->i_last_rate = i_rate; } - vout_DisplayPicture( p_vout, p_picture ); + vout_PutPicture( p_vout, p_picture ); + vout_ReleasePicture( p_vout, p_picture ); } else { - if( p_picture->date <= 0 ) - { - msg_Warn( p_vout, "non-dated video buffer received" ); - } + if( b_dated ) + msg_Warn( p_vout, "early picture skipped" ); else - { - msg_Warn( p_vout, "early picture skipped (%"PRId64")", - p_picture->date - mdate() ); - } + msg_Warn( p_vout, "non-dated video buffer received" ); + *pi_lost_sum += 1; - vout_DropPicture( p_vout, p_picture ); + vout_ReleasePicture( p_vout, p_picture ); + vout_ReleasePicture( p_vout, p_picture ); } int i_tmp_display; int i_tmp_lost; @@ -1402,7 +1469,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) if( p_dec->b_die ) { /* It prevent freezing VLC in case of broken decoder */ - vout_DropPicture( p_vout, p_pic ); + vout_ReleasePicture( p_vout, p_pic ); if( p_block ) block_Release( p_block ); break; @@ -1410,19 +1477,19 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) i_decoded++; - if( p_pic->date < p_owner->i_preroll_end ) + if( p_owner->i_preroll_end > VLC_TS_INVALID && p_pic->date < p_owner->i_preroll_end ) { - vout_DropPicture( p_vout, p_pic ); + vout_ReleasePicture( p_vout, p_pic ); continue; } - if( p_owner->i_preroll_end > 0 ) + if( p_owner->i_preroll_end > VLC_TS_INVALID ) { msg_Dbg( p_dec, "End of video preroll" ); if( p_vout ) - vout_Flush( p_vout, 1 ); + vout_Flush( p_vout, VLC_TS_INVALID+1 ); /* */ - p_owner->i_preroll_end = -1; + p_owner->i_preroll_end = VLC_TS_INVALID; } if( p_dec->pf_get_cc && @@ -1454,7 +1521,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, vout_thread_t *p_vout = p_owner->p_spu_vout; /* */ - if( p_subpic->i_start <= 0 ) + if( p_subpic->i_start <= VLC_TS_INVALID && !b_telx ) { msg_Warn( p_dec, "non-dated spu buffer received" ); subpicture_Delete( p_subpic ); @@ -1476,7 +1543,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, if( p_owner->buffer.i_count > 0 ) { p_owner->buffer.b_full = true; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_acknowledge ); } } @@ -1507,12 +1574,18 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, /* */ DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL, - NULL, NULL, b_telx ); + NULL, INT64_MAX, b_telx ); 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( !b_reject ) - spu_DisplaySubpicture( p_vout->p_spu, p_subpic ); + spu_DisplaySubpicture( vout_GetSpu( p_vout ), p_subpic ); else subpicture_Delete( p_subpic ); @@ -1546,7 +1619,7 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block, if( p_owner->buffer.i_count > 0 ) { p_owner->buffer.b_full = true; - vlc_cond_signal( &p_owner->wait ); + vlc_cond_signal( &p_owner->wait_acknowledge ); } } @@ -1578,12 +1651,12 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *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_sout_block->i_rate, INT64_MAX, b_telx ); vlc_mutex_unlock( &p_owner->lock ); if( !b_reject ) - sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); + sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); // FIXME --VLC_TS_INVALID inspect stream_output/* else block_Release( p_sout_block ); @@ -1613,7 +1686,10 @@ static void DecoderFlushBuffering( decoder_t *p_dec ) p_owner->buffer.i_count--; if( p_owner->p_vout ) - vout_DropPicture( p_owner->p_vout, p_picture ); + { + vout_ReleasePicture( p_owner->p_vout, p_picture ); + vout_ReleasePicture( p_owner->p_vout, p_picture ); + } if( !p_owner->buffer.p_picture ) p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; @@ -1657,7 +1733,7 @@ static void DecoderFlushBuffering( decoder_t *p_dec ) static void DecoderProcessSout( 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_telx = p_dec->fmt_in.i_codec == VLC_FOURCC('t','e','l','x'); + const bool b_telx = p_dec->fmt_in.i_codec == VLC_CODEC_TELETEXT; block_t *p_sout_block; while( ( p_sout_block = @@ -1671,8 +1747,7 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block ) p_owner->sout.i_id = p_dec->fmt_in.i_id; if( p_dec->fmt_in.psz_language ) { - if( p_owner->sout.psz_language ) - free( p_owner->sout.psz_language ); + free( p_owner->sout.psz_language ); p_owner->sout.psz_language = strdup( p_dec->fmt_in.psz_language ); } @@ -1707,20 +1782,6 @@ static void DecoderProcessSout( decoder_t *p_dec, block_t *p_block ) p_sout_block = p_next; } - - /* For now it's enough, as only sout impact on this flag */ - if( p_owner->p_sout->i_out_pace_nocontrol > 0 && - p_owner->p_input->p->b_out_pace_control ) - { - msg_Dbg( p_dec, "switching to sync mode" ); - p_owner->p_input->p->b_out_pace_control = false; - } - else if( p_owner->p_sout->i_out_pace_nocontrol <= 0 && - !p_owner->p_input->p->b_out_pace_control ) - { - msg_Dbg( p_dec, "switching to async mode" ); - p_owner->p_input->p->b_out_pace_control = true; - } } } @@ -1756,6 +1817,14 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus p_packetized_block = p_next; } } + /* The packetizer does not output a block that tell the decoder to flush + * do it ourself */ + if( b_flush ) + { + block_t *p_null = DecoderBlockFlushNew(); + if( p_null ) + DecoderDecodeVideo( p_dec, p_null ); + } } else if( p_block ) { @@ -1763,7 +1832,7 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus } if( b_flush && p_owner->p_vout ) - vout_Flush( p_owner->p_vout, 1 ); + vout_Flush( p_owner->p_vout, VLC_TS_INVALID+1 ); } /* This function process a audio block @@ -1796,6 +1865,14 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus p_packetized_block = p_next; } } + /* The packetizer does not output a block that tell the decoder to flush + * do it ourself */ + if( b_flush ) + { + block_t *p_null = DecoderBlockFlushNew(); + if( p_null ) + DecoderDecodeAudio( p_dec, p_null ); + } } else if( p_block ) { @@ -1811,7 +1888,7 @@ static void DecoderProcessAudio( decoder_t *p_dec, block_t *p_block, bool b_flus static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block, bool b_flush ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; - const bool b_telx = p_dec->fmt_in.i_codec == VLC_FOURCC('t','e','l','x'); + const bool b_telx = p_dec->fmt_in.i_codec == VLC_CODEC_TELETEXT; input_thread_t *p_input = p_owner->p_input; vout_thread_t *p_vout; @@ -1823,13 +1900,13 @@ static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block, bool b_flush stats_UpdateInteger( p_dec, p_input->p->counters.p_decoded_sub, 1, NULL ); vlc_mutex_unlock( &p_input->p->counters.counters_lock ); - p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + p_vout = input_resource_HoldVout( p_input->p->p_resource ); if( p_vout && p_owner->p_spu_vout == p_vout ) { /* Preroll does not work very well with subtitle */ - if( p_spu->i_start > 0 && + if( p_spu->i_start > VLC_TS_INVALID && p_spu->i_start < p_owner->i_preroll_end && - ( p_spu->i_stop <= 0 || p_spu->i_stop < p_owner->i_preroll_end ) ) + ( p_spu->i_stop <= VLC_TS_INVALID || p_spu->i_stop < p_owner->i_preroll_end ) ) { subpicture_Delete( p_spu ); } @@ -1848,10 +1925,10 @@ static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block, bool b_flush if( b_flush && p_owner->p_spu_vout ) { - p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + p_vout = input_resource_HoldVout( p_input->p->p_resource ); if( p_vout && p_owner->p_spu_vout == p_vout ) - spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, + spu_Control( vout_GetSpu( p_vout ), SPU_CHANNEL_CLEAR, p_owner->i_spu_channel ); if( p_vout ) @@ -1859,6 +1936,22 @@ static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block, bool b_flush } } +/* */ +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 ) + { + p_owner->b_flushing = false; + vlc_cond_signal( &p_owner->wait_acknowledge ); + } + vlc_mutex_unlock( &p_owner->lock ); +} + /** * Decode a block * @@ -1866,7 +1959,7 @@ static void DecoderProcessSpu( decoder_t *p_dec, block_t *p_block, bool b_flush * \param p_block the block to decode * \return VLC_SUCCESS or an error code */ -static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) +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); @@ -1875,12 +1968,11 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) { assert( !b_flush_request ); block_Release( p_block ); - return VLC_SUCCESS; + return; } - int canc = vlc_savecancel(); #ifdef ENABLE_SOUT - if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) + if( p_owner->b_packetizer ) { if( p_block ) p_block->i_flags &= ~BLOCK_FLAG_CORE_PRIVATE_MASK; @@ -1902,15 +1994,15 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) p_block->i_flags &= ~BLOCK_FLAG_CORE_PRIVATE_MASK; } - if( p_dec->fmt_in.i_cat == AUDIO_ES ) + if( p_dec->fmt_out.i_cat == AUDIO_ES ) { DecoderProcessAudio( p_dec, p_block, b_flush ); } - else if( p_dec->fmt_in.i_cat == VIDEO_ES ) + else if( p_dec->fmt_out.i_cat == VIDEO_ES ) { DecoderProcessVideo( p_dec, p_block, b_flush ); } - else if( p_dec->fmt_in.i_cat == SPU_ES ) + else if( p_dec->fmt_out.i_cat == SPU_ES ) { DecoderProcessSpu( p_dec, p_block, b_flush ); } @@ -1923,18 +2015,22 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) /* */ if( b_flush_request ) - { - vlc_mutex_lock( &p_owner->lock ); - DecoderFlushBuffering( p_dec ); - vlc_mutex_unlock( &p_owner->lock ); + DecoderProcessOnFlush( p_dec ); +} - DecoderSignalFlushed( p_dec ); - } - vlc_restorecancel( canc ); +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 ); - return p_dec->b_error ? VLC_EGENERIC : VLC_SUCCESS; + if( b_flush_request ) + DecoderProcessOnFlush( p_dec ); } + /** * Destroys a decoder object * @@ -1963,16 +2059,19 @@ static void DeleteDecoder( decoder_t * p_dec ) aout_DecDelete( p_owner->p_aout, p_owner->p_aout_input ); if( p_owner->p_aout ) { - vlc_object_release( p_owner->p_aout ); + input_resource_RequestAout( p_owner->p_input->p->p_resource, + p_owner->p_aout ); + input_SendEventAout( p_owner->p_input ); p_owner->p_aout = NULL; } if( p_owner->p_vout ) { - /* Hack to make sure all the the pictures are freed by the decoder */ - vout_FixLeaks( p_owner->p_vout, true ); + /* Hack to make sure all the the pictures are freed by the decoder + * and that the vout is not paused anymore */ + vout_Reset( p_owner->p_vout ); - /* We are about to die. Reattach video output to p_vlc. */ - vout_Request( p_dec, p_owner->p_vout, NULL ); + /* */ + input_resource_RequestVout( p_owner->p_input->p->p_resource, p_owner->p_vout, NULL, true ); input_SendEventVout( p_owner->p_input ); } @@ -1984,21 +2083,26 @@ static void DeleteDecoder( decoder_t * p_dec ) } #endif - if( p_dec->fmt_in.i_cat == SPU_ES ) + if( p_dec->fmt_out.i_cat == SPU_ES ) { vout_thread_t *p_vout; - p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); - if( p_vout && p_owner->p_spu_vout == p_vout ) + p_vout = input_resource_HoldVout( p_owner->p_input->p->p_resource ); + if( p_vout ) { - spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR, - p_owner->i_spu_channel ); + if( p_owner->p_spu_vout == p_vout ) + spu_Control( vout_GetSpu( p_vout ), SPU_CHANNEL_CLEAR, p_owner->i_spu_channel ); vlc_object_release( p_vout ); } } es_format_Clean( &p_dec->fmt_in ); 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 ); if( p_owner->p_packetizer ) { @@ -2006,14 +2110,16 @@ static void DeleteDecoder( decoder_t * p_dec ) p_owner->p_packetizer->p_module ); es_format_Clean( &p_owner->p_packetizer->fmt_in ); es_format_Clean( &p_owner->p_packetizer->fmt_out ); - vlc_object_detach( p_owner->p_packetizer ); + if( p_owner->p_packetizer->p_description ) + vlc_meta_Delete( p_owner->p_packetizer->p_description ); vlc_object_release( p_owner->p_packetizer ); } - vlc_cond_destroy( &p_owner->wait ); + vlc_cond_destroy( &p_owner->wait_acknowledge ); + vlc_cond_destroy( &p_owner->wait_request ); vlc_mutex_destroy( &p_owner->lock ); - vlc_object_detach( p_dec ); + vlc_object_release( p_dec ); free( p_owner ); } @@ -2021,6 +2127,36 @@ static void DeleteDecoder( decoder_t * p_dec ) /***************************************************************************** * Buffers allocation callbacks for the decoders *****************************************************************************/ +static void DecoderUpdateFormatLocked( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + vlc_assert_locked( &p_owner->lock ); + + 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 ); + p_owner->p_description = p_dec->p_description; + p_dec->p_description = NULL; +} +static vout_thread_t *aout_request_vout( void *p_private, + vout_thread_t *p_vout, video_format_t *p_fmt, bool b_recyle ) +{ + decoder_t *p_dec = p_private; + input_thread_t *p_input = p_dec->p_owner->p_input; + + p_vout = input_resource_RequestVout( p_input->p->p_resource, p_vout, p_fmt, b_recyle ); + input_SendEventVout( p_input ); + + return p_vout; +} + static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -2048,10 +2184,11 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) if( p_owner->p_aout_input == NULL ) { - const int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" ); + const int i_force_dolby = var_InheritInteger( p_dec, "force-dolby-surround" ); audio_sample_format_t format; aout_input_t *p_aout_input; aout_instance_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; @@ -2073,15 +2210,25 @@ 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; + p_aout = p_owner->p_aout; + if( !p_aout ) + p_aout = input_resource_RequestAout( p_owner->p_input->p->p_resource, NULL ); p_aout_input = aout_DecNew( p_dec, &p_aout, - &format, &p_dec->fmt_out.audio_replay_gain ); + &format, &p_dec->fmt_out.audio_replay_gain, &request_vout ); vlc_mutex_lock( &p_owner->lock ); + p_owner->p_aout = p_aout; p_owner->p_aout_input = p_aout_input; + DecoderUpdateFormatLocked( p_dec ); + vlc_mutex_unlock( &p_owner->lock ); + input_SendEventAout( p_owner->p_input ); + if( p_owner->p_aout_input == NULL ) { msg_Err( p_dec, "failed to create audio output" ); @@ -2105,9 +2252,6 @@ static void aout_del_buffer( decoder_t *p_dec, aout_buffer_t *p_buffer ) p_owner->p_aout_input, p_buffer ); } - -int vout_CountPictureAvailable( vout_thread_t *p_vout ); - static picture_t *vout_new_buffer( decoder_t *p_dec ) { decoder_owner_sys_t *p_owner = p_dec->p_owner; @@ -2116,7 +2260,8 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) 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_chroma != p_owner->video.i_chroma || - p_dec->fmt_out.video.i_aspect != p_owner->video.i_aspect ) + (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 ) { vout_thread_t *p_vout; @@ -2151,19 +2296,19 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) 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; + if( !(p_dec->fmt_out.video.i_sar_num % 136)) + { + 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; + p_dec->fmt_out.video.i_sar_num = 1; + p_dec->fmt_out.video.i_sar_den = 1; } vlc_ureduce( &p_dec->fmt_out.video.i_sar_num, @@ -2182,10 +2327,14 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) p_owner->p_vout = NULL; vlc_mutex_unlock( &p_owner->lock ); - p_vout = vout_Request( p_dec, p_vout, &p_dec->fmt_out.video ); + p_vout = input_resource_RequestVout( p_owner->p_input->p->p_resource, + p_vout, &p_dec->fmt_out.video, true ); vlc_mutex_lock( &p_owner->lock ); p_owner->p_vout = p_vout; + + DecoderUpdateFormatLocked( p_dec ); + vlc_mutex_unlock( &p_owner->lock ); input_SendEventVout( p_owner->p_input ); @@ -2195,35 +2344,18 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) p_dec->b_error = true; return NULL; } - - if( p_owner->video.i_rmask ) - p_owner->p_vout->render.i_rmask = p_owner->video.i_rmask; - if( p_owner->video.i_gmask ) - p_owner->p_vout->render.i_gmask = p_owner->video.i_gmask; - if( p_owner->video.i_bmask ) - p_owner->p_vout->render.i_bmask = p_owner->video.i_bmask; } /* Get a new picture */ for( ;; ) { - picture_t *p_picture; - if( p_dec->b_die || p_dec->b_error ) return NULL; - /* The video filter chain required that there is always 1 free buffer - * that it will use as temporary one. It will release the temporary - * buffer once its work is done, so this check is safe even if we don't - * lock around both count() and create(). - */ - if( vout_CountPictureAvailable( p_owner->p_vout ) >= 2 ) - { - p_picture = vout_CreatePicture( p_owner->p_vout, 0, 0, 0 ); - if( p_picture ) - return p_picture; - } + picture_t *p_picture = vout_GetPicture( p_owner->p_vout ); + if( p_picture ) + return p_picture; if( DecoderIsFlushing( p_dec ) ) return NULL; @@ -2232,7 +2364,7 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) DecoderSignalBuffering( p_dec, true ); /* Check the decoder doesn't leak pictures */ - vout_FixLeaks( p_owner->p_vout, false ); + vout_FixLeaks( p_owner->p_vout ); /* FIXME add a vout_WaitPictureAvailable (timedwait) */ msleep( VOUT_OUTMEM_SLEEP ); @@ -2241,17 +2373,17 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic ) { - vout_DropPicture( p_dec->p_owner->p_vout, 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_LinkPicture( p_dec->p_owner->p_vout, 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_UnlinkPicture( p_dec->p_owner->p_vout, p_pic ); + vout_ReleasePicture( p_dec->p_owner->p_vout, p_pic ); } static subpicture_t *spu_new_buffer( decoder_t *p_dec ) @@ -2266,7 +2398,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) if( p_dec->b_die || p_dec->b_error ) break; - p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + p_vout = input_resource_HoldVout( p_owner->p_input->p->p_resource ); if( p_vout ) break; @@ -2287,7 +2419,7 @@ static subpicture_t *spu_new_buffer( decoder_t *p_dec ) vlc_mutex_unlock( &p_owner->lock ); - spu_Control( p_vout->p_spu, SPU_CHANNEL_REGISTER, + spu_Control( vout_GetSpu( p_vout ), SPU_CHANNEL_REGISTER, &p_owner->i_spu_channel ); p_owner->i_spu_order = 0; p_owner->p_spu_vout = p_vout; @@ -2311,7 +2443,7 @@ 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 = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE ); + p_vout = input_resource_HoldVout( p_owner->p_input->p->p_resource ); if( !p_vout || p_owner->p_spu_vout != p_vout ) { if( p_vout )