Commit 057a9633 authored by Laurent Aimar's avatar Laurent Aimar

Pause vout on decoder pause.

This provides a pause with a maximal latency of one call
to pf_demux from the demuxer.
parent b0123347
...@@ -47,11 +47,14 @@ ...@@ -47,11 +47,14 @@
#include "input_clock.h" #include "input_clock.h"
#include "input_decoder.h" #include "input_decoder.h"
#include "../video_output/vout_internal.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 *, int, sout_instance_t *p_sout );
static void DeleteDecoder( decoder_t * ); static void DeleteDecoder( decoder_t * );
static void *DecoderThread( vlc_object_t * ); static void *DecoderThread( vlc_object_t * );
static int DecoderDecode( decoder_t * p_dec, block_t *p_block ); static int DecoderDecode( decoder_t * p_dec, block_t *p_block );
static void DecoderOutputChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date );
/* Buffers allocation callbacks for the decoders */ /* Buffers allocation callbacks for the decoders */
static aout_buffer_t *aout_new_buffer( decoder_t *, int ); static aout_buffer_t *aout_new_buffer( decoder_t *, int );
...@@ -76,11 +79,6 @@ struct decoder_owner_sys_t ...@@ -76,11 +79,6 @@ struct decoder_owner_sys_t
input_thread_t *p_input; input_thread_t *p_input;
input_clock_t *p_clock; input_clock_t *p_clock;
aout_instance_t *p_aout;
aout_input_t *p_aout_input;
vout_thread_t *p_vout;
vout_thread_t *p_spu_vout; vout_thread_t *p_spu_vout;
int i_spu_channel; int i_spu_channel;
int64_t i_spu_order; int64_t i_spu_order;
...@@ -103,10 +101,16 @@ struct decoder_owner_sys_t ...@@ -103,10 +101,16 @@ struct decoder_owner_sys_t
vlc_mutex_t lock; vlc_mutex_t lock;
vlc_cond_t wait; vlc_cond_t wait;
/* */ /* -- These variables need locking on write(only) -- */
aout_instance_t *p_aout;
aout_input_t *p_aout_input;
vout_thread_t *p_vout;
/* -- Theses variables need locking on read *and* write -- */
/* Pause */
bool b_paused; bool b_paused;
mtime_t i_pause_date; mtime_t i_pause_date;
/* CC */ /* CC */
bool b_cc_supported; bool b_cc_supported;
bool pb_cc_present[4]; bool pb_cc_present[4];
...@@ -474,14 +478,15 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date ) ...@@ -474,14 +478,15 @@ void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
{ {
decoder_owner_sys_t *p_owner = p_dec->p_owner; decoder_owner_sys_t *p_owner = p_dec->p_owner;
/* TODO FIXME we may loose small pause here ! */
vlc_mutex_lock( &p_owner->lock ); vlc_mutex_lock( &p_owner->lock );
assert( (!p_owner->b_paused) != (!b_paused) ); assert( (!p_owner->b_paused) != (!b_paused) );
p_owner->b_paused = b_paused; p_owner->b_paused = b_paused;
p_owner->i_pause_date = i_date; p_owner->i_pause_date = i_date;
vlc_cond_signal( &p_owner->wait ); if( p_owner->b_own_thread )
vlc_cond_signal( &p_owner->wait );
DecoderOutputChangePause( p_dec, b_paused, i_date );
vlc_mutex_unlock( &p_owner->lock ); vlc_mutex_unlock( &p_owner->lock );
} }
/** /**
...@@ -646,31 +651,14 @@ static void* DecoderThread( vlc_object_t *p_this ) ...@@ -646,31 +651,14 @@ static void* DecoderThread( vlc_object_t *p_this )
/* The decoder's main loop */ /* The decoder's main loop */
while( vlc_object_alive( p_dec ) && !p_dec->b_error ) while( vlc_object_alive( p_dec ) && !p_dec->b_error )
{ {
/* Handle pause
* TODO move it to just after the decode stage */
vlc_mutex_lock( &p_owner->lock );
if( p_owner->b_paused )
{
/* TODO pause vout/aout */
/* */
while( p_owner->b_paused )
vlc_cond_wait( &p_owner->wait, &p_owner->lock );
/* TODO unpause vout/aout */
}
vlc_mutex_unlock( &p_owner->lock );
if( ( p_block = block_FifoGet( p_owner->p_fifo ) ) == NULL ) if( ( p_block = block_FifoGet( p_owner->p_fifo ) ) == NULL )
{ {
p_dec->b_error = 1; p_dec->b_error = 1;
break; break;
} }
if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS ) if( DecoderDecode( p_dec, p_block ) != VLC_SUCCESS )
{
break; break;
}
} }
while( vlc_object_alive( p_dec ) ) while( vlc_object_alive( p_dec ) )
...@@ -688,6 +676,41 @@ static void* DecoderThread( vlc_object_t *p_this ) ...@@ -688,6 +676,41 @@ static void* DecoderThread( vlc_object_t *p_this )
return NULL; return NULL;
} }
static void DecoderWaitUnpause( decoder_t *p_dec )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
vlc_mutex_lock( &p_owner->lock );
while( p_owner->b_paused )
vlc_cond_wait( &p_owner->wait, &p_owner->lock );
vlc_mutex_unlock( &p_owner->lock );
}
static void DecoderOutputChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
if( p_dec->i_object_type == VLC_OBJECT_PACKETIZER )
return;
if( p_dec->fmt_in.i_cat == AUDIO_ES )
{
// TODO
//if( p_own->p_vout )
// aout_ChangePause( p_own->p_aout, p_own->p_aout_input, b_paused, i_date );
}
else if( p_dec->fmt_in.i_cat == VIDEO_ES )
{
if( p_owner->p_vout )
vout_ChangePause( p_owner->p_vout, b_paused, i_date );
}
else if( p_dec->fmt_in.i_cat == SPU_ES )
{
/* XXX is it needed, maybe the vout should simply pause it */
}
}
static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ) static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
{ {
if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) ) if( p->i_flags & (BLOCK_FLAG_PREROLL|BLOCK_FLAG_DISCONTINUITY) )
...@@ -817,6 +840,8 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block ) ...@@ -817,6 +840,8 @@ static void DecoderDecodeAudio( decoder_t *p_dec, block_t *p_block )
p_owner->i_preroll_end = -1; p_owner->i_preroll_end = -1;
} }
DecoderWaitUnpause( p_dec );
const int i_rate = p_clock ? input_clock_GetRate( p_clock ) : p_block->i_rate; const int i_rate = p_clock ? input_clock_GetRate( p_clock ) : p_block->i_rate;
DecoderAoutBufferFixTs( p_aout_buf, p_clock, p_input->i_pts_delay ); DecoderAoutBufferFixTs( p_aout_buf, p_clock, p_input->i_pts_delay );
...@@ -1047,6 +1072,8 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block ) ...@@ -1047,6 +1072,8 @@ static void DecoderDecodeVideo( decoder_t *p_dec, block_t *p_block )
( !p_owner->p_packetizer || !p_owner->p_packetizer->pf_get_cc ) ) ( !p_owner->p_packetizer || !p_owner->p_packetizer->pf_get_cc ) )
DecoderGetCc( p_dec, p_dec ); DecoderGetCc( p_dec, p_dec );
DecoderWaitUnpause( p_dec );
DecoderVoutBufferFixTs( p_pic, p_owner->p_clock, p_input->i_pts_delay ); DecoderVoutBufferFixTs( p_pic, p_owner->p_clock, p_input->i_pts_delay );
vout_DatePicture( p_vout, p_pic, p_pic->date ); vout_DatePicture( p_vout, p_pic, p_pic->date );
...@@ -1124,6 +1151,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -1124,6 +1151,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
p_sout_block->p_next = NULL; p_sout_block->p_next = NULL;
DecoderWaitUnpause( p_dec );
DecoderSoutBufferFixTs( p_sout_block, DecoderSoutBufferFixTs( p_sout_block,
p_owner->p_clock, p_owner->p_input->i_pts_delay, b_telx ); p_owner->p_clock, p_owner->p_input->i_pts_delay, b_telx );
...@@ -1265,6 +1294,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block ) ...@@ -1265,6 +1294,8 @@ static int DecoderDecode( decoder_t *p_dec, block_t *p_block )
} }
else else
{ {
DecoderWaitUnpause( p_dec );
DecoderSpuBufferFixTs( p_spu, p_owner->p_clock, p_input->i_pts_delay, b_telx ); DecoderSpuBufferFixTs( p_spu, p_owner->p_clock, p_input->i_pts_delay, b_telx );
spu_DisplaySubpicture( p_vout->p_spu, p_spu ); spu_DisplaySubpicture( p_vout->p_spu, p_spu );
} }
...@@ -1390,15 +1421,23 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) ...@@ -1390,15 +1421,23 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
p_dec->fmt_out.audio.i_bytes_per_frame != p_dec->fmt_out.audio.i_bytes_per_frame !=
p_owner->audio.i_bytes_per_frame ) ) p_owner->audio.i_bytes_per_frame ) )
{ {
aout_input_t *p_aout_input = p_owner->p_aout_input;
/* Parameters changed, restart the aout */ /* Parameters changed, restart the aout */
aout_DecDelete( p_owner->p_aout, p_owner->p_aout_input ); vlc_mutex_lock( &p_owner->lock );
p_owner->p_aout_input = NULL; p_owner->p_aout_input = NULL;
aout_DecDelete( p_owner->p_aout, p_aout_input );
vlc_mutex_unlock( &p_owner->lock );
} }
if( p_owner->p_aout_input == NULL ) if( p_owner->p_aout_input == NULL )
{ {
const int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" );
audio_sample_format_t format; audio_sample_format_t format;
int i_force_dolby = config_GetInt( p_dec, "force-dolby-surround" ); aout_input_t *p_aout_input;
aout_instance_t *p_aout;
p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec; p_dec->fmt_out.audio.i_format = p_dec->fmt_out.i_codec;
p_owner->audio = p_dec->fmt_out.audio; p_owner->audio = p_dec->fmt_out.audio;
...@@ -1419,8 +1458,15 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples ) ...@@ -1419,8 +1458,15 @@ static aout_buffer_t *aout_new_buffer( decoder_t *p_dec, int i_samples )
} }
} }
p_owner->p_aout_input = p_aout = p_owner->p_aout;
aout_DecNew( p_dec, &p_owner->p_aout, &format, &p_dec->fmt_out.audio_replay_gain ); p_aout_input = aout_DecNew( p_dec, &p_aout,
&format, &p_dec->fmt_out.audio_replay_gain );
vlc_mutex_lock( &p_owner->lock );
p_owner->p_aout = p_aout;
p_owner->p_aout_input = p_aout_input;
vlc_mutex_unlock( &p_owner->lock );
if( p_owner->p_aout_input == NULL ) if( p_owner->p_aout_input == NULL )
{ {
msg_Err( p_dec, "failed to create audio output" ); msg_Err( p_dec, "failed to create audio output" );
...@@ -1458,6 +1504,8 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) ...@@ -1458,6 +1504,8 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
p_dec->fmt_out.video.i_chroma != p_owner->video.i_chroma || p_dec->fmt_out.video.i_chroma != p_owner->video.i_chroma ||
p_dec->fmt_out.video.i_aspect != p_owner->video.i_aspect ) p_dec->fmt_out.video.i_aspect != p_owner->video.i_aspect )
{ {
vout_thread_t *p_vout;
if( !p_dec->fmt_out.video.i_width || if( !p_dec->fmt_out.video.i_width ||
!p_dec->fmt_out.video.i_height ) !p_dec->fmt_out.video.i_height )
{ {
...@@ -1512,10 +1560,15 @@ static picture_t *vout_new_buffer( decoder_t *p_dec ) ...@@ -1512,10 +1560,15 @@ static picture_t *vout_new_buffer( decoder_t *p_dec )
p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec; p_dec->fmt_out.video.i_chroma = p_dec->fmt_out.i_codec;
p_owner->video = p_dec->fmt_out.video; p_owner->video = p_dec->fmt_out.video;
p_owner->p_vout = vout_Request( p_dec, p_owner->p_vout, p_vout = vout_Request( p_dec, p_owner->p_vout,
&p_dec->fmt_out.video ); &p_dec->fmt_out.video );
vlc_mutex_lock( &p_owner->lock );
p_owner->p_vout = p_vout;
vlc_mutex_unlock( &p_owner->lock );
var_SetBool( p_owner->p_input, "intf-change-vout", true ); var_SetBool( p_owner->p_input, "intf-change-vout", true );
if( p_owner->p_vout == NULL ) if( p_vout == NULL )
{ {
msg_Err( p_dec, "failed to create video output" ); msg_Err( p_dec, "failed to create video output" );
p_dec->b_error = true; p_dec->b_error = true;
......
...@@ -307,7 +307,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) ...@@ -307,7 +307,7 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
return NULL; return NULL;
/* */ /* */
p_vout->p = calloc( 1, sizeof(p_vout->p) ); p_vout->p = calloc( 1, sizeof(*p_vout->p) );
if( !p_vout->p ) if( !p_vout->p )
{ {
vlc_object_release( p_vout ); vlc_object_release( p_vout );
...@@ -365,6 +365,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt ) ...@@ -365,6 +365,8 @@ vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
p_vout->p->render_time = 10; p_vout->p->render_time = 10;
p_vout->p->c_fps_samples = 0; p_vout->p->c_fps_samples = 0;
p_vout->p->b_filter_change = 0; p_vout->p->b_filter_change = 0;
p_vout->p->b_paused = false;
p_vout->p->i_pause_date = 0;
p_vout->pf_control = NULL; p_vout->pf_control = NULL;
p_vout->p_window = NULL; p_vout->p_window = NULL;
p_vout->p->i_par_num = p_vout->p->i_par_num =
...@@ -580,6 +582,31 @@ static void vout_Destructor( vlc_object_t * p_this ) ...@@ -580,6 +582,31 @@ static void vout_Destructor( vlc_object_t * p_this )
#endif #endif
} }
/* */
void vout_ChangePause( vout_thread_t *p_vout, bool b_paused, mtime_t i_date )
{
vlc_object_lock( p_vout );
assert( (!p_vout->p->b_paused) != (!b_paused) );
if( p_vout->p->b_paused )
{
const mtime_t i_duration = i_date - p_vout->p->i_pause_date;
for( int i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
{
picture_t *p_pic = PP_RENDERPICTURE[i_index];
if( p_pic->i_status == READY_PICTURE )
p_pic->date += i_duration;
}
// TODO spu
}
p_vout->p->b_paused = b_paused;
p_vout->p->i_pause_date = i_date;
vlc_object_unlock( p_vout );
}
/***************************************************************************** /*****************************************************************************
* InitThread: initialize video output thread * InitThread: initialize video output thread
***************************************************************************** *****************************************************************************
...@@ -876,12 +903,14 @@ static void* RunThread( vlc_object_t *p_this ) ...@@ -876,12 +903,14 @@ static void* RunThread( vlc_object_t *p_this )
display_date = p_picture->date; display_date = p_picture->date;
} }
} }
if( p_vout->p->b_paused && p_last_picture != NULL )
p_picture = p_last_picture;
if( p_picture ) if( p_picture )
{ {
/* If we met the last picture, parse again to see whether there is /* If we met the last picture, parse again to see whether there is
* a more appropriate one. */ * a more appropriate one. */
if( p_picture == p_last_picture ) if( p_picture == p_last_picture && !p_vout->p->b_paused )
{ {
for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ ) for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
{ {
......
...@@ -59,6 +59,10 @@ struct vout_thread_sys_t ...@@ -59,6 +59,10 @@ struct vout_thread_sys_t
for the calculation of the jitter */ for the calculation of the jitter */
#endif #endif
/* Pause */
bool b_paused;
mtime_t i_pause_date;
/** delay created by internal caching */ /** delay created by internal caching */
int i_pts_delay; int i_pts_delay;
...@@ -86,5 +90,11 @@ picture_t *vout_RenderPicture( vout_thread_t *, picture_t *, ...@@ -86,5 +90,11 @@ picture_t *vout_RenderPicture( vout_thread_t *, picture_t *,
/* DO NOT use vout_CountPictureAvailable unless your are in src/input/decoder.c (no exception) */ /* DO NOT use vout_CountPictureAvailable unless your are in src/input/decoder.c (no exception) */
int vout_CountPictureAvailable( vout_thread_t * ); int vout_CountPictureAvailable( vout_thread_t * );
/**
* This function will (un)pause the display of pictures.
* It is thread safe
*/
void vout_ChangePause( vout_thread_t *, bool b_paused, mtime_t i_date );
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment