X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Fdecoder.c;h=96da051d0677c7aa1272551069addf1680b80d38;hb=15edb457d5068568c996b41bbfb96b41a3fb1da2;hp=a941a328f5cfc13171d0e3360adcaeec00b45af4;hpb=53f3c079b7658feb03fe1fb68bcf47aeccc575d1;p=vlc diff --git a/src/input/decoder.c b/src/input/decoder.c index a941a328f5..96da051d06 100644 --- a/src/input/decoder.c +++ b/src/input/decoder.c @@ -39,21 +39,25 @@ #include #include #include +#include +#include -#include #include "audio_output/aout_internal.h" #include "stream_output/stream_output.h" #include "input_internal.h" -#include "input_clock.h" -#include "input_decoder.h" +#include "clock.h" +#include "decoder.h" +#include "event.h" +#include "resource.h" -#include "../video_output/vout_internal.h" +#include "../video_output/vout_control.h" static decoder_t *CreateDecoder( input_thread_t *, es_format_t *, int, 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 +77,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; @@ -98,6 +100,11 @@ struct decoder_owner_sys_t 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; @@ -118,12 +125,14 @@ struct decoder_owner_sys_t struct { mtime_t i_date; + int i_ignore; } pause; /* Buffering */ bool b_buffering; struct { + bool b_first; bool b_full; int i_count; @@ -135,6 +144,9 @@ struct decoder_owner_sys_t aout_buffer_t *p_audio; aout_buffer_t **pp_audio_next; + + block_t *p_block; + block_t **pp_block_next; } buffer; /* Flushing */ @@ -156,48 +168,88 @@ struct decoder_owner_sys_t #define DECODER_MAX_BUFFERING_AUDIO_DURATION (AOUT_MAX_PREPARE_TIME) #define DECODER_MAX_BUFFERING_VIDEO_DURATION (1*CLOCK_FREQ) +/* Pictures which are DECODER_BOGUS_VIDEO_DELAY or more in advance probably have + * a bogus PTS and won't be displayed */ +#define DECODER_BOGUS_VIDEO_DELAY ((mtime_t)(DEFAULT_PTS_DELAY * 30)) + +/* */ +#define DECODER_SPU_VOUT_WAIT_DURATION ((int)(0.200*CLOCK_FREQ)) + + /***************************************************************************** * Public functions *****************************************************************************/ +picture_t *decoder_NewPicture( decoder_t *p_decoder ) +{ + picture_t *p_picture = p_decoder->pf_vout_buffer_new( p_decoder ); + if( !p_picture ) + msg_Warn( p_decoder, "can't get output picture" ); + return p_picture; +} +void decoder_DeletePicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_vout_buffer_del( p_decoder, p_picture ); +} +void decoder_LinkPicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_picture_link( p_decoder, p_picture ); +} +void decoder_UnlinkPicture( decoder_t *p_decoder, picture_t *p_picture ) +{ + p_decoder->pf_picture_unlink( p_decoder, p_picture ); +} -/* decoder_GetInputAttachment: - */ -input_attachment_t *decoder_GetInputAttachment( decoder_t *p_dec, - const char *psz_name ) +aout_buffer_t *decoder_NewAudioBuffer( decoder_t *p_decoder, int i_size ) { - input_attachment_t *p_attachment; - if( input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENT, &p_attachment, psz_name ) ) + if( !p_decoder->pf_aout_buffer_new ) return NULL; - return p_attachment; + return p_decoder->pf_aout_buffer_new( p_decoder, i_size ); +} +void decoder_DeleteAudioBuffer( decoder_t *p_decoder, aout_buffer_t *p_buffer ) +{ + p_decoder->pf_aout_buffer_del( p_decoder, p_buffer ); +} + +subpicture_t *decoder_NewSubpicture( decoder_t *p_decoder ) +{ + subpicture_t *p_subpicture = p_decoder->pf_spu_buffer_new( p_decoder ); + if( !p_subpicture ) + msg_Warn( p_decoder, "can't get output subpicture" ); + return p_subpicture; } +void decoder_DeleteSubpicture( decoder_t *p_decoder, subpicture_t *p_subpicture ) +{ + p_decoder->pf_spu_buffer_del( p_decoder, p_subpicture ); +} + /* decoder_GetInputAttachments: */ int decoder_GetInputAttachments( decoder_t *p_dec, input_attachment_t ***ppp_attachment, int *pi_attachment ) { - return input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENTS, - ppp_attachment, pi_attachment ); + if( !p_dec->pf_get_attachments ) + return VLC_EGENERIC; + + return p_dec->pf_get_attachments( p_dec, ppp_attachment, pi_attachment ); } /* decoder_GetDisplayDate: */ mtime_t decoder_GetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) { - decoder_owner_sys_t *p_owner = p_dec->p_owner; + if( !p_dec->pf_get_display_date ) + return 0; - if( !p_owner->p_clock ) - return i_ts; - return input_clock_GetTS( p_owner->p_clock, NULL, p_owner->p_input->i_pts_delay, i_ts ); + return p_dec->pf_get_display_date( p_dec, i_ts ); } /* decoder_GetDisplayRate: */ int decoder_GetDisplayRate( decoder_t *p_dec ) { - decoder_owner_sys_t *p_owner = p_dec->p_owner; - - if( !p_owner->p_clock ) + if( !p_dec->pf_get_display_rate ) return INPUT_RATE_DEFAULT; - return input_clock_GetRate( p_owner->p_clock ); + + return p_dec->pf_get_display_rate( p_dec ); } /** @@ -213,9 +265,7 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, decoder_t *p_dec = NULL; int i_priority; -#ifndef ENABLE_SOUT - (void)b_force_decoder; -#else +#ifdef ENABLE_SOUT /* If we are in sout mode, search for packetizer module */ if( p_sout ) { @@ -224,8 +274,8 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, 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.") ); + dialog_Fatal( p_input, _("Streaming / Transcoding failed"), + _("VLC could not open the packetizer module.") ); return NULL; } } @@ -237,8 +287,8 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, 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.") ); + dialog_Fatal( p_input, _("Streaming / Transcoding failed"), + _("VLC could not open the decoder module.") ); return NULL; } } @@ -253,15 +303,15 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, } 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 ); @@ -286,23 +336,19 @@ 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 ); vlc_mutex_unlock( &p_owner->lock ); - /* Make sure the thread leaves the function */ - block_FifoWake( p_owner->p_fifo ); - vlc_thread_join( p_dec ); + p_owner->b_paused = b_was_paused; - /* Don't module_unneed() here because of the dll loader that wants - * close() in the same thread than open()/decode() */ + module_unneed( p_dec, p_dec->p_module ); /* */ if( p_dec->p_owner->cc.b_supported ) @@ -321,6 +367,7 @@ void input_DecoderDelete( decoder_t *p_dec ) /** * Put a block_t in the decoder's fifo. + * Thread-safe w.r.t. the decoder. May be a cancellation point. * * \param p_dec the decoder object * \param p_block the data block @@ -331,17 +378,17 @@ void input_DecoderDecode( decoder_t *p_dec, block_t *p_block ) if( p_owner->p_input->p->b_out_pace_control ) { - /* FIXME !!!!! */ - while( vlc_object_alive( p_dec ) && !p_dec->b_error && - block_FifoCount( p_owner->p_fifo ) > 10 ) - { - msleep( 1000 ); - } + /* The fifo is not consummed when buffering and so will + * deadlock vlc. + * There is no need to lock as b_buffering is never modify + * inside decoder thread. */ + if( !p_owner->b_buffering ) + block_FifoPace( p_owner->p_fifo, 10, SIZE_MAX ); } else if( block_FifoSize( p_owner->p_fifo ) > 50000000 /* 50 MB */ ) { /* FIXME: ideally we would check the time amount of data - * in the fifo instead of its size. */ + * in the FIFO instead of its size. */ msg_Warn( p_dec, "decoder/packetizer fifo full (data not " "consumed quickly enough), resetting fifo!" ); block_FifoEmpty( p_owner->p_fifo ); @@ -393,8 +440,8 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) 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"), + _("VLC could not open the decoder module.") ); return VLC_EGENERIC; } else if( !p_cc->p_module ) @@ -453,6 +500,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 ); DecoderOutputChangePause( p_dec, b_paused, i_date ); @@ -477,10 +525,12 @@ void input_DecoderStartBuffering( decoder_t *p_dec ) DecoderFlush( p_dec ); + 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 ); + 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; @@ -491,6 +541,10 @@ void input_DecoderStartBuffering( decoder_t *p_dec ) p_owner->buffer.p_audio = NULL; p_owner->buffer.pp_audio_next = &p_owner->buffer.p_audio; + p_owner->buffer.p_block = NULL; + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + + p_owner->b_buffering = true; vlc_cond_signal( &p_owner->wait ); @@ -526,9 +580,93 @@ void input_DecoderWaitBuffering( decoder_t *p_dec ) 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; + + *pi_duration = 0; + + vlc_mutex_lock( &p_owner->lock ); + 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 ); + } + } + else + { + /* TODO subtitle should not be flushed */ + DecoderFlush( p_dec ); + } + 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; +} + /***************************************************************************** * Internal functions *****************************************************************************/ +static int DecoderGetInputAttachments( decoder_t *p_dec, + input_attachment_t ***ppp_attachment, + int *pi_attachment ) +{ + return input_Control( p_dec->p_owner->p_input, INPUT_GET_ATTACHMENTS, + ppp_attachment, pi_attachment ); +} +static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + vlc_mutex_lock( &p_owner->lock ); + if( p_owner->b_buffering || p_owner->b_paused ) + i_ts = 0; + vlc_mutex_unlock( &p_owner->lock ); + + if( !p_owner->p_clock || !i_ts ) + return i_ts; + + if( input_clock_ConvertTS( p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) + return 0; + + return i_ts; +} +static int DecoderGetDisplayRate( decoder_t *p_dec ) +{ + decoder_owner_sys_t *p_owner = p_dec->p_owner; + + if( !p_owner->p_clock ) + return INPUT_RATE_DEFAULT; + return input_clock_GetRate( p_owner->p_clock ); +} /* */ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) @@ -536,9 +674,10 @@ static void DecoderUnsupportedCodec( decoder_t *p_dec, vlc_fourcc_t codec ) msg_Err( p_dec, "no suitable decoder module for fourcc `%4.4s'.\n" "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 ); } @@ -555,6 +694,8 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, { decoder_t *p_dec; decoder_owner_sys_t *p_owner; + es_format_t null_es_format; + int i; p_dec = vlc_object_create( p_input, i_object_type ); @@ -567,13 +708,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 ) @@ -611,14 +754,18 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, p_dec->pf_picture_unlink = vout_unlink_picture; p_dec->pf_spu_buffer_new = spu_new_buffer; p_dec->pf_spu_buffer_del = spu_del_buffer; + /* */ + p_dec->pf_get_attachments = DecoderGetInputAttachments; + p_dec->pf_get_display_date = DecoderGetDisplayDate; + p_dec->pf_get_display_rate = DecoderGetDisplayRate; vlc_object_attach( p_dec, p_input ); /* Find a suitable decoder/packetizer module */ if( i_object_type == VLC_OBJECT_DECODER ) - p_dec->p_module = module_need( p_dec, "decoder", "$codec", 0 ); + 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 && @@ -638,7 +785,7 @@ 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 ) { @@ -671,15 +818,22 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, vlc_mutex_init( &p_owner->lock ); vlc_cond_init( &p_owner->wait ); + 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_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_flushing = false; @@ -712,42 +866,47 @@ static void *DecoderThread( vlc_object_t *p_this ) decoder_t *p_dec = (decoder_t *)p_this; decoder_owner_sys_t *p_owner = p_dec->p_owner; - int canc = vlc_savecancel(); - /* The decoder's main loop */ - while( vlc_object_alive( p_dec ) && !p_dec->b_error ) + 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 && DecoderProcess( p_dec, p_block ) != VLC_SUCCESS ) - break; - } - - while( vlc_object_alive( p_dec ) ) - { - block_t *p_block = block_FifoGet( p_owner->p_fifo ); + if( p_block ) + { + int canc = vlc_savecancel(); - DecoderSignalBuffering( p_dec, p_block == NULL ); + if( p_dec->b_error ) + DecoderError( p_dec, p_block ); + else + DecoderProcess( p_dec, p_block ); - /* Trash all received PES packets */ - if( p_block ) - block_Release( p_block ); + vlc_restorecancel( canc ); + } } - DecoderSignalBuffering( p_dec, true ); - - /* We do it here because of the dll loader that wants close() in the - * same thread than open()/decode() */ - module_unneed( p_dec, p_dec->p_module ); - vlc_restorecancel( canc ); return NULL; } +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 ); @@ -759,15 +918,9 @@ static void DecoderFlush( decoder_t *p_dec ) vlc_cond_signal( &p_owner->wait ); /* 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 ); /* */ @@ -828,8 +981,21 @@ static void DecoderWaitUnblock( decoder_t *p_dec, bool *pb_reject ) while( !p_owner->b_flushing ) { - if( !p_owner->b_paused && ( !p_owner->b_buffering || !p_owner->buffer.b_full ) ) - break; + if( p_owner->b_paused ) + { + if( p_owner->b_buffering && !p_owner->buffer.b_full ) + break; + if( p_owner->pause.i_ignore > 0 ) + { + p_owner->pause.i_ignore--; + break; + } + } + else + { + if( !p_owner->b_buffering || !p_owner->buffer.b_full ) + break; + } vlc_cond_wait( &p_owner->wait, &p_owner->lock ); } @@ -847,13 +1013,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 ); @@ -863,13 +1029,13 @@ 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 ) *pi_preroll = __MIN( *pi_preroll, p->i_dts ); + else if( p->i_pts > 0 ) + *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(); @@ -878,41 +1044,43 @@ static mtime_t DecoderTeletextFixTs( mtime_t i_ts, mtime_t i_ts_delay ) { /* 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 ); + { + *pi_ts0 += i_es_delay; + if( pi_ts1 && *pi_ts1 > 0 ) + *pi_ts1 += i_es_delay; + if( input_clock_ConvertTS( p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) + *pi_ts0 = 0; + } + 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; @@ -922,16 +1090,11 @@ 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 <= 0 ) *pi_ts1 = *pi_ts0; } } - if( pi_delay ) - { - const int r = i_rate > 0 ? i_rate : INPUT_RATE_DEFAULT; - *pi_delay = i_ts_delay + i_es_delay * r / INPUT_RATE_DEFAULT; - } } static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, @@ -987,6 +1150,7 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, p_audio = p_owner->buffer.p_audio; p_owner->buffer.p_audio = p_audio->p_next; + p_owner->buffer.i_count--; b_has_more = p_owner->buffer.p_audio != NULL; if( !b_has_more ) @@ -994,51 +1158,61 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, } /* */ + const bool b_dated = p_audio->start_date > 0; 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 ); + &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->start_date <= 0 || i_rate < INPUT_RATE_DEFAULT/AOUT_MAX_INPUT_RATE || i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) b_reject = true; - if( !b_reject ) + /* Do not wait against unprotected date */ + const mtime_t i_deadline = p_audio->start_date - AOUT_MAX_PREPARE_TIME; + while( !b_reject && i_deadline > mdate() ) { - /* Wait if we are too early - * FIXME that's plain ugly to do it here */ - mwait( p_audio->start_date - AOUT_MAX_PREPARE_TIME ); + vlc_mutex_lock( &p_owner->lock ); + if( p_owner->b_flushing || p_dec->b_die ) + { + b_reject = true; + vlc_mutex_unlock( &p_owner->lock ); + break; + } + vlc_cond_timedwait( &p_owner->wait, &p_owner->lock, i_deadline ); + vlc_mutex_unlock( &p_owner->lock ); + } + if( !b_reject ) + { 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 ); } if( !b_has_more ) break; + vlc_mutex_lock( &p_owner->lock ); + if( !p_owner->buffer.p_audio ) + { + vlc_mutex_unlock( &p_owner->lock ); + break; + } } } @@ -1055,8 +1229,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 ) { @@ -1140,66 +1312,26 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) } vlc_mutex_unlock( &p_owner->lock ); } -static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic ) -{ - vlc_mutex_lock( &p_vout->picture_lock ); - - if( p_pic->i_status == READY_PICTURE ) - { - /* Grr cannot destroy ready picture by myself so be sure vout won't like it */ - p_pic->date = 1; - } - else if( p_pic->i_refcount > 0 ) - { - p_pic->i_status = DISPLAYED_PICTURE; - } - else - { - p_pic->i_status = DESTROYED_PICTURE; - picture_CleanupQuant( p_pic ); - p_vout->i_heap_size--; - } - - vlc_mutex_unlock( &p_vout->picture_lock ); -} -static void VoutFlushPicture( vout_thread_t *p_vout, mtime_t i_max_date ) -{ - int i; - vlc_mutex_lock( &p_vout->picture_lock ); - for( i = 0; i < p_vout->render.i_pictures; i++ ) - { - picture_t *p_pic = p_vout->render.pp_picture[i]; - - if( p_pic->i_status == READY_PICTURE || - p_pic->i_status == DISPLAYED_PICTURE ) - { - /* We cannot change picture status if it is in READY_PICTURE state, - * Just make sure they won't be displayed */ - if( p_pic->date > i_max_date ) - p_pic->date = i_max_date; - } - } - vlc_mutex_unlock( &p_vout->picture_lock ); -} static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, int *pi_played_sum, int *pi_lost_sum ) { 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 <= 0 ) { msg_Warn( p_vout, "non-dated video buffer received" ); *pi_lost_sum += 1; - VoutDisplayedPicture( p_vout, p_picture ); + vout_DropPicture( p_vout, p_picture ); return; } /* */ vlc_mutex_lock( &p_owner->lock ); - if( p_owner->b_buffering || p_owner->buffer.p_picture ) + if( ( p_owner->b_buffering && !p_owner->buffer.b_first ) || p_owner->buffer.p_picture ) { p_picture->p_next = NULL; @@ -1214,19 +1346,22 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, vlc_cond_signal( &p_owner->wait ); } } + b_first_buffered = p_owner->buffer.p_picture != NULL; - for( ;; ) + for( ;; b_first_buffered = false ) { bool b_has_more = false; bool b_reject; + DecoderWaitUnblock( p_dec, &b_reject ); - if( p_owner->b_buffering ) + 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 ) @@ -1234,6 +1369,7 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *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 ) @@ -1241,46 +1377,45 @@ 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 ); + assert( !p_owner->buffer.i_count ); + msg_Dbg( p_dec, "Received first picture" ); + p_owner->buffer.b_first = false; + p_picture->b_force = true; + } + const bool b_dated = p_picture->date > 0; + 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 + VOUT_BOGUS_DELAY; - - if( p_picture->date <= 0 || p_picture->date >= i_max_date ) + if( !p_picture->b_force && p_picture->date <= 0 ) b_reject = true; if( !b_reject ) { - if( i_rate != p_owner->i_last_rate ) + if( i_rate != p_owner->i_last_rate || b_first_buffered ) { /* Be sure to not display old picture after our own */ - VoutFlushPicture( p_vout, p_picture->date ); + vout_Flush( p_vout, p_picture->date ); p_owner->i_last_rate = i_rate; } - - vout_DatePicture( p_vout, p_picture, p_picture->date ); - vout_DisplayPicture( 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; - VoutDisplayedPicture( p_vout, p_picture ); + vout_DropPicture( p_vout, p_picture ); } int i_tmp_display; int i_tmp_lost; @@ -1289,9 +1424,15 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, *pi_played_sum += i_tmp_display; *pi_lost_sum += i_tmp_lost; - if( !b_has_more ) + if( !b_has_more || b_buffering_first ) break; + vlc_mutex_lock( &p_owner->lock ); + if( !p_owner->buffer.p_picture ) + { + vlc_mutex_unlock( &p_owner->lock ); + break; + } } } @@ -1310,7 +1451,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 */ - VoutDisplayedPicture( p_vout, p_pic ); + vout_DropPicture( p_vout, p_pic ); if( p_block ) block_Release( p_block ); break; @@ -1320,7 +1461,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) if( p_pic->date < p_owner->i_preroll_end ) { - VoutDisplayedPicture( p_vout, p_pic ); + vout_DropPicture( p_vout, p_pic ); continue; } @@ -1328,7 +1469,7 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) { msg_Dbg( p_dec, "End of video preroll" ); if( p_vout ) - VoutFlushPicture( p_vout, 1 ); + vout_Flush( p_vout, 1 ); /* */ p_owner->i_preroll_end = -1; } @@ -1406,6 +1547,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, p_subpic = p_owner->buffer.p_subpic; p_owner->buffer.p_subpic = p_subpic->p_next; + p_owner->buffer.i_count--; b_has_more = p_owner->buffer.p_subpic != NULL; if( !b_has_more ) @@ -1414,7 +1556,7 @@ 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 ); @@ -1426,6 +1568,11 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, if( !b_has_more ) break; vlc_mutex_lock( &p_owner->lock ); + if( !p_owner->buffer.p_subpic ) + { + vlc_mutex_unlock( &p_owner->lock ); + break; + } } } @@ -1435,18 +1582,69 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block, decoder_owner_sys_t *p_owner = p_dec->p_owner; assert( p_owner->p_clock ); + assert( !p_sout_block->p_next ); vlc_mutex_lock( &p_owner->lock ); - bool b_reject; - DecoderWaitUnblock( p_dec, &b_reject ); + if( p_owner->b_buffering || p_owner->buffer.p_block ) + { + block_ChainLastAppend( &p_owner->buffer.pp_block_next, p_sout_block ); + + 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 ); + } + } + + for( ;; ) + { + bool b_has_more = false; + bool b_reject; + DecoderWaitUnblock( p_dec, &b_reject ); - 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 ); + if( p_owner->b_buffering ) + { + vlc_mutex_unlock( &p_owner->lock ); + return; + } - vlc_mutex_unlock( &p_owner->lock ); + /* */ + if( p_owner->buffer.p_block ) + { + p_sout_block = p_owner->buffer.p_block; + + p_owner->buffer.p_block = p_sout_block->p_next; + p_owner->buffer.i_count--; + + b_has_more = p_owner->buffer.p_block != NULL; + if( !b_has_more ) + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + } + p_sout_block->p_next = NULL; + + DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts, + &p_sout_block->i_length, + &p_sout_block->i_rate, INT64_MAX, b_telx ); + + vlc_mutex_unlock( &p_owner->lock ); + + if( !b_reject ) + sout_InputSendBuffer( p_owner->p_sout_input, p_sout_block ); + else + block_Release( p_sout_block ); - sout_InputSendBuffer( p_owner->p_sout_input, 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; + } + } } /* */ @@ -1464,7 +1662,7 @@ static void DecoderFlushBuffering( decoder_t *p_dec ) p_owner->buffer.i_count--; if( p_owner->p_vout ) - VoutDisplayedPicture( p_owner->p_vout, p_picture ); + vout_DropPicture( p_owner->p_vout, p_picture ); if( !p_owner->buffer.p_picture ) p_owner->buffer.pp_picture_next = &p_owner->buffer.p_picture; @@ -1493,6 +1691,14 @@ static void DecoderFlushBuffering( decoder_t *p_dec ) if( !p_owner->buffer.p_subpic ) p_owner->buffer.pp_subpic_next = &p_owner->buffer.p_subpic; } + if( p_owner->buffer.p_block ) + { + block_ChainRelease( p_owner->buffer.p_block ); + + p_owner->buffer.i_count = 0; + p_owner->buffer.p_block = NULL; + p_owner->buffer.pp_block_next = &p_owner->buffer.p_block; + } } /* This function process a block for sout @@ -1599,6 +1805,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 ) { @@ -1606,7 +1820,7 @@ static void DecoderProcessVideo( decoder_t *p_dec, block_t *p_block, bool b_flus } if( b_flush && p_owner->p_vout ) - VoutFlushPicture( p_owner->p_vout, 1 ); + vout_Flush( p_owner->p_vout, 1 ); } /* This function process a audio block @@ -1639,6 +1853,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 ) { @@ -1666,7 +1888,7 @@ 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 */ @@ -1691,7 +1913,7 @@ 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, @@ -1702,6 +1924,17 @@ 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 ); + vlc_mutex_unlock( &p_owner->lock ); + + DecoderSignalFlushed( p_dec ); +} /** * Decode a block * @@ -1709,7 +1942,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); @@ -1718,11 +1951,11 @@ static int DecoderProcess( decoder_t *p_dec, block_t *p_block ) { assert( !b_flush_request ); block_Release( p_block ); - return VLC_SUCCESS; + return; } #ifdef ENABLE_SOUT - if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER ) + if( vlc_internals( p_dec )->i_object_type == VLC_OBJECT_PACKETIZER ) { if( p_block ) p_block->i_flags &= ~BLOCK_FLAG_CORE_PRIVATE_MASK; @@ -1744,15 +1977,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 ); } @@ -1765,17 +1998,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 ); - } +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 * @@ -1804,25 +2042,22 @@ 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 */ - for( int i_pic = 0; i_pic < p_owner->p_vout->render.i_pictures; i_pic++ ) - { - picture_t *p_pic = p_owner->p_vout->render.pp_picture[i_pic]; + /* Hack to make sure all the the pictures are freed by the decoder + * and that the vout is not paused anymore */ + vout_FixLeaks( p_owner->p_vout, true ); + if( p_owner->b_paused ) + vout_ChangePause( p_owner->p_vout, false, mdate() ); - if( p_pic->i_status == RESERVED_PICTURE ) - vout_DestroyPicture( p_owner->p_vout, p_pic ); - if( p_pic->i_refcount > 0 ) - vout_UnlinkPicture( p_owner->p_vout, p_pic ); - } - - /* We are about to die. Reattach video output to p_vlc. */ - vout_Request( p_dec, p_owner->p_vout, NULL ); - var_SetBool( p_owner->p_input, "intf-change-vout", true ); + /* */ + input_resource_RequestVout( p_owner->p_input->p->p_resource, p_owner->p_vout, NULL, true ); + input_SendEventVout( p_owner->p_input ); } #ifdef ENABLE_SOUT @@ -1833,21 +2068,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( p_vout->p_spu, 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 ) { @@ -1855,6 +2095,8 @@ 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 ); + if( p_owner->p_packetizer->p_description ) + vlc_meta_Delete( p_owner->p_packetizer->p_description ); vlc_object_detach( p_owner->p_packetizer ); vlc_object_release( p_owner->p_packetizer ); } @@ -1870,6 +2112,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; @@ -1901,15 +2173,17 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) 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; memcpy( &format, &p_owner->audio, sizeof( audio_sample_format_t ) ); - if ( i_force_dolby && (format.i_original_channels&AOUT_CHAN_PHYSMASK) - == (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) ) + if( i_force_dolby && + (format.i_original_channels&AOUT_CHAN_PHYSMASK) == + (AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT) ) { - if ( i_force_dolby == 1 ) + if( i_force_dolby == 1 ) { format.i_original_channels = format.i_original_channels | AOUT_CHAN_DOLBYSTEREO; @@ -1921,15 +2195,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" ); @@ -2030,13 +2314,17 @@ 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 ); - var_SetBool( p_owner->p_input, "intf-change-vout", true ); + input_SendEventVout( p_owner->p_input ); if( p_vout == NULL ) { msg_Err( p_dec, "failed to create video output" ); @@ -2057,7 +2345,6 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) for( ;; ) { picture_t *p_picture; - int i_pic, i_ready_pic; if( p_dec->b_die || p_dec->b_error ) return NULL; @@ -2081,55 +2368,16 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) DecoderSignalBuffering( p_dec, true ); /* Check the decoder doesn't leak pictures */ - for( i_pic = 0, i_ready_pic = 0; i_pic < p_owner->p_vout->render.i_pictures; i_pic++ ) - { - const picture_t *p_pic = p_owner->p_vout->render.pp_picture[i_pic]; - - if( p_pic->i_status == READY_PICTURE ) - { - i_ready_pic++; - /* If we have at least 2 ready pictures, wait for the vout thread to - * process one */ - if( i_ready_pic >= 2 ) - break; - - continue; - } - - if( p_pic->i_status == DISPLAYED_PICTURE ) - { - /* If at least one displayed picture is not referenced - * let vout free it */ - if( p_pic->i_refcount == 0 ) - break; - } - } - - if( i_pic == p_owner->p_vout->render.i_pictures ) - { - /* Too many pictures are still referenced, there is probably a bug - * with the decoder */ - msg_Err( p_dec, "decoder is leaking pictures, resetting the heap" ); - - /* Just free all the pictures */ - for( i_pic = 0; i_pic < p_owner->p_vout->render.i_pictures; i_pic++ ) - { - picture_t *p_pic = p_owner->p_vout->render.pp_picture[i_pic]; - - if( p_pic->i_status == RESERVED_PICTURE ) - vout_DestroyPicture( p_owner->p_vout, p_pic ); - if( p_pic->i_refcount > 0 ) - vout_UnlinkPicture( p_owner->p_vout, p_pic ); - } - } + vout_FixLeaks( p_owner->p_vout, false ); + /* FIXME add a vout_WaitPictureAvailable (timedwait) */ msleep( VOUT_OUTMEM_SLEEP ); } } static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic ) { - VoutDisplayedPicture( p_dec->p_owner->p_vout, p_pic ); + vout_DropPicture( p_dec->p_owner->p_vout, p_pic ); } static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic ) @@ -2154,11 +2402,11 @@ 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; - msleep( VOUT_DISPLAY_DELAY ); + msleep( DECODER_SPU_VOUT_WAIT_DURATION ); } if( !p_vout ) @@ -2199,7 +2447,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 )