Commit 5fc945b6 authored by Jean-Marc Dressler's avatar Jean-Marc Dressler

Refonte de la synchro qui devrait eliminer les problemes rencontres

lors des changements de flux.
parent 5671a4b5
...@@ -207,23 +207,15 @@ typedef struct ...@@ -207,23 +207,15 @@ typedef struct
typedef struct pcr_descriptor_struct typedef struct pcr_descriptor_struct
{ {
vlc_mutex_t lock; /* pcr modification lock */ /* system_date = PTS_date + delta_pcr + delta_absolute */
mtime_t delta_pcr;
mtime_t delta_absolute;
mtime_t delta_clock;
mtime_t delta_decode;
/* represents decoder_time - pcr_time in usecondes */
mtime_t last_pcr; mtime_t last_pcr;
count_t c_average; u32 i_synchro_state;
count_t c_average_count;
/* counter used to compute dynamic average values */ /* counter used to compute dynamic average values */
count_t c_pts;
#ifdef STATS
/* Stats */
count_t c_average_jitter;
mtime_t max_jitter; /* the evalueted maximum jitter */
mtime_t average_jitter; /* the evalueted average jitter */
count_t c_pcr; /* the number of PCR which have been decoded */
#endif
} pcr_descriptor_t; } pcr_descriptor_t;
/****************************************************************************** /******************************************************************************
......
...@@ -9,9 +9,14 @@ ...@@ -9,9 +9,14 @@
* new_average = (old_average * c_average + new_sample_value) / (c_average +1) */ * new_average = (old_average * c_average + new_sample_value) / (c_average +1) */
#define PCR_MAX_AVERAGE_COUNTER 40 #define PCR_MAX_AVERAGE_COUNTER 40
/* Maximum allowed gap between two PCRs. */ /* Maximum gap allowed between two PCRs. */
#define PCR_MAX_GAP 1000000 #define PCR_MAX_GAP 1000000
/* synchro states */
#define SYNCHRO_NOT_STARTED 1
#define SYNCHRO_START 2
#define SYNCHRO_REINIT 3
/****************************************************************************** /******************************************************************************
* Prototypes * Prototypes
******************************************************************************/ ******************************************************************************/
......
...@@ -915,27 +915,38 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input, ...@@ -915,27 +915,38 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
pcr_descriptor_t * p_pcr; pcr_descriptor_t * p_pcr;
p_pcr = p_input->p_pcr; p_pcr = p_input->p_pcr;
vlc_mutex_lock( &p_pcr->lock );
if( p_pcr->delta_clock == 0 ) p_pes->i_pts =
( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) |
(((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) ) * 300;
p_pes->i_pts /= 27;
if( p_pcr->i_synchro_state )
{ {
switch( p_pcr->i_synchro_state )
{
case SYNCHRO_NOT_STARTED:
p_pes->b_has_pts = 0;
break;
case SYNCHRO_START:
p_pes->i_pts += p_pcr->delta_pcr;
p_pcr->delta_absolute = mdate() - p_pes->i_pts + 500000;
p_pes->i_pts += p_pcr->delta_absolute;
p_pcr->i_synchro_state = 0;
break;
case SYNCHRO_REINIT: /* We skip a PES */
p_pes->b_has_pts = 0; p_pes->b_has_pts = 0;
p_pcr->i_synchro_state = SYNCHRO_START;
break;
}
} }
else else
{ {
p_pes->i_pts = ( ((mtime_t)(p_pes->p_pes_header[9] & 0x0E) << 29) | p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
(((mtime_t)U16_AT(p_pes->p_pes_header + 10) << 14) - (1 << 14)) |
((mtime_t)U16_AT(p_pes->p_pes_header + 12) >> 1) );
p_pes->i_pts *= 300;
p_pes->i_pts /= 27;
p_pes->i_pts += p_pcr->delta_clock;
if( p_pcr->c_pts == 0 )
{
p_pcr->delta_decode = mdate() - p_pes->i_pts + 500000;
}
p_pes->i_pts += p_pcr->delta_decode;
p_pcr->c_pts += 1;
} }
vlc_mutex_unlock( &p_pcr->lock );
} }
break; break;
} }
......
...@@ -22,25 +22,38 @@ ...@@ -22,25 +22,38 @@
#include "intf_msg.h" #include "intf_msg.h"
#include "input_pcr.h" #include "input_pcr.h"
/* Note:
*
* SYNCHRONIZATION METHOD
*
* We compute an average for the pcr because we want to eliminate the
* network jitter and keep the low frequency variations. The average is
* in fact a low pass filter and the jitter is a high frequency signal
* that is why it is eliminated by the filter/average.
*
* The low frequency variations enable us to synchronize the client clock
* with the server clock because they represent the time variation between
* the 2 clocks. Those variations (ie the filtered pcr) are used to compute
* the presentation dates for the audio and video frames. With those dates
* we can decoding (or trashing) the MPEG2 stream at "exactly" the same rate
* as it is sent by the server and so we keep the synchronization between
* the server and the client.
*
* It is a very important matter if you want to avoid underflow or overflow
* in all the FIFOs, but it may be not enough.
*
*/
/****************************************************************************** /******************************************************************************
* input_PcrReInit : Reinitialize the pcr_descriptor * input_PcrReInit : Reinitialize the pcr_descriptor
******************************************************************************/ ******************************************************************************/
void input_PcrReInit( input_thread_t *p_input ) void input_PcrReInit( input_thread_t *p_input )
{ {
ASSERT(p_input); ASSERT( p_input );
p_input->p_pcr->delta_clock = 0; p_input->p_pcr->delta_pcr = 0;
p_input->p_pcr->c_average = 0;
p_input->p_pcr->c_pts = 0;
p_input->p_pcr->last_pcr = 0; p_input->p_pcr->last_pcr = 0;
p_input->p_pcr->c_average_count = 0;
#ifdef STATS
p_input->p_pcr->c_average_jitter = 0;
p_input->p_pcr->c_pcr = 0;
p_input->p_pcr->max_jitter = 0;
/* For the printf in input_PcrDecode() (for debug purpose only) */
printf("\n");
#endif
} }
/****************************************************************************** /******************************************************************************
...@@ -48,14 +61,14 @@ void input_PcrReInit( input_thread_t *p_input ) ...@@ -48,14 +61,14 @@ void input_PcrReInit( input_thread_t *p_input )
******************************************************************************/ ******************************************************************************/
int input_PcrInit( input_thread_t *p_input ) int input_PcrInit( input_thread_t *p_input )
{ {
ASSERT(p_input); ASSERT( p_input );
if( (p_input->p_pcr = malloc(sizeof(pcr_descriptor_t))) == NULL ) if( (p_input->p_pcr = malloc(sizeof(pcr_descriptor_t))) == NULL )
{ {
return( -1 ); return( -1 );
} }
vlc_mutex_init( &p_input->p_pcr->lock );
input_PcrReInit(p_input); input_PcrReInit(p_input);
p_input->p_pcr->i_synchro_state = SYNCHRO_NOT_STARTED;
return( 0 ); return( 0 );
} }
...@@ -66,22 +79,20 @@ int input_PcrInit( input_thread_t *p_input ) ...@@ -66,22 +79,20 @@ int input_PcrInit( input_thread_t *p_input )
void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es, void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es,
u8* p_pcr_data ) u8* p_pcr_data )
{ {
mtime_t pcr_time, sys_time, delta_clock; mtime_t pcr_time, sys_time, delta_pcr;
pcr_descriptor_t *p_pcr; pcr_descriptor_t *p_pcr;
ASSERT(p_pcr_data); ASSERT( p_pcr_data );
ASSERT(p_input); ASSERT( p_input );
ASSERT(p_es); ASSERT( p_es );
p_pcr = p_input->p_pcr; p_pcr = p_input->p_pcr;
/* Express the PCR in microseconde /* Convert the PCR in microseconde
* WARNING: do not remove the casts in the following calculation ! */ * WARNING: do not remove the casts in the following calculation ! */
pcr_time = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27; pcr_time = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27;
sys_time = mdate(); sys_time = mdate();
delta_clock = sys_time - pcr_time; delta_pcr = sys_time - pcr_time;
vlc_mutex_lock( &p_pcr->lock );
if( p_es->b_discontinuity || if( p_es->b_discontinuity ||
( p_pcr->last_pcr != 0 && ( p_pcr->last_pcr != 0 &&
...@@ -90,67 +101,29 @@ void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es, ...@@ -90,67 +101,29 @@ void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es,
{ {
intf_DbgMsg("input debug: input_PcrReInit()\n"); intf_DbgMsg("input debug: input_PcrReInit()\n");
input_PcrReInit(p_input); input_PcrReInit(p_input);
p_pcr->i_synchro_state = SYNCHRO_REINIT;
p_es->b_discontinuity = 0; p_es->b_discontinuity = 0;
} }
p_pcr->last_pcr = pcr_time; p_pcr->last_pcr = pcr_time;
if( p_pcr->c_average == PCR_MAX_AVERAGE_COUNTER ) if( p_pcr->c_average_count == PCR_MAX_AVERAGE_COUNTER )
{ {
p_pcr->delta_clock = (delta_clock + (p_pcr->delta_clock * (PCR_MAX_AVERAGE_COUNTER-1))) p_pcr->delta_pcr =
( delta_pcr + (p_pcr->delta_pcr * (PCR_MAX_AVERAGE_COUNTER-1)) )
/ PCR_MAX_AVERAGE_COUNTER; / PCR_MAX_AVERAGE_COUNTER;
} }
else else
{ {
p_pcr->delta_clock = (delta_clock + (p_pcr->delta_clock * p_pcr->c_average)) p_pcr->delta_pcr =
/ (p_pcr->c_average + 1); ( delta_pcr + (p_pcr->delta_pcr * p_pcr->c_average_count) )
p_pcr->c_average++; / ( p_pcr->c_average_count + 1 );
} p_pcr->c_average_count++;
vlc_mutex_unlock( &p_pcr->lock );
#ifdef STATS
{
mtime_t jitter;
jitter = delta_clock - p_pcr->delta_clock;
/* Compute the maximum jitter */
if( jitter < 0 )
{
if( (p_pcr->max_jitter <= 0 && p_pcr->max_jitter >= jitter) ||
(p_pcr->max_jitter >= 0 && p_pcr->max_jitter <= -jitter))
{
p_pcr->max_jitter = jitter;
}
}
else
{
if( (p_pcr->max_jitter <= 0 && -p_pcr->max_jitter <= jitter) ||
(p_pcr->max_jitter >= 0 && p_pcr->max_jitter <= jitter))
{
p_pcr->max_jitter = jitter;
}
} }
/* Compute the average jitter */ if( p_pcr->i_synchro_state == SYNCHRO_NOT_STARTED )
if( p_pcr->c_average_jitter == PCR_MAX_AVERAGE_COUNTER )
{ {
p_pcr->average_jitter = (jitter + (p_pcr->average_jitter * (PCR_MAX_AVERAGE_COUNTER-1))) p_pcr->i_synchro_state = SYNCHRO_START;
/ PCR_MAX_AVERAGE_COUNTER;
}
else
{
p_pcr->average_jitter = (jitter + (p_pcr->average_jitter * p_pcr->c_average_jitter))
/ (p_pcr->c_average + 1);
p_pcr->c_average_jitter++;
}
printf("delta: % 13Ld, max_jitter: % 9Ld, av. jitter: % 6Ld, PCR %6ld \r",
p_pcr->delta_clock , p_pcr->max_jitter, p_pcr->average_jitter, p_pcr->c_pcr);
fflush(stdout);
p_pcr->c_pcr++;
} }
#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