#include <vlc_sout.h>
#include <vlc_codec.h>
#include <vlc_osd.h>
+#include <vlc_meta.h>
#include <vlc_interface.h>
#include "audio_output/aout_internal.h"
#include "input_internal.h"
#include "clock.h"
#include "decoder.h"
+#include "event.h"
+#include "ressource.h"
#include "../video_output/vout_control.h"
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 );
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;
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 );
- }
+ 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 );
vlc_thread_join( p_dec );
if( p_owner->p_input->p->b_out_pace_control )
{
- block_FifoPace( p_owner->p_fifo, 10, SIZE_MAX );
+ /* 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 */ )
{
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;
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
*****************************************************************************/
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 )
/* 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 &&
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 )
{
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;
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 )
- { /* Trash all received PES packets */
- block_Release( p_block );
- }
- else if( DecoderProcess( p_dec, p_block ) != VLC_SUCCESS )
- {
- break;
- }
+ DecoderError( p_dec, p_block );
+ else
+ DecoderProcess( p_dec, p_block );
+
+ vlc_restorecancel( canc );
}
+ /* Ensure fast cancellation in case the fifo is not empty */
+ vlc_testcancel();
}
-
- DecoderSignalBuffering( p_dec, true );
return NULL;
}
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 );
{
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 )
{
}
/* */
- int i_rate = INPUT_RATE_DEFAULT;
- mtime_t i_delay;
-
if( b_buffering_first )
{
assert( p_owner->buffer.b_first );
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 );
}
+
+ int i_rate = INPUT_RATE_DEFAULT;
+ mtime_t i_delay;
DecoderFixTs( p_dec, &p_picture->date, NULL, NULL,
&i_rate, &i_delay, false );
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 );
if( p_owner->b_buffering || p_owner->buffer.p_block )
{
- p_sout_block->p_next = NULL;
-
block_ChainLastAppend( &p_owner->buffer.pp_block_next, p_sout_block );
p_owner->buffer.i_count++;
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,
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_ressource_HoldVout( p_input->p->p_ressource );
if( p_vout && p_owner->p_spu_vout == p_vout )
{
/* Preroll does not work very well with subtitle */
if( b_flush && p_owner->p_spu_vout )
{
- p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
+ p_vout = input_ressource_HoldVout( p_input->p->p_ressource );
if( p_vout && p_owner->p_spu_vout == p_vout )
spu_Control( p_vout->p_spu, SPU_CHANNEL_CLEAR,
}
}
+/* */
+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
*
* \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);
{
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( 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
*
aout_DecDelete( p_owner->p_aout, p_owner->p_aout_input );
if( p_owner->p_aout )
{
- vlc_object_release( p_owner->p_aout );
+ input_ressource_RequestAout( p_owner->p_input->p->p_ressource,
+ 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 );
- /* 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_ressource_RequestVout( p_owner->p_input->p->p_ressource, p_owner->p_vout, NULL );
+ input_SendEventVout( p_owner->p_input );
}
#ifdef ENABLE_SOUT
{
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_ressource_HoldVout( p_owner->p_input->p->p_ressource );
+ 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 )
{
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 );
}
/*****************************************************************************
* 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 )
+{
+ decoder_t *p_dec = p_private;
+
+ p_vout = input_ressource_RequestVout( p_dec->p_owner->p_input->p->p_ressource, p_vout, p_fmt );
+ input_SendEventVout( p_dec->p_owner->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;
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;
}
}
+ 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_ressource_RequestAout( p_owner->p_input->p->p_ressource, 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" );
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_ressource_RequestVout( p_owner->p_input->p->p_ressource,
+ p_vout, &p_dec->fmt_out.video );
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" );
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_ressource_HoldVout( p_owner->p_input->p->p_ressource );
if( p_vout )
break;
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_ressource_HoldVout( p_owner->p_input->p->p_ressource );
if( !p_vout || p_owner->p_spu_vout != p_vout )
{
if( p_vout )