Commit f5574a64 authored by Laurent Aimar's avatar Laurent Aimar

Made input_clock_t in charge of pts_delay.

It fixes a lot of unlocked access.
It will allows a better clock algo.
parent f8b7bbc6
...@@ -107,6 +107,7 @@ static void AvgClean( average_t * ); ...@@ -107,6 +107,7 @@ static void AvgClean( average_t * );
static void AvgReset( average_t * ); static void AvgReset( average_t * );
static void AvgUpdate( average_t *, mtime_t i_value ); static void AvgUpdate( average_t *, mtime_t i_value );
static mtime_t AvgGet( average_t * ); static mtime_t AvgGet( average_t * );
static void AvgRescale( average_t *, int i_divider );
/* */ /* */
typedef struct typedef struct
...@@ -144,6 +145,7 @@ struct input_clock_t ...@@ -144,6 +145,7 @@ struct input_clock_t
/* Current modifiers */ /* Current modifiers */
int i_rate; int i_rate;
mtime_t i_pts_delay;
bool b_paused; bool b_paused;
mtime_t i_pause_date; mtime_t i_pause_date;
}; };
...@@ -154,7 +156,7 @@ static mtime_t ClockSystemToStream( input_clock_t *, mtime_t i_system ); ...@@ -154,7 +156,7 @@ static mtime_t ClockSystemToStream( input_clock_t *, mtime_t i_system );
/***************************************************************************** /*****************************************************************************
* input_clock_New: create a new clock * input_clock_New: create a new clock
*****************************************************************************/ *****************************************************************************/
input_clock_t *input_clock_New( int i_cr_average, int i_rate ) input_clock_t *input_clock_New( int i_rate )
{ {
input_clock_t *cl = malloc( sizeof(*cl) ); input_clock_t *cl = malloc( sizeof(*cl) );
if( !cl ) if( !cl )
...@@ -169,9 +171,10 @@ input_clock_t *input_clock_New( int i_cr_average, int i_rate ) ...@@ -169,9 +171,10 @@ input_clock_t *input_clock_New( int i_cr_average, int i_rate )
cl->i_ts_max = 0; cl->i_ts_max = 0;
cl->i_next_drift_update = 0; cl->i_next_drift_update = 0;
AvgInit( &cl->drift, i_cr_average ); AvgInit( &cl->drift, 10 );
cl->i_rate = i_rate; cl->i_rate = i_rate;
cl->i_pts_delay = 0;
cl->b_paused = false; cl->b_paused = false;
cl->i_pause_date = 0; cl->i_pause_date = 0;
...@@ -325,7 +328,7 @@ mtime_t input_clock_GetWakeup( input_clock_t *cl ) ...@@ -325,7 +328,7 @@ mtime_t input_clock_GetWakeup( input_clock_t *cl )
* input_clock_GetTS: manages a PTS or DTS * input_clock_GetTS: manages a PTS or DTS
*****************************************************************************/ *****************************************************************************/
mtime_t input_clock_GetTS( input_clock_t *cl, int *pi_rate, mtime_t input_clock_GetTS( input_clock_t *cl, int *pi_rate,
mtime_t i_pts_delay, mtime_t i_ts ) mtime_t i_ts, mtime_t i_ts_bound )
{ {
mtime_t i_converted_ts; mtime_t i_converted_ts;
...@@ -347,7 +350,14 @@ mtime_t input_clock_GetTS( input_clock_t *cl, int *pi_rate, ...@@ -347,7 +350,14 @@ mtime_t input_clock_GetTS( input_clock_t *cl, int *pi_rate,
vlc_mutex_unlock( &cl->lock ); vlc_mutex_unlock( &cl->lock );
return i_converted_ts + i_pts_delay; i_converted_ts += cl->i_pts_delay;
/* Check ts validity */
if( i_ts_bound != INT64_MAX &&
i_converted_ts >= mdate() + cl->i_pts_delay + i_ts_bound )
return 0;
return i_converted_ts;
} }
/***************************************************************************** /*****************************************************************************
* input_clock_GetRate: Return current rate * input_clock_GetRate: Return current rate
...@@ -399,6 +409,28 @@ void input_clock_ChangeSystemOrigin( input_clock_t *cl, mtime_t i_system ) ...@@ -399,6 +409,28 @@ void input_clock_ChangeSystemOrigin( input_clock_t *cl, mtime_t i_system )
vlc_mutex_unlock( &cl->lock ); vlc_mutex_unlock( &cl->lock );
} }
#warning "input_clock_SetJitter needs more work"
void input_clock_SetJitter( input_clock_t *cl,
mtime_t i_pts_delay, int i_cr_average )
{
vlc_mutex_lock( &cl->lock );
/* TODO always save the value, and when rebuffering use the new one if smaller
* TODO when increasing -> force rebuffering
*/
if( cl->i_pts_delay < i_pts_delay )
cl->i_pts_delay = i_pts_delay;
/* */
if( i_cr_average < 10 )
i_cr_average = 10;
if( cl->drift.i_divider != i_cr_average )
AvgRescale( &cl->drift, i_cr_average );
vlc_mutex_unlock( &cl->lock );
}
/***************************************************************************** /*****************************************************************************
* ClockStreamToSystem: converts a movie clock to system date * ClockStreamToSystem: converts a movie clock to system date
*****************************************************************************/ *****************************************************************************/
...@@ -457,4 +489,11 @@ static mtime_t AvgGet( average_t *p_avg ) ...@@ -457,4 +489,11 @@ static mtime_t AvgGet( average_t *p_avg )
{ {
return p_avg->i_value; return p_avg->i_value;
} }
static void AvgRescale( average_t *p_avg, int i_divider )
{
const mtime_t i_tmp = p_avg->i_value * p_avg->i_divider + p_avg->i_residue;
p_avg->i_divider = i_divider;
p_avg->i_value = i_tmp / p_avg->i_divider;
p_avg->i_residue = i_tmp % p_avg->i_divider;
}
...@@ -43,7 +43,8 @@ ...@@ -43,7 +43,8 @@
* This function creates a new input_clock_t. * This function creates a new input_clock_t.
* You must use input_clock_Delete to delete it once unused. * You must use input_clock_Delete to delete it once unused.
*/ */
input_clock_t *input_clock_New( int i_cr_average, int i_rate ); input_clock_t *input_clock_New( int i_rate );
/** /**
* This function destroys a input_clock_t created by input_clock_New. * This function destroys a input_clock_t created by input_clock_New.
*/ */
...@@ -88,8 +89,10 @@ void input_clock_ChangeSystemOrigin( input_clock_t *, mtime_t i_system ); ...@@ -88,8 +89,10 @@ void input_clock_ChangeSystemOrigin( input_clock_t *, mtime_t i_system );
* *
* If pi_rate is provided it will be field with the rate value used for * If pi_rate is provided it will be field with the rate value used for
* the conversion. * the conversion.
* If i_ts_bound is not INT64_MAX, the value will be invalidated if not
* before mdate() + i_pts_delay + i_ts_bound.
*/ */
mtime_t input_clock_GetTS( input_clock_t *, int *pi_rate, mtime_t i_pts_delay, mtime_t ); mtime_t input_clock_GetTS( input_clock_t *, int *pi_rate, mtime_t i_ts, mtime_t i_ts_bound );
/** /**
* This function returns the current rate. * This function returns the current rate.
...@@ -104,5 +107,11 @@ int input_clock_GetState( input_clock_t *, ...@@ -104,5 +107,11 @@ int input_clock_GetState( input_clock_t *,
mtime_t *pi_stream_start, mtime_t *pi_system_start, mtime_t *pi_stream_start, mtime_t *pi_system_start,
mtime_t *pi_stream_duration, mtime_t *pi_system_duration ); mtime_t *pi_stream_duration, mtime_t *pi_system_duration );
/**
* This function allows the set the minimal configuration for the jitter estimation algo.
*/
void input_clock_SetJitter( input_clock_t *,
mtime_t i_pts_delay, int i_cr_average );
#endif #endif
...@@ -652,7 +652,7 @@ static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts ) ...@@ -652,7 +652,7 @@ static mtime_t DecoderGetDisplayDate( decoder_t *p_dec, mtime_t i_ts )
if( !p_owner->p_clock || !i_ts ) if( !p_owner->p_clock || !i_ts )
return i_ts; return i_ts;
return input_clock_GetTS( p_owner->p_clock, NULL, p_owner->p_input->p->i_pts_delay, i_ts ); return input_clock_GetTS( p_owner->p_clock, NULL, i_ts, INT64_MAX );
} }
static int DecoderGetDisplayRate( decoder_t *p_dec ) static int DecoderGetDisplayRate( decoder_t *p_dec )
{ {
...@@ -1020,7 +1020,7 @@ static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p ) ...@@ -1020,7 +1020,7 @@ static inline void DecoderUpdatePreroll( int64_t *pi_preroll, const block_t *p )
*pi_preroll = __MIN( *pi_preroll, p->i_dts ); *pi_preroll = __MIN( *pi_preroll, p->i_dts );
} }
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(); mtime_t current_date = mdate();
...@@ -1029,13 +1029,13 @@ static mtime_t DecoderTeletextFixTs( mtime_t i_ts, mtime_t i_ts_delay ) ...@@ -1029,13 +1029,13 @@ 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 /* ETSI EN 300 472 Annex A : do not take into account the PTS
* for teletext streams. */ * for teletext streams. */
return current_date + 400000 + i_ts_delay; return current_date + 400000;
} }
return i_ts; return i_ts;
} }
static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, 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; decoder_owner_sys_t *p_owner = p_dec->p_owner;
input_clock_t *p_clock = p_owner->p_clock; input_clock_t *p_clock = p_owner->p_clock;
...@@ -1043,7 +1043,6 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, ...@@ -1043,7 +1043,6 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
vlc_assert_locked( &p_owner->lock ); vlc_assert_locked( &p_owner->lock );
const mtime_t i_ts_delay = p_owner->p_input->p->i_pts_delay;
const mtime_t i_es_delay = p_owner->i_ts_delay; const mtime_t i_es_delay = p_owner->i_ts_delay;
if( p_clock ) if( p_clock )
...@@ -1051,11 +1050,14 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, ...@@ -1051,11 +1050,14 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
const bool b_ephemere = pi_ts1 && *pi_ts0 == *pi_ts1; const bool b_ephemere = pi_ts1 && *pi_ts0 == *pi_ts1;
if( *pi_ts0 > 0 ) if( *pi_ts0 > 0 )
*pi_ts0 = input_clock_GetTS( p_clock, &i_rate, i_ts_delay, *pi_ts0 = input_clock_GetTS( p_clock, &i_rate, *pi_ts0 + i_es_delay, i_ts_bound );
*pi_ts0 + i_es_delay );
if( pi_ts1 && *pi_ts1 > 0 ) if( pi_ts1 && *pi_ts1 > 0 )
*pi_ts1 = input_clock_GetTS( p_clock, &i_rate, i_ts_delay, {
*pi_ts1 + i_es_delay ); if( *pi_ts0 > 0 )
*pi_ts1 = input_clock_GetTS( p_clock, &i_rate, *pi_ts1 + i_es_delay, INT64_MAX );
else
*pi_ts1 = 0;
}
/* Do not create ephemere data because of rounding errors */ /* Do not create ephemere data because of rounding errors */
if( !b_ephemere && pi_ts1 && *pi_ts0 == *pi_ts1 ) if( !b_ephemere && pi_ts1 && *pi_ts0 == *pi_ts1 )
...@@ -1073,16 +1075,11 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1, ...@@ -1073,16 +1075,11 @@ static void DecoderFixTs( decoder_t *p_dec, mtime_t *pi_ts0, mtime_t *pi_ts1,
if( b_telx ) if( b_telx )
{ {
*pi_ts0 = DecoderTeletextFixTs( *pi_ts0, i_ts_delay ); *pi_ts0 = DecoderTeletextFixTs( *pi_ts0 );
if( pi_ts1 && *pi_ts1 <= 0 ) if( pi_ts1 && *pi_ts1 <= 0 )
*pi_ts1 = *pi_ts0; *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, static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
...@@ -1146,19 +1143,16 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, ...@@ -1146,19 +1143,16 @@ 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; int i_rate = INPUT_RATE_DEFAULT;
mtime_t i_delay;
DecoderFixTs( p_dec, &p_audio->start_date, &p_audio->end_date, NULL, 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 ); 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 || 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 ||
i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE ) i_rate > INPUT_RATE_DEFAULT*AOUT_MAX_INPUT_RATE )
b_reject = true; b_reject = true;
...@@ -1186,15 +1180,11 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio, ...@@ -1186,15 +1180,11 @@ static void DecoderPlayAudio( decoder_t *p_dec, aout_buffer_t *p_audio,
} }
else 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" ); 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; *pi_lost_sum += 1;
aout_BufferFree( p_audio ); aout_BufferFree( p_audio );
} }
...@@ -1381,17 +1371,15 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, ...@@ -1381,17 +1371,15 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
p_picture->b_force = true; p_picture->b_force = true;
} }
const bool b_dated = p_picture->date > 0;
int i_rate = INPUT_RATE_DEFAULT; int i_rate = INPUT_RATE_DEFAULT;
mtime_t i_delay;
DecoderFixTs( p_dec, &p_picture->date, NULL, NULL, 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 ); vlc_mutex_unlock( &p_owner->lock );
/* */ /* */
const mtime_t i_max_date = mdate() + i_delay + DECODER_BOGUS_VIDEO_DELAY; if( !p_picture->b_force && p_picture->date <= 0 )
if( !p_picture->b_force && ( p_picture->date <= 0 || p_picture->date >= i_max_date ) )
b_reject = true; b_reject = true;
if( !b_reject ) if( !b_reject )
...@@ -1406,15 +1394,11 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture, ...@@ -1406,15 +1394,11 @@ static void DecoderPlayVideo( decoder_t *p_dec, picture_t *p_picture,
} }
else else
{ {
if( p_picture->date <= 0 ) if( b_dated )
{ msg_Warn( p_vout, "early picture skipped" );
msg_Warn( p_vout, "non-dated video buffer received" );
}
else else
{ msg_Warn( p_vout, "non-dated video buffer received" );
msg_Warn( p_vout, "early picture skipped (%"PRId64")",
p_picture->date - mdate() );
}
*pi_lost_sum += 1; *pi_lost_sum += 1;
vout_DropPicture( p_vout, p_picture ); vout_DropPicture( p_vout, p_picture );
} }
...@@ -1557,7 +1541,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic, ...@@ -1557,7 +1541,7 @@ static void DecoderPlaySpu( decoder_t *p_dec, subpicture_t *p_subpic,
/* */ /* */
DecoderFixTs( p_dec, &p_subpic->i_start, &p_subpic->i_stop, NULL, 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 ); vlc_mutex_unlock( &p_owner->lock );
...@@ -1628,7 +1612,7 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block, ...@@ -1628,7 +1612,7 @@ static void DecoderPlaySout( decoder_t *p_dec, block_t *p_sout_block,
DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts, DecoderFixTs( p_dec, &p_sout_block->i_dts, &p_sout_block->i_pts,
&p_sout_block->i_length, &p_sout_block->i_length,
&p_sout_block->i_rate, NULL, b_telx ); &p_sout_block->i_rate, INT64_MAX, b_telx );
vlc_mutex_unlock( &p_owner->lock ); vlc_mutex_unlock( &p_owner->lock );
......
...@@ -142,7 +142,9 @@ struct es_out_sys_t ...@@ -142,7 +142,9 @@ struct es_out_sys_t
int64_t i_audio_delay; int64_t i_audio_delay;
int64_t i_spu_delay; int64_t i_spu_delay;
/* Rate used for clock */ /* Clock configuration */
mtime_t i_pts_delay;
int i_cr_average;
int i_rate; int i_rate;
/* */ /* */
...@@ -305,6 +307,8 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate ) ...@@ -305,6 +307,8 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
p_sys->i_pause_date = -1; p_sys->i_pause_date = -1;
p_sys->i_rate = i_rate; p_sys->i_rate = i_rate;
p_sys->i_pts_delay = 0;
p_sys->i_cr_average = 0;
p_sys->b_buffering = true; p_sys->b_buffering = true;
p_sys->i_buffering_extra_initial = 0; p_sys->i_buffering_extra_initial = 0;
...@@ -622,7 +626,7 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced ) ...@@ -622,7 +626,7 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
if( p_sys->i_preroll_end >= 0 ) if( p_sys->i_preroll_end >= 0 )
i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 ); i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
const mtime_t i_buffering_duration = p_sys->p_input->p->i_pts_delay + const mtime_t i_buffering_duration = p_sys->i_pts_delay +
i_preroll_duration + i_preroll_duration +
p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial; p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
...@@ -787,7 +791,7 @@ static void EsOutFrameNext( es_out_t *out ) ...@@ -787,7 +791,7 @@ static void EsOutFrameNext( es_out_t *out )
if( i_ret ) if( i_ret )
return; return;
p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->p_input->p->i_pts_delay; /* FIXME < 0 ? */ p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
p_sys->i_buffering_extra_system = p_sys->i_buffering_extra_system =
p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial; p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
} }
...@@ -842,7 +846,7 @@ static mtime_t EsOutGetBuffering( es_out_t *out ) ...@@ -842,7 +846,7 @@ static mtime_t EsOutGetBuffering( es_out_t *out )
} }
const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration; const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
i_delay = p_sys->p_input->p->i_pts_delay - i_consumed; i_delay = p_sys->i_pts_delay - i_consumed;
} }
if( i_delay < 0 ) if( i_delay < 0 )
return 0; return 0;
...@@ -1013,12 +1017,14 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group ) ...@@ -1013,12 +1017,14 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
p_pgrm->psz_now_playing = NULL; p_pgrm->psz_now_playing = NULL;
p_pgrm->psz_publisher = NULL; p_pgrm->psz_publisher = NULL;
p_pgrm->p_epg = NULL; p_pgrm->p_epg = NULL;
p_pgrm->p_clock = input_clock_New( p_input->p->i_cr_average, p_sys->i_rate ); p_pgrm->p_clock = input_clock_New( p_sys->i_rate );
if( !p_pgrm->p_clock ) if( !p_pgrm->p_clock )
{ {
free( p_pgrm ); free( p_pgrm );
return NULL; return NULL;
} }
input_clock_SetJitter( p_pgrm->p_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
/* Append it */ /* Append it */
TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm ); TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
...@@ -2392,6 +2398,23 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args ) ...@@ -2392,6 +2398,23 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length ); input_SendEventTimes( p_sys->p_input, f_position, i_time, i_length );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
case ES_OUT_SET_JITTER:
{
mtime_t i_pts_delay = (mtime_t)va_arg( args, mtime_t );
int i_cr_average = (int)va_arg( args, int );
if( i_pts_delay == p_sys->i_pts_delay &&
i_cr_average == p_sys->i_cr_average )
return VLC_SUCCESS;
p_sys->i_pts_delay = i_pts_delay;
p_sys->i_cr_average = i_cr_average;
for( int i = 0; i < p_sys->i_pgrm; i++ )
input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
i_pts_delay, i_cr_average );
return VLC_SUCCESS;
}
default: default:
msg_Err( p_sys->p_input, "unknown query in es_out_Control" ); msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
......
...@@ -74,6 +74,9 @@ enum es_out_query_private_e ...@@ -74,6 +74,9 @@ enum es_out_query_private_e
/* Set position/time/length */ /* Set position/time/length */
ES_OUT_SET_TIMES, /* arg1=double f_position arg2=mtime_t i_time arg3=mtime_t i_length res=cannot fail */ ES_OUT_SET_TIMES, /* arg1=double f_position arg2=mtime_t i_time arg3=mtime_t i_length res=cannot fail */
/* Set jitter */
ES_OUT_SET_JITTER, /* arg1=mtime_t i_pts_delay arg2=int i_cr_average res=cannot fail */
}; };
static inline mtime_t es_out_GetWakeup( es_out_t *p_out ) static inline mtime_t es_out_GetWakeup( es_out_t *p_out )
...@@ -129,6 +132,11 @@ static inline void es_out_SetTimes( es_out_t *p_out, double f_position, mtime_t ...@@ -129,6 +132,11 @@ static inline void es_out_SetTimes( es_out_t *p_out, double f_position, mtime_t
int i_ret = es_out_Control( p_out, ES_OUT_SET_TIMES, f_position, i_time, i_length ); int i_ret = es_out_Control( p_out, ES_OUT_SET_TIMES, f_position, i_time, i_length );
assert( !i_ret ); assert( !i_ret );
} }
static inline void es_out_SetJitter( es_out_t *p_out, mtime_t i_pts_delay, int i_cr_average )
{
int i_ret = es_out_Control( p_out, ES_OUT_SET_JITTER, i_pts_delay, i_cr_average );
assert( !i_ret );
}
es_out_t *input_EsOutNew( input_thread_t *, int i_rate ); es_out_t *input_EsOutNew( input_thread_t *, int i_rate );
......
...@@ -128,6 +128,11 @@ typedef struct attribute_packed ...@@ -128,6 +128,11 @@ typedef struct attribute_packed
mtime_t i_time; mtime_t i_time;
mtime_t i_length; mtime_t i_length;
} times; } times;
struct
{
mtime_t i_pts_delay;
int i_cr_average;
} jitter;
}; };
} ts_cmd_control_t; } ts_cmd_control_t;
...@@ -599,6 +604,7 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args ) ...@@ -599,6 +604,7 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
case ES_OUT_SET_ES_STATE: case ES_OUT_SET_ES_STATE:
case ES_OUT_SET_ES_FMT: case ES_OUT_SET_ES_FMT:
case ES_OUT_SET_TIMES: case ES_OUT_SET_TIMES:
case ES_OUT_SET_JITTER:
{ {
ts_cmd_t cmd; ts_cmd_t cmd;
if( CmdInitControl( &cmd, i_query, args, p_sys->b_delayed ) ) if( CmdInitControl( &cmd, i_query, args, p_sys->b_delayed ) )
...@@ -1392,6 +1398,15 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co ...@@ -1392,6 +1398,15 @@ static int CmdInitControl( ts_cmd_t *p_cmd, int i_query, va_list args, bool b_co
p_cmd->control.times.i_length = i_length; p_cmd->control.times.i_length = i_length;
break; break;
} }
case ES_OUT_SET_JITTER:
{
mtime_t i_pts_delay = (mtime_t)va_arg( args, mtime_t );
int i_cr_average = (int)va_arg( args, int );
p_cmd->control.jitter.i_pts_delay = i_pts_delay;
p_cmd->control.jitter.i_cr_average = i_cr_average;
break;
}
default: default:
assert(0); assert(0);
...@@ -1452,6 +1467,9 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd ) ...@@ -1452,6 +1467,9 @@ static int CmdExecuteControl( es_out_t *p_out, ts_cmd_t *p_cmd )
return es_out_Control( p_out, i_query, p_cmd->control.times.f_position, return es_out_Control( p_out, i_query, p_cmd->control.times.f_position,
p_cmd->control.times.i_time, p_cmd->control.times.i_time,
p_cmd->control.times.i_length ); p_cmd->control.times.i_length );
case ES_OUT_SET_JITTER:
return es_out_Control( p_out, i_query, p_cmd->control.jitter.i_pts_delay,
p_cmd->control.jitter.i_cr_average );
default: default:
assert(0); assert(0);
......
...@@ -183,8 +183,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, ...@@ -183,8 +183,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
p_input->p->p_es_out = NULL; p_input->p->p_es_out = NULL;
p_input->p->p_sout = NULL; p_input->p->p_sout = NULL;
p_input->p->b_out_pace_control = false; p_input->p->b_out_pace_control = false;
p_input->p->i_pts_delay = 0;
p_input->p->i_cr_average = 0;
vlc_gc_incref( p_item ); /* Released in Destructor() */ vlc_gc_incref( p_item ); /* Released in Destructor() */
p_input->p->p_item = p_item; p_input->p->p_item = p_item;
...@@ -239,8 +237,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item, ...@@ -239,8 +237,6 @@ static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
input_ControlVarInit( p_input ); input_ControlVarInit( p_input );
/* */ /* */
p_input->p->i_cr_average = var_GetInteger( p_input, "cr-average" );
if( !p_input->b_preparsing ) if( !p_input->b_preparsing )
{ {
var_Get( p_input, "bookmarks", &val ); var_Get( p_input, "bookmarks", &val );
...@@ -903,22 +899,6 @@ static void InitTitle( input_thread_t * p_input ) ...@@ -903,22 +899,6 @@ static void InitTitle( input_thread_t * p_input )
p_input->p->b_can_pace_control = p_master->b_can_pace_control; p_input->p->b_can_pace_control = p_master->b_can_pace_control;
p_input->p->b_can_pause = p_master->b_can_pause; p_input->p->b_can_pause = p_master->b_can_pause;
p_input->p->b_can_rate_control = p_master->b_can_rate_control; p_input->p->b_can_rate_control = p_master->b_can_rate_control;
/* Fix pts delay */
if( p_input->p->i_pts_delay < 0 )
p_input->p->i_pts_delay = 0;
/* If the desynchronisation requested by the user is < 0, we need to
* cache more data. */
const int i_desynch = var_GetInteger( p_input, "audio-desync" );
if( i_desynch < 0 )
p_input->p->i_pts_delay -= i_desynch * 1000;
/* Update cr_average depending on the caching */
p_input->p->i_cr_average *= (10 * p_input->p->i_pts_delay / 200000);
p_input->p->i_cr_average /= 10;
if( p_input->p->i_cr_average < 10 )
p_input->p->i_cr_average = 10;
} }
static void StartTitle( input_thread_t * p_input ) static void StartTitle( input_thread_t * p_input )
...@@ -1059,11 +1039,40 @@ static void LoadSlaves( input_thread_t *p_input ) ...@@ -1059,11 +1039,40 @@ static void LoadSlaves( input_thread_t *p_input )
free( psz_org ); free( psz_org );
} }
static void UpdatePtsDelay( input_thread_t *p_input )
{
input_thread_private_t *p_sys = p_input->p;
/* Get max pts delay from input source */
mtime_t i_pts_delay = p_sys->input.i_pts_delay;
for( int i = 0; i < p_sys->i_slave; i++ )
i_pts_delay = __MAX( i_pts_delay, p_sys->slave[i]->i_pts_delay );
if( i_pts_delay < 0 )
i_pts_delay = 0;
/* Take care of audio/spu delay */
const int i_audio_delay = var_GetTime( p_input, "audio-delay" );
const int i_spu_delay = var_GetTime( p_input, "spu-delay" );
const int i_extra_delay = __MIN( i_audio_delay, i_spu_delay );
if( i_extra_delay < 0 )
i_pts_delay -= i_extra_delay * INT64_C(1000);
/* Update cr_average depending on the caching */
const int i_cr_average = var_GetInteger( p_input, "cr-average" ) * i_pts_delay / DEFAULT_PTS_DELAY;
/* */
es_out_SetJitter( p_input->p->p_es_out, i_pts_delay, i_cr_average );
}
static void InitPrograms( input_thread_t * p_input ) static void InitPrograms( input_thread_t * p_input )
{ {
int i_es_out_mode; int i_es_out_mode;
vlc_value_t val; vlc_value_t val;
/* Compute correct pts_delay */
UpdatePtsDelay( p_input );
/* Set up es_out */ /* Set up es_out */
es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, true ); es_out_Control( p_input->p->p_es_out, ES_OUT_SET_ACTIVE, true );
i_es_out_mode = ES_OUT_MODE_AUTO; i_es_out_mode = ES_OUT_MODE_AUTO;
...@@ -1831,12 +1840,18 @@ static bool Control( input_thread_t *p_input, int i_type, ...@@ -1831,12 +1840,18 @@ static bool Control( input_thread_t *p_input, int i_type,
case INPUT_CONTROL_SET_AUDIO_DELAY: case INPUT_CONTROL_SET_AUDIO_DELAY:
if( !es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, val.i_time ) ) if( !es_out_SetDelay( p_input->p->p_es_out_display, AUDIO_ES, val.i_time ) )
{
input_SendEventAudioDelay( p_input, val.i_time ); input_SendEventAudioDelay( p_input, val.i_time );
UpdatePtsDelay( p_input );
}
break; break;
case INPUT_CONTROL_SET_SPU_DELAY: case INPUT_CONTROL_SET_SPU_DELAY:
if( !es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, val.i_time ) ) if( !es_out_SetDelay( p_input->p->p_es_out_display, SPU_ES, val.i_time ) )
{
input_SendEventSubtitleDelay( p_input, val.i_time ); input_SendEventSubtitleDelay( p_input, val.i_time );
UpdatePtsDelay( p_input );
}
break; break;
case INPUT_CONTROL_SET_TITLE: case INPUT_CONTROL_SET_TITLE:
...@@ -2338,12 +2353,9 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -2338,12 +2353,9 @@ static int InputSourceInit( input_thread_t *p_input,
if( in->p_demux ) if( in->p_demux )
{ {
int64_t i_pts_delay;
/* Get infos from access_demux */ /* Get infos from access_demux */
demux_Control( in->p_demux, demux_Control( in->p_demux,
DEMUX_GET_PTS_DELAY, &i_pts_delay ); DEMUX_GET_PTS_DELAY, &in->i_pts_delay );
p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
in->b_title_demux = true; in->b_title_demux = true;
if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO, if( demux_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
...@@ -2385,8 +2397,6 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -2385,8 +2397,6 @@ static int InputSourceInit( input_thread_t *p_input,
} }
else else
{ {
int64_t i_pts_delay;
/* Now try a real access */ /* Now try a real access */
in->p_access = access_New( p_input, psz_access, psz_demux, psz_path ); in->p_access = access_New( p_input, psz_access, psz_demux, psz_path );
...@@ -2416,8 +2426,7 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -2416,8 +2426,7 @@ static int InputSourceInit( input_thread_t *p_input,
if( !p_input->b_preparsing ) if( !p_input->b_preparsing )
{ {
access_Control( in->p_access, access_Control( in->p_access,
ACCESS_GET_PTS_DELAY, &i_pts_delay ); ACCESS_GET_PTS_DELAY, &in->i_pts_delay );
p_input->p->i_pts_delay = __MAX( p_input->p->i_pts_delay, i_pts_delay );
in->b_title_demux = false; in->b_title_demux = false;
if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO, if( access_Control( in->p_access, ACCESS_GET_TITLE_INFO,
......
...@@ -68,6 +68,9 @@ typedef struct ...@@ -68,6 +68,9 @@ typedef struct
bool b_can_stream_record; bool b_can_stream_record;
bool b_rescale_ts; bool b_rescale_ts;
/* */
int64_t i_pts_delay;
bool b_eof; /* eof of demuxer */ bool b_eof; /* eof of demuxer */
} input_source_t; } input_source_t;
...@@ -82,9 +85,6 @@ struct input_thread_private_t ...@@ -82,9 +85,6 @@ struct input_thread_private_t
double f_fps; double f_fps;
int i_state; int i_state;
/* Internal caching common to all sources */
mtime_t i_pts_delay;
/* Current state */ /* Current state */
int i_rate; int i_rate;
bool b_recording; bool b_recording;
...@@ -121,8 +121,7 @@ struct input_thread_private_t ...@@ -121,8 +121,7 @@ struct input_thread_private_t
/* Input item */ /* Input item */
input_item_t *p_item; input_item_t *p_item;
/* Clock average variation */
int i_cr_average;
/* Main source */ /* Main source */
input_source_t input; input_source_t input;
/* Slave sources (subs, and others) */ /* Slave sources (subs, and others) */
......
...@@ -774,11 +774,6 @@ static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd, ...@@ -774,11 +774,6 @@ static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
if( !strcmp( psz_cmd, "audio-delay" ) ) if( !strcmp( psz_cmd, "audio-delay" ) )
{ {
/* Change i_pts_delay to make sure es are decoded in time */
if( newval.i_int < 0 || oldval.i_int < 0 )
{
p_input->p->i_pts_delay -= newval.i_int - oldval.i_int;
}
input_ControlPush( p_input, INPUT_CONTROL_SET_AUDIO_DELAY, &newval ); input_ControlPush( p_input, INPUT_CONTROL_SET_AUDIO_DELAY, &newval );
} }
else if( !strcmp( psz_cmd, "spu-delay" ) ) else if( !strcmp( psz_cmd, "spu-delay" ) )
......
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