Commit cbcd0db8 authored by Laurent Aimar's avatar Laurent Aimar

Modularize drift algo by introducing a long term average helper.

parent 5fed3935
...@@ -81,6 +81,26 @@ ...@@ -81,6 +81,26 @@
/***************************************************************************** /*****************************************************************************
* Structures * Structures
*****************************************************************************/ *****************************************************************************/
/**
* This structure holds long term average
*/
typedef struct
{
mtime_t i_value;
int i_residue;
int i_count;
int i_divider;
} average_t;
static void AverageInit( average_t *, int i_divider );
static void AverageClean( average_t * );
static void AverageReset( average_t * );
static void AverageUpdate( average_t *, mtime_t i_value );
static mtime_t AverageGet( average_t * );
/* */
struct input_clock_t struct input_clock_t
{ {
/* Reference point */ /* Reference point */
...@@ -99,20 +119,16 @@ struct input_clock_t ...@@ -99,20 +119,16 @@ struct input_clock_t
mtime_t i_system; mtime_t i_system;
} last; } last;
/* Maixmal timestamp returned by input_clock_GetTS (in system unit) */ /* Maximal timestamp returned by input_clock_GetTS (in system unit) */
mtime_t i_ts_max; mtime_t i_ts_max;
/* Clock drift */ /* Clock drift */
mtime_t i_delta_update; /* System time to wait for drift update */ mtime_t i_next_drift_update;
mtime_t i_delta; average_t drift;
int i_delta_residue;
/* Current modifiers */ /* Current modifiers */
bool b_master; bool b_master;
int i_rate; int i_rate;
/* Static configuration */
int i_cr_average;
}; };
static mtime_t ClockStreamToSystem( input_clock_t *, mtime_t i_clock ); static mtime_t ClockStreamToSystem( input_clock_t *, mtime_t i_clock );
...@@ -137,14 +153,12 @@ input_clock_t *input_clock_New( bool b_master, int i_cr_average, int i_rate ) ...@@ -137,14 +153,12 @@ input_clock_t *input_clock_New( bool b_master, int i_cr_average, int i_rate )
cl->i_ts_max = 0; cl->i_ts_max = 0;
cl->i_delta = 0; cl->i_next_drift_update = 0;
cl->i_delta_residue = 0; AverageInit( &cl->drift, i_cr_average );
cl->b_master = b_master; cl->b_master = b_master;
cl->i_rate = i_rate; cl->i_rate = i_rate;
cl->i_cr_average = i_cr_average;
return cl; return cl;
} }
...@@ -153,6 +167,7 @@ input_clock_t *input_clock_New( bool b_master, int i_cr_average, int i_rate ) ...@@ -153,6 +167,7 @@ input_clock_t *input_clock_New( bool b_master, int i_cr_average, int i_rate )
*****************************************************************************/ *****************************************************************************/
void input_clock_Delete( input_clock_t *cl ) void input_clock_Delete( input_clock_t *cl )
{ {
AverageClean( &cl->drift );
free( cl ); free( cl );
} }
...@@ -172,8 +187,6 @@ void input_clock_SetPCR( input_clock_t *cl, ...@@ -172,8 +187,6 @@ void input_clock_SetPCR( input_clock_t *cl,
if( ( !cl->b_has_reference ) || if( ( !cl->b_has_reference ) ||
( i_ck_stream == 0 && cl->last.i_clock != 0 ) ) ( i_ck_stream == 0 && cl->last.i_clock != 0 ) )
{ {
cl->i_delta_update = 0;
/* */ /* */
b_reset_reference= true; b_reset_reference= true;
} }
...@@ -193,8 +206,8 @@ void input_clock_SetPCR( input_clock_t *cl, ...@@ -193,8 +206,8 @@ void input_clock_SetPCR( input_clock_t *cl,
} }
if( b_reset_reference ) if( b_reset_reference )
{ {
cl->i_delta = 0; cl->i_next_drift_update = 0;
cl->i_delta_residue = 0; AverageReset( &cl->drift );
/* Feed synchro with a new reference point. */ /* Feed synchro with a new reference point. */
ClockSetReference( cl, i_ck_stream, ClockSetReference( cl, i_ck_stream,
...@@ -204,19 +217,13 @@ void input_clock_SetPCR( input_clock_t *cl, ...@@ -204,19 +217,13 @@ void input_clock_SetPCR( input_clock_t *cl,
cl->last.i_clock = i_ck_stream; cl->last.i_clock = i_ck_stream;
cl->last.i_system = i_ck_system; cl->last.i_system = i_ck_system;
if( !b_synchronize && i_ck_system - cl->i_delta_update > 200000 ) if( !b_synchronize && cl->i_next_drift_update < i_ck_system )
{ {
/* Smooth clock reference variations. */ const mtime_t i_converted = ClockSystemToStream( cl, i_ck_system );
const mtime_t i_extrapoled_clock = ClockSystemToStream( cl, i_ck_system );
/* Bresenham algorithm to smooth variations. */
const mtime_t i_tmp = cl->i_delta * (cl->i_cr_average - 1) +
( i_extrapoled_clock - i_ck_stream ) * 1 +
cl->i_delta_residue;
cl->i_delta_residue = i_tmp % cl->i_cr_average; AverageUpdate( &cl->drift, i_converted - i_ck_stream );
cl->i_delta = i_tmp / cl->i_cr_average;
cl->i_delta_update = i_ck_system; cl->i_next_drift_update = i_ck_system + CLOCK_FREQ/5; /* FIXME why that */
} }
} }
...@@ -241,7 +248,7 @@ mtime_t input_clock_GetTS( input_clock_t *cl, ...@@ -241,7 +248,7 @@ mtime_t input_clock_GetTS( input_clock_t *cl,
return 0; return 0;
/* */ /* */
i_converted_ts = ClockStreamToSystem( cl, i_ts + cl->i_delta ); i_converted_ts = ClockStreamToSystem( cl, i_ts + AverageGet( &cl->drift ) );
if( i_converted_ts > cl->i_ts_max ) if( i_converted_ts > cl->i_ts_max )
cl->i_ts_max = i_converted_ts; cl->i_ts_max = i_converted_ts;
...@@ -320,4 +327,46 @@ static void ClockSetReference( input_clock_t *cl, ...@@ -320,4 +327,46 @@ static void ClockSetReference( input_clock_t *cl,
cl->ref.i_system = i_system; cl->ref.i_system = i_system;
} }
/*****************************************************************************
* Long term average helpers
*****************************************************************************/
typedef struct
{
mtime_t i_value;
int i_residue;
int i_count;
int i_divider;
} averager_t;
static void AverageInit( average_t *p_avg, int i_divider )
{
p_avg->i_divider = i_divider;
AverageReset( p_avg );
}
static void AverageClean( average_t *p_avg )
{
VLC_UNUSED(p_avg);
}
static void AverageReset( average_t *p_avg )
{
p_avg->i_value = 0;
p_avg->i_residue = 0;
p_avg->i_count = 0;
}
static void AverageUpdate( average_t *p_avg, mtime_t i_value )
{
const int i_f0 = __MIN( p_avg->i_divider - 1, p_avg->i_count );
const int i_f1 = p_avg->i_divider - i_f0;
const mtime_t i_tmp = i_f0 * p_avg->i_value + i_f1 * i_value + p_avg->i_residue;
p_avg->i_value = i_tmp / p_avg->i_divider;
p_avg->i_residue = i_tmp % p_avg->i_divider;
p_avg->i_count++;
}
static mtime_t AverageGet( average_t *p_avg )
{
return p_avg->i_value;
}
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