#include "../video_output/vout_control.h"
static decoder_t *CreateDecoder( vlc_object_t *, input_thread_t *,
- es_format_t *, bool, input_resource_t *,
+ const es_format_t *, bool, input_resource_t *,
sout_instance_t *p_sout );
static void DeleteDecoder( decoder_t * );
static void *DecoderThread( void * );
static void DecoderProcess( decoder_t *, block_t * );
static void DecoderFlush( decoder_t * );
-static void DecoderSignalWait( decoder_t *, bool );
+static void DecoderSignalWait( decoder_t * );
static void DecoderUnsupportedCodec( decoder_t *, vlc_fourcc_t );
/* Buffers allocation callbacks for the decoders */
+static int vout_update_format( decoder_t * );
static picture_t *vout_new_buffer( decoder_t * );
-static void vout_del_buffer( decoder_t *, picture_t * );
-static void vout_link_picture( decoder_t *, picture_t * );
-static void vout_unlink_picture( decoder_t *, picture_t * );
static int aout_update_format( decoder_t * );
static subpicture_t *spu_new_buffer( decoder_t *, const subpicture_updater_t * );
-static void spu_del_buffer( decoder_t *, subpicture_t * );
struct decoder_owner_sys_t
{
vout_thread_t *p_vout;
/* -- Theses variables need locking on read *and* write -- */
- bool b_exit;
-
/* Pause */
bool b_paused;
struct
} pause;
/* Waiting */
+ bool b_woken;
bool b_waiting;
bool b_first;
bool b_has_data;
*****************************************************************************/
picture_t *decoder_NewPicture( decoder_t *p_decoder )
{
+ if( decoder_UpdateVideoFormat( p_decoder ) )
+ return NULL;
+
picture_t *p_picture = p_decoder->pf_vout_buffer_new( p_decoder );
if( !p_picture )
msg_Warn( p_decoder, "can't get output picture" );
return p_picture;
}
-void decoder_DeletePicture( decoder_t *p_decoder, picture_t *p_picture )
-{
- p_decoder->pf_vout_buffer_del( p_decoder, p_picture );
-}
-void decoder_LinkPicture( decoder_t *p_decoder, picture_t *p_picture )
-{
- p_decoder->pf_picture_link( p_decoder, p_picture );
-}
-void decoder_UnlinkPicture( decoder_t *p_decoder, picture_t *p_picture )
-{
- p_decoder->pf_picture_unlink( p_decoder, p_picture );
-}
block_t *decoder_NewAudioBuffer( decoder_t *dec, int samples )
{
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,
/* TODO: pass p_sout through p_resource? -- Courmisch */
static decoder_t *decoder_New( vlc_object_t *p_parent, input_thread_t *p_input,
- es_format_t *fmt, input_clock_t *p_clock,
+ const es_format_t *fmt, input_clock_t *p_clock,
input_resource_t *p_resource,
sout_instance_t *p_sout )
{
/**
* Spawn a decoder thread outside of the input thread.
*/
-decoder_t *input_DecoderCreate( vlc_object_t *p_parent, es_format_t *fmt,
+decoder_t *input_DecoderCreate( vlc_object_t *p_parent, const es_format_t *fmt,
input_resource_t *p_resource )
{
return decoder_New( p_parent, NULL, fmt, NULL, p_resource, NULL );
/* Make sure we aren't paused/waiting/decoding anymore */
vlc_mutex_lock( &p_owner->lock );
- const bool b_was_paused = p_owner->b_paused;
p_owner->b_paused = false;
p_owner->b_waiting = false;
p_owner->b_flushing = true;
- p_owner->b_exit = true;
vlc_cond_signal( &p_owner->wait_request );
vlc_mutex_unlock( &p_owner->lock );
vlc_join( p_owner->thread, NULL );
- p_owner->b_paused = b_was_paused;
module_unneed( p_dec, p_dec->p_module );
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
- if( b_do_pace )
- {
- /* The fifo is not consumed when waiting and so will
- * deadlock vlc.
- * There is no need to lock as b_waiting is never modified
- * inside decoder thread. */
- if( !p_owner->b_waiting )
- block_FifoPace( p_owner->p_fifo, 10, SIZE_MAX );
- }
-#ifdef __arm__
- else if( block_FifoSize( p_owner->p_fifo ) > 50*1024*1024 /* 50 MiB */ )
-#else
- else if( block_FifoSize( p_owner->p_fifo ) > 400*1024*1024 /* 400 MiB, ie ~ 50mb/s for 60s */ )
-#endif
+ vlc_fifo_Lock( p_owner->p_fifo );
+ if( !b_do_pace )
{
/* FIXME: ideally we would check the time amount of data
* in the FIFO instead of its size. */
- msg_Warn( p_dec, "decoder/packetizer fifo full (data not "
- "consumed quickly enough), resetting fifo!" );
- block_FifoEmpty( p_owner->p_fifo );
+ /* 400 MiB, i.e. ~ 50mb/s for 60s */
+ if( vlc_fifo_GetBytes( p_owner->p_fifo ) > 400*1024*1024 )
+ {
+ msg_Warn( p_dec, "decoder/packetizer fifo full (data not "
+ "consumed quickly enough), resetting fifo!" );
+ block_ChainRelease( vlc_fifo_DequeueAllUnlocked( p_owner->p_fifo ) );
+ }
+ }
+ else
+ if( !p_owner->b_waiting )
+ { /* The FIFO is not consumed when waiting, so pacing would deadlock VLC.
+ * Locking is not necessary as b_waiting is only read, not written by
+ * the decoder thread. */
+ while( vlc_fifo_GetCount( p_owner->p_fifo ) >= 10 )
+ vlc_fifo_WaitCond( p_owner->p_fifo, &p_owner->wait_acknowledge );
}
- block_FifoPut( p_owner->p_fifo, p_block );
+ vlc_fifo_QueueUnlocked( p_owner->p_fifo, p_block );
+ vlc_fifo_Unlock( p_owner->p_fifo );
}
bool input_DecoderIsEmpty( decoder_t * p_dec )
{
vlc_mutex_lock( &p_owner->lock );
/* TODO subtitles support */
- if( p_dec->fmt_out.i_cat == VIDEO_ES && p_owner->p_vout )
+ if( p_owner->fmt.i_cat == VIDEO_ES && p_owner->p_vout )
b_empty = vout_IsEmpty( p_owner->p_vout );
- else if( p_dec->fmt_out.i_cat == AUDIO_ES && p_owner->p_aout )
+ else if( p_owner->fmt.i_cat == AUDIO_ES && p_owner->p_aout )
b_empty = aout_DecIsEmpty( p_owner->p_aout );
vlc_mutex_unlock( &p_owner->lock );
}
* - for sout it is useless
* - for subs, it is done by the vout
*/
- if( p_dec->fmt_out.i_cat == AUDIO_ES )
+ if( p_owner->fmt.i_cat == AUDIO_ES )
{
if( p_owner->p_aout )
aout_DecChangePause( p_owner->p_aout, b_paused, i_date );
}
- else if( p_dec->fmt_out.i_cat == VIDEO_ES )
+ else if( p_owner->fmt.i_cat == VIDEO_ES )
{
if( p_owner->p_vout )
vout_ChangePause( p_owner->p_vout, b_paused, i_date );
vlc_mutex_unlock( &p_owner->lock );
}
-void input_DecoderStartWait( decoder_t *p_dec )
+/**
+ * Requests that the decoder immediately discard all pending buffers.
+ * This is useful at end of stream, when seeking or when deselecting a stream.
+ */
+void input_DecoderFlush( decoder_t *p_dec )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
vlc_mutex_lock( &p_owner->lock );
-
DecoderFlush( p_dec );
+ vlc_mutex_unlock( &p_owner->lock );
+}
+void input_DecoderStartWait( decoder_t *p_dec )
+{
+ decoder_owner_sys_t *p_owner = p_dec->p_owner;
+
+ assert( !p_owner->b_waiting );
+
+ vlc_mutex_lock( &p_owner->lock );
p_owner->b_first = true;
p_owner->b_has_data = false;
-
p_owner->b_waiting = true;
-
vlc_cond_signal( &p_owner->wait_request );
-
vlc_mutex_unlock( &p_owner->lock );
}
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
- vlc_mutex_lock( &p_owner->lock );
+ assert( p_owner->b_waiting );
+ vlc_mutex_lock( &p_owner->lock );
p_owner->b_waiting = false;
-
vlc_cond_signal( &p_owner->wait_request );
-
vlc_mutex_unlock( &p_owner->lock );
}
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
- vlc_mutex_lock( &p_owner->lock );
+ assert( p_owner->b_waiting );
- while( p_owner->b_waiting && !p_owner->b_has_data )
+ vlc_mutex_lock( &p_owner->lock );
+ while( !p_owner->b_has_data )
{
- block_FifoWake( p_owner->p_fifo );
+ vlc_fifo_Lock( p_owner->p_fifo );
+ p_owner->b_woken = true;
+ vlc_fifo_Signal( p_owner->p_fifo );
+ vlc_fifo_Unlock( p_owner->p_fifo );
vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
}
-
vlc_mutex_unlock( &p_owner->lock );
}
*pi_duration = 0;
vlc_mutex_lock( &p_owner->lock );
- if( p_dec->fmt_out.i_cat == VIDEO_ES )
+ if( p_owner->fmt.i_cat == VIDEO_ES )
{
if( p_owner->b_paused && p_owner->p_vout )
{
else
{
/* TODO subtitle should not be flushed */
+ p_owner->b_waiting = false;
DecoderFlush( p_dec );
}
vlc_mutex_unlock( &p_owner->lock );
if( !p_owner->p_clock || i_ts <= VLC_TS_INVALID )
return i_ts;
- if( input_clock_ConvertTS( p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) {
+ if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_owner->p_clock, NULL, &i_ts, NULL, INT64_MAX ) ) {
msg_Err(p_dec, "Could not get display date for timestamp %"PRId64"", i_ts);
return VLC_TS_INVALID;
}
*/
static decoder_t * CreateDecoder( vlc_object_t *p_parent,
input_thread_t *p_input,
- es_format_t *fmt, bool b_packetizer,
+ const es_format_t *fmt, bool b_packetizer,
input_resource_t *p_resource,
sout_instance_t *p_sout )
{
es_format_Init( &p_owner->fmt, UNKNOWN_ES, 0 );
/* decoder fifo */
+ p_owner->b_woken = false;
p_owner->p_fifo = block_FifoNew();
if( unlikely(p_owner->p_fifo == NULL) )
{
/* Set buffers allocation callbacks for the decoders */
p_dec->pf_aout_format_update = aout_update_format;
+ p_dec->pf_vout_format_update = vout_update_format;
p_dec->pf_vout_buffer_new = vout_new_buffer;
- p_dec->pf_vout_buffer_del = vout_del_buffer;
- p_dec->pf_picture_link = vout_link_picture;
- p_dec->pf_picture_unlink = vout_unlink_picture;
p_dec->pf_spu_buffer_new = spu_new_buffer;
- p_dec->pf_spu_buffer_del = spu_del_buffer;
/* */
p_dec->pf_get_attachments = DecoderGetInputAttachments;
p_dec->pf_get_display_date = DecoderGetDisplayDate;
p_owner->b_fmt_description = false;
p_owner->p_description = NULL;
- p_owner->b_exit = false;
-
p_owner->b_paused = false;
p_owner->pause.i_date = VLC_TS_INVALID;
p_owner->pause.i_ignore = 0;
/* The decoder's main loop */
for( ;; )
{
- block_t *p_block = block_FifoGet( p_owner->p_fifo );
+ block_t *p_block;
- /* Make sure there is no cancellation point other than this one^^.
- * If you need one, be sure to push cleanup of p_block. */
- bool end_wait = !p_block || p_block->i_flags & BLOCK_FLAG_CORE_EOS;
- DecoderSignalWait( p_dec, end_wait );
- if (end_wait)
- input_DecoderStopWait( p_dec );
+ vlc_fifo_Lock( p_owner->p_fifo );
+ vlc_fifo_CleanupPush( p_owner->p_fifo );
+
+ while( vlc_fifo_IsEmpty( p_owner->p_fifo ) )
+ {
+ if( p_owner->b_woken )
+ break;
+ vlc_fifo_Wait( p_owner->p_fifo );
+ /* Make sure there is no cancellation point other than this one^^.
+ * If you need one, be sure to push cleanup of p_block. */
+ }
+
+ p_block = vlc_fifo_DequeueUnlocked( p_owner->p_fifo );
+ if( p_block != NULL )
+ vlc_cond_signal( &p_owner->wait_acknowledge );
+
+ p_owner->b_woken = false;
+ vlc_cleanup_run();
+
+ if( p_block == NULL || p_block->i_flags & BLOCK_FLAG_CORE_EOS )
+ DecoderSignalWait( p_dec );
if( p_block )
{
/* Empty the fifo */
block_FifoEmpty( p_owner->p_fifo );
- p_owner->b_waiting = false;
/* Monitor for flush end */
p_owner->b_flushing = true;
vlc_cond_signal( &p_owner->wait_request );
vlc_cond_wait( &p_owner->wait_acknowledge, &p_owner->lock );
}
-static void DecoderSignalWait( decoder_t *p_dec, bool b_has_data )
+static void DecoderSignalWait( decoder_t *p_dec )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
if( p_owner->b_waiting )
{
- if( b_has_data )
- p_owner->b_has_data = true;
+ p_owner->b_has_data = true;
vlc_cond_signal( &p_owner->wait_acknowledge );
}
*pi_ts0 += i_es_delay;
if( pi_ts1 && *pi_ts1 > VLC_TS_INVALID )
*pi_ts1 += i_es_delay;
- if( input_clock_ConvertTS( p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) {
+ if( input_clock_ConvertTS( VLC_OBJECT(p_dec), p_clock, &i_rate, pi_ts0, pi_ts1, i_ts_bound ) ) {
if( pi_ts1 != NULL )
msg_Err(p_dec, "Could not convert timestamps %"PRId64
", %"PRId64"", *pi_ts0, *pi_ts1);
*pi_rate = i_rate;
}
-static bool DecoderIsExitRequested( decoder_t *p_dec )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
-
- vlc_mutex_lock( &p_owner->lock );
- bool b_exit = p_owner->b_exit;
- vlc_mutex_unlock( &p_owner->lock );
-
- return b_exit;
-}
-
/**
* 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.
do
{
- if( p_owner->b_flushing || p_owner->b_exit )
+ if( p_owner->b_flushing )
{
*pb_reject = true;
break;
}
else while( (p_aout_buf = p_dec->pf_decode_audio( p_dec, &p_block )) )
{
- if( DecoderIsExitRequested( p_dec ) )
+ if( DecoderIsFlushing( p_dec ) )
{
/* It prevent freezing VLC in case of broken decoder */
block_Release( p_aout_buf );
{
msg_Warn( p_dec, "non-dated video buffer received" );
*pi_lost_sum += 1;
- vout_ReleasePicture( p_vout, p_picture );
+ picture_Release( p_picture );
return;
}
msg_Warn( p_dec, "non-dated video buffer received" );
*pi_lost_sum += 1;
- vout_ReleasePicture( p_vout, p_picture );
+ picture_Release( p_picture );
}
int i_tmp_display;
int i_tmp_lost;
while( (p_pic = p_dec->pf_decode_video( p_dec, &p_block )) )
{
vout_thread_t *p_vout = p_owner->p_vout;
- if( DecoderIsExitRequested( p_dec ) )
- {
- /* It prevent freezing VLC in case of broken decoder */
- vout_ReleasePicture( p_vout, p_pic );
+ if( DecoderIsFlushing( p_dec ) )
+ { /* It prevent freezing VLC in case of broken decoder */
+ picture_Release( p_pic );
if( p_block )
block_Release( p_block );
break;
if( p_owner->i_preroll_end > VLC_TS_INVALID && p_pic->date < p_owner->i_preroll_end )
{
- vout_ReleasePicture( p_vout, p_pic );
+ picture_Release( p_pic );
continue;
}
(unsigned)block_FifoCount( p_owner->p_fifo ) );
/* Free all packets still in the decoder fifo. */
- block_FifoEmpty( p_owner->p_fifo );
block_FifoRelease( p_owner->p_fifo );
/* Cleanup */
DecoderUpdateFormatLocked( p_dec );
- if( unlikely(p_owner->b_paused) ) /* fake pause if needed */
+ if( unlikely(p_owner->b_paused) && p_aout != NULL )
+ /* fake pause if needed */
aout_DecChangePause( p_aout, true, mdate() );
vlc_mutex_unlock( &p_owner->lock );
return 0;
}
-static picture_t *vout_new_buffer( decoder_t *p_dec )
+static int vout_update_format( decoder_t *p_dec )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
!p_dec->fmt_out.video.i_height )
{
/* Can't create a new vout without display size */
- return NULL;
+ return -1;
}
video_format_t fmt = p_dec->fmt_out.video;
{
msg_Err( p_dec, "failed to create video output" );
p_dec->b_error = true;
- return NULL;
+ return -1;
}
}
+ return 0;
+}
+
+static picture_t *vout_new_buffer( decoder_t *p_dec )
+{
+ decoder_owner_sys_t *p_owner = p_dec->p_owner;
- /* Get a new picture
- */
for( ;; )
{
- if( DecoderIsExitRequested( p_dec ) || p_dec->b_error )
+ if( DecoderIsFlushing( p_dec ) || p_dec->b_error )
return NULL;
picture_t *p_picture = vout_GetPicture( p_owner->p_vout );
if( p_picture )
return p_picture;
- if( DecoderIsFlushing( p_dec ) )
- return NULL;
-
/* */
- DecoderSignalWait( p_dec, true );
+ DecoderSignalWait( p_dec );
/* Check the decoder doesn't leak pictures */
vout_FixLeaks( p_owner->p_vout );
}
}
-static void vout_del_buffer( decoder_t *p_dec, picture_t *p_pic )
-{
- vout_ReleasePicture( p_dec->p_owner->p_vout, p_pic );
-}
-
-static void vout_link_picture( decoder_t *p_dec, picture_t *p_pic )
-{
- vout_HoldPicture( p_dec->p_owner->p_vout, p_pic );
-}
-
-static void vout_unlink_picture( decoder_t *p_dec, picture_t *p_pic )
-{
- vout_ReleasePicture( p_dec->p_owner->p_vout, p_pic );
-}
-
static subpicture_t *spu_new_buffer( decoder_t *p_dec,
const subpicture_updater_t *p_updater )
{
while( i_attempts-- )
{
- if( DecoderIsExitRequested( p_dec ) || p_dec->b_error )
+ if( DecoderIsFlushing( p_dec ) || p_dec->b_error )
break;
p_vout = input_resource_HoldVout( p_owner->p_resource );
return p_subpic;
}
-
-static void spu_del_buffer( decoder_t *p_dec, subpicture_t *p_subpic )
-{
- decoder_owner_sys_t *p_owner = p_dec->p_owner;
- vout_thread_t *p_vout = NULL;
-
- p_vout = input_resource_HoldVout( p_owner->p_resource );
- if( !p_vout || p_owner->p_spu_vout != p_vout )
- {
- if( p_vout )
- vlc_object_release( p_vout );
- msg_Warn( p_dec, "no vout found, leaking subpicture" );
- return;
- }
-
- subpicture_Delete( p_subpic );
-
- vlc_object_release( p_vout );
-}