Commit c6021166 authored by Laurent Aimar's avatar Laurent Aimar

The input now pauses the decoders.

This allows a more reactive pause (independant of *-caching value). It is
not yet instantaneous as vout/aout still play their buffer.
parent f15f2bd7
...@@ -143,6 +143,8 @@ struct input_clock_t ...@@ -143,6 +143,8 @@ struct input_clock_t
/* Current modifiers */ /* Current modifiers */
int i_rate; int i_rate;
bool b_paused;
mtime_t i_pause_date;
}; };
static mtime_t ClockStreamToSystem( input_clock_t *, mtime_t i_stream ); static mtime_t ClockStreamToSystem( input_clock_t *, mtime_t i_stream );
...@@ -169,6 +171,8 @@ input_clock_t *input_clock_New( int i_cr_average, int i_rate ) ...@@ -169,6 +171,8 @@ input_clock_t *input_clock_New( int i_cr_average, int i_rate )
AvgInit( &cl->drift, i_cr_average ); AvgInit( &cl->drift, i_cr_average );
cl->i_rate = i_rate; cl->i_rate = i_rate;
cl->b_paused = false;
cl->i_pause_date = 0;
return cl; return cl;
} }
...@@ -196,6 +200,9 @@ void input_clock_Update( input_clock_t *cl, ...@@ -196,6 +200,9 @@ void input_clock_Update( input_clock_t *cl,
bool b_reset_reference = false; bool b_reset_reference = false;
vlc_mutex_lock( &cl->lock ); vlc_mutex_lock( &cl->lock );
assert( !cl->b_paused );
if( ( !cl->b_has_reference ) || if( ( !cl->b_has_reference ) ||
( i_ck_stream == 0 && cl->last.i_stream != 0 ) ) ( i_ck_stream == 0 && cl->last.i_stream != 0 ) )
{ {
...@@ -270,6 +277,30 @@ void input_clock_ChangeRate( input_clock_t *cl, int i_rate ) ...@@ -270,6 +277,30 @@ void input_clock_ChangeRate( input_clock_t *cl, int i_rate )
vlc_mutex_unlock( &cl->lock ); vlc_mutex_unlock( &cl->lock );
} }
/*****************************************************************************
* input_clock_ChangePause:
*****************************************************************************/
void input_clock_ChangePause( input_clock_t *cl, bool b_paused, mtime_t i_date )
{
vlc_mutex_lock( &cl->lock );
assert( (!cl->b_paused) != (!b_paused) );
if( cl->b_paused )
{
const mtime_t i_duration = i_date - cl->i_pause_date;
if( cl->b_has_reference && i_duration > 0 )
{
cl->ref.i_system += i_duration;
cl->last.i_system += i_duration;
}
}
cl->i_pause_date = i_date;
cl->b_paused = b_paused;
vlc_mutex_unlock( &cl->lock );
}
/***************************************************************************** /*****************************************************************************
* input_clock_GetWakeup * input_clock_GetWakeup
*****************************************************************************/ *****************************************************************************/
......
...@@ -99,9 +99,16 @@ struct decoder_owner_sys_t ...@@ -99,9 +99,16 @@ struct decoder_owner_sys_t
/* fifo */ /* fifo */
block_fifo_t *p_fifo; block_fifo_t *p_fifo;
/* Lock for communication with decoder thread */
vlc_mutex_t lock;
vlc_cond_t wait;
/* */
bool b_paused;
mtime_t i_pause_date;
/* CC */ /* CC */
bool b_cc_supported; bool b_cc_supported;
vlc_mutex_t lock_cc;
bool pb_cc_present[4]; bool pb_cc_present[4];
decoder_t *pp_cc[4]; decoder_t *pp_cc[4];
}; };
...@@ -252,10 +259,21 @@ decoder_t *input_DecoderNew( input_thread_t *p_input, ...@@ -252,10 +259,21 @@ decoder_t *input_DecoderNew( input_thread_t *p_input,
*/ */
void input_DecoderDelete( decoder_t *p_dec ) void input_DecoderDelete( decoder_t *p_dec )
{ {
decoder_owner_sys_t *p_owner = p_dec->p_owner;
vlc_object_kill( p_dec ); vlc_object_kill( p_dec );
if( p_dec->p_owner->b_own_thread ) if( p_owner->b_own_thread )
{
/* Make sure we aren't paused anymore */
vlc_mutex_lock( &p_owner->lock );
if( p_owner->b_paused )
{ {
p_owner->b_paused = false;
vlc_cond_signal( &p_owner->wait );
}
vlc_mutex_unlock( &p_owner->lock );
/* Make sure the thread leaves the function by /* Make sure the thread leaves the function by
* sending it an empty block. */ * sending it an empty block. */
block_t *p_block = block_New( p_dec, 0 ); block_t *p_block = block_New( p_dec, 0 );
...@@ -372,10 +390,10 @@ void input_DecoderIsCcPresent( decoder_t *p_dec, bool pb_present[4] ) ...@@ -372,10 +390,10 @@ void input_DecoderIsCcPresent( decoder_t *p_dec, bool pb_present[4] )
decoder_owner_sys_t *p_owner = p_dec->p_owner; decoder_owner_sys_t *p_owner = p_dec->p_owner;
int i; int i;
vlc_mutex_lock( &p_owner->lock_cc ); vlc_mutex_lock( &p_owner->lock );
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
pb_present[i] = p_owner->pb_cc_present[i]; pb_present[i] = p_owner->pb_cc_present[i];
vlc_mutex_unlock( &p_owner->lock_cc ); vlc_mutex_unlock( &p_owner->lock );
} }
int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
{ {
...@@ -415,18 +433,18 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel ) ...@@ -415,18 +433,18 @@ int input_DecoderSetCcState( decoder_t *p_dec, bool b_decode, int i_channel )
} }
p_cc->p_owner->p_clock = p_owner->p_clock; p_cc->p_owner->p_clock = p_owner->p_clock;
vlc_mutex_lock( &p_owner->lock_cc ); vlc_mutex_lock( &p_owner->lock );
p_owner->pp_cc[i_channel] = p_cc; p_owner->pp_cc[i_channel] = p_cc;
vlc_mutex_unlock( &p_owner->lock_cc ); vlc_mutex_unlock( &p_owner->lock );
} }
else else
{ {
decoder_t *p_cc; decoder_t *p_cc;
vlc_mutex_lock( &p_owner->lock_cc ); vlc_mutex_lock( &p_owner->lock );
p_cc = p_owner->pp_cc[i_channel]; p_cc = p_owner->pp_cc[i_channel];
p_owner->pp_cc[i_channel] = NULL; p_owner->pp_cc[i_channel] = NULL;
vlc_mutex_unlock( &p_owner->lock_cc ); vlc_mutex_unlock( &p_owner->lock );
if( p_cc ) if( p_cc )
{ {
...@@ -446,12 +464,26 @@ int input_DecoderGetCcState( decoder_t *p_dec, bool *pb_decode, int i_channel ) ...@@ -446,12 +464,26 @@ int input_DecoderGetCcState( decoder_t *p_dec, bool *pb_decode, int i_channel )
if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] ) if( i_channel < 0 || i_channel >= 4 || !p_owner->pb_cc_present[i_channel] )
return VLC_EGENERIC; return VLC_EGENERIC;
vlc_mutex_lock( &p_owner->lock_cc ); vlc_mutex_lock( &p_owner->lock );
*pb_decode = p_owner->pp_cc[i_channel] != NULL; *pb_decode = p_owner->pp_cc[i_channel] != NULL;
vlc_mutex_unlock( &p_owner->lock_cc ); vlc_mutex_unlock( &p_owner->lock );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
void input_DecoderChangePause( decoder_t *p_dec, bool b_paused, mtime_t i_date )
{
decoder_owner_sys_t *p_owner = p_dec->p_owner;
/* TODO FIXME we may loose small pause here ! */
vlc_mutex_lock( &p_owner->lock );
assert( (!p_owner->b_paused) != (!b_paused) );
p_owner->b_paused = b_paused;
p_owner->i_pause_date = i_date;
vlc_cond_signal( &p_owner->wait );
vlc_mutex_unlock( &p_owner->lock );
}
/** /**
* Create a decoder object * Create a decoder object
* *
...@@ -586,7 +618,10 @@ static decoder_t * CreateDecoder( input_thread_t *p_input, ...@@ -586,7 +618,10 @@ static decoder_t * CreateDecoder( input_thread_t *p_input,
p_owner->b_cc_supported = true; p_owner->b_cc_supported = true;
} }
vlc_mutex_init( &p_owner->lock_cc ); vlc_mutex_init( &p_owner->lock );
vlc_cond_init( &p_owner->wait );
p_owner->b_paused = false;
p_owner->i_pause_date = 0;
for( i = 0; i < 4; i++ ) for( i = 0; i < 4; i++ )
{ {
p_owner->pb_cc_present[i] = false; p_owner->pb_cc_present[i] = false;
...@@ -609,8 +644,24 @@ static void* DecoderThread( vlc_object_t *p_this ) ...@@ -609,8 +644,24 @@ static void* DecoderThread( vlc_object_t *p_this )
int canc = vlc_savecancel(); int canc = vlc_savecancel();
/* The decoder's main loop */ /* The decoder's main loop */
while( !p_dec->b_die && !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;
...@@ -622,7 +673,7 @@ static void* DecoderThread( vlc_object_t *p_this ) ...@@ -622,7 +673,7 @@ static void* DecoderThread( vlc_object_t *p_this )
} }
} }
while( !p_dec->b_die ) while( vlc_object_alive( p_dec ) )
{ {
/* Trash all received PES packets */ /* Trash all received PES packets */
p_block = block_FifoGet( p_owner->p_fifo ); p_block = block_FifoGet( p_owner->p_fifo );
...@@ -794,7 +845,7 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) ...@@ -794,7 +845,7 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
if( !p_cc ) if( !p_cc )
return; return;
vlc_mutex_lock( &p_owner->lock_cc ); vlc_mutex_lock( &p_owner->lock );
for( i = 0, i_cc_decoder = 0; i < 4; i++ ) for( i = 0, i_cc_decoder = 0; i < 4; i++ )
{ {
p_owner->pb_cc_present[i] |= pb_present[i]; p_owner->pb_cc_present[i] |= pb_present[i];
...@@ -813,7 +864,7 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc ) ...@@ -813,7 +864,7 @@ static void DecoderGetCc( decoder_t *p_dec, decoder_t *p_dec_cc )
DecoderDecode( p_owner->pp_cc[i], p_cc ); DecoderDecode( p_owner->pp_cc[i], p_cc );
i_cc_decoder--; i_cc_decoder--;
} }
vlc_mutex_unlock( &p_owner->lock_cc ); vlc_mutex_unlock( &p_owner->lock );
} }
static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic ) static void VoutDisplayedPicture( vout_thread_t *p_vout, picture_t *p_pic )
{ {
...@@ -1316,7 +1367,8 @@ static void DeleteDecoder( decoder_t * p_dec ) ...@@ -1316,7 +1367,8 @@ static void DeleteDecoder( decoder_t * p_dec )
vlc_object_release( p_owner->p_packetizer ); vlc_object_release( p_owner->p_packetizer );
} }
vlc_mutex_destroy( &p_owner->lock_cc ); vlc_cond_destroy( &p_owner->wait );
vlc_mutex_destroy( &p_owner->lock );
vlc_object_detach( p_dec ); vlc_object_detach( p_dec );
......
...@@ -386,6 +386,33 @@ static void EsOutDiscontinuity( es_out_t *out, bool b_flush, bool b_audio ) ...@@ -386,6 +386,33 @@ static void EsOutDiscontinuity( es_out_t *out, bool b_flush, bool b_audio )
} }
} }
} }
static void EsOutDecoderChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
{
es_out_sys_t *p_sys = out->p_sys;
/* Pause decoders first */
for( int i = 0; i < p_sys->i_es; i++ )
{
es_out_id_t *es = p_sys->es[i];
/* Send a dummy block to let decoder know that
* there is a discontinuity */
if( es->p_dec )
{
input_DecoderChangePause( es->p_dec, b_paused, i_date );
if( es->p_dec_record )
input_DecoderChangePause( es->p_dec_record, b_paused, i_date );
}
}
}
static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
{
es_out_sys_t *p_sys = out->p_sys;
for( int i = 0; i < p_sys->i_pgrm; i++ )
input_clock_ChangePause( p_sys->pgrm[i]->p_clock, b_paused, i_date );
}
void input_EsOutChangeRate( es_out_t *out, int i_rate ) void input_EsOutChangeRate( es_out_t *out, int i_rate )
{ {
es_out_sys_t *p_sys = out->p_sys; es_out_sys_t *p_sys = out->p_sys;
...@@ -477,21 +504,18 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay ) ...@@ -477,21 +504,18 @@ void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
else if( i_cat == SPU_ES ) else if( i_cat == SPU_ES )
p_sys->i_spu_delay = i_delay; p_sys->i_spu_delay = i_delay;
} }
void input_EsOutChangeState( es_out_t *out ) void input_EsOutChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
{ {
es_out_sys_t *p_sys = out->p_sys; /* XXX the order is important */
input_thread_t *p_input = p_sys->p_input; if( b_paused )
if( p_input->i_state == PAUSE_S )
{ {
/* Send discontinuity to decoders (it will allow them to flush EsOutDecoderChangePause( out, true, i_date );
* * if implemented */ EsOutProgramChangePause( out, true, i_date );
EsOutDiscontinuity( out, false, false );
} }
else else
{ {
/* Out of pause, reset pcr */ EsOutProgramChangePause( out, false, i_date );
es_out_Control( out, ES_OUT_RESET_PCR ); EsOutDecoderChangePause( out, false, i_date );
} }
} }
void input_EsOutChangePosition( es_out_t *out ) void input_EsOutChangePosition( es_out_t *out )
......
...@@ -1471,9 +1471,11 @@ static void ControlReduce( input_thread_t *p_input ) ...@@ -1471,9 +1471,11 @@ static void ControlReduce( input_thread_t *p_input )
static bool Control( input_thread_t *p_input, int i_type, static bool Control( input_thread_t *p_input, int i_type,
vlc_value_t val ) vlc_value_t val )
{ {
const mtime_t i_control_date = mdate();
bool b_force_update = false; bool b_force_update = false;
if( !p_input ) return b_force_update; if( !p_input )
return b_force_update;
switch( i_type ) switch( i_type )
{ {
...@@ -1612,7 +1614,7 @@ static bool Control( input_thread_t *p_input, int i_type, ...@@ -1612,7 +1614,7 @@ static bool Control( input_thread_t *p_input, int i_type,
/* */ /* */
if( !i_ret ) if( !i_ret )
input_EsOutChangeState( p_input->p->p_es_out ); input_EsOutChangePause( p_input->p->p_es_out, false, i_control_date );
} }
else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
p_input->p->b_can_pause ) p_input->p->b_can_pause )
...@@ -1642,7 +1644,7 @@ static bool Control( input_thread_t *p_input, int i_type, ...@@ -1642,7 +1644,7 @@ static bool Control( input_thread_t *p_input, int i_type,
/* */ /* */
if( !i_ret ) if( !i_ret )
input_EsOutChangeState( p_input->p->p_es_out ); input_EsOutChangePause( p_input->p->p_es_out, true, i_control_date );
} }
else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause ) else if( val.i_int == PAUSE_S && !p_input->p->b_can_pause )
{ {
......
...@@ -70,6 +70,11 @@ mtime_t input_clock_GetWakeup( input_clock_t * ); ...@@ -70,6 +70,11 @@ mtime_t input_clock_GetWakeup( input_clock_t * );
*/ */
void input_clock_ChangeRate( input_clock_t *, int i_rate ); void input_clock_ChangeRate( input_clock_t *, int i_rate );
/**
* This function allows to change the pause status.
*/
void input_clock_ChangePause( input_clock_t *, bool b_paused, mtime_t i_date );
/** /**
* This function converts a timestamp from stream clock to system clock. * This function converts a timestamp from stream clock to system clock.
*/ */
......
...@@ -35,20 +35,28 @@ ...@@ -35,20 +35,28 @@
#define BLOCK_FLAG_CORE_FLUSH (1 <<BLOCK_FLAG_CORE_PRIVATE_SHIFT) #define BLOCK_FLAG_CORE_FLUSH (1 <<BLOCK_FLAG_CORE_PRIVATE_SHIFT)
/** /**
* This functions warn the decoder about a discontinuity and allow flushing * This function changes the pause state.
* The date parameter MUST hold the exact date at wich the change has been
* done for proper vout/aout pausing.
*/
void input_DecoderChangePause( decoder_t *, bool b_paused, mtime_t i_date );
/**
* This function warn the decoder about a discontinuity and allow flushing
* if requested. * if requested.
*/ */
void input_DecoderDiscontinuity( decoder_t * p_dec, bool b_flush ); void input_DecoderDiscontinuity( decoder_t *, bool b_flush );
/** /**
* This function returns true if the decoder fifo is empty and false otherwise. * This function returns true if the decoder fifo is empty and false otherwise.
*/ */
bool input_DecoderEmpty( decoder_t * p_dec ); bool input_DecoderEmpty( decoder_t * );
/** /**
* This function activates the request closed caption channel. * This function activates the request closed caption channel.
*/ */
int input_DecoderSetCcState( decoder_t *, bool b_decode, int i_channel ); int input_DecoderSetCcState( decoder_t *, bool b_decode, int i_channel );
/** /**
* This function returns an error if the requested channel does not exist and * This function returns an error if the requested channel does not exist and
* set pb_decode to the channel status(active or not) otherwise. * set pb_decode to the channel status(active or not) otherwise.
......
...@@ -351,7 +351,7 @@ mtime_t input_EsOutGetWakeup( es_out_t * ); ...@@ -351,7 +351,7 @@ mtime_t input_EsOutGetWakeup( es_out_t * );
void input_EsOutSetDelay( es_out_t *, int i_cat, int64_t ); void input_EsOutSetDelay( es_out_t *, int i_cat, int64_t );
int input_EsOutSetRecord( es_out_t *, bool b_record ); int input_EsOutSetRecord( es_out_t *, bool b_record );
void input_EsOutChangeRate( es_out_t *, int ); void input_EsOutChangeRate( es_out_t *, int );
void input_EsOutChangeState( es_out_t * ); void input_EsOutChangePause( es_out_t *, bool b_paused, mtime_t i_date );
void input_EsOutChangePosition( es_out_t * ); void input_EsOutChangePosition( es_out_t * );
bool input_EsOutDecodersEmpty( es_out_t * ); bool input_EsOutDecodersEmpty( es_out_t * );
......
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