pcr_descriptor_t * 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 )
{
- p_pes->b_has_pts = 0;
+ 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_pcr->i_synchro_state = SYNCHRO_START;
+ break;
+ }
}
else
{
- 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) );
- 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;
+ p_pes->i_pts += p_pcr->delta_pcr + p_pcr->delta_absolute;
}
- vlc_mutex_unlock( &p_pcr->lock );
}
break;
}
#include "intf_msg.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
******************************************************************************/
void input_PcrReInit( input_thread_t *p_input )
{
- ASSERT(p_input);
-
- p_input->p_pcr->delta_clock = 0;
- p_input->p_pcr->c_average = 0;
- p_input->p_pcr->c_pts = 0;
- p_input->p_pcr->last_pcr = 0;
+ ASSERT( p_input );
-#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
+ p_input->p_pcr->delta_pcr = 0;
+ p_input->p_pcr->last_pcr = 0;
+ p_input->p_pcr->c_average_count = 0;
}
/******************************************************************************
******************************************************************************/
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 )
{
return( -1 );
}
- vlc_mutex_init( &p_input->p_pcr->lock );
input_PcrReInit(p_input);
+ p_input->p_pcr->i_synchro_state = SYNCHRO_NOT_STARTED;
return( 0 );
}
void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es,
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;
- ASSERT(p_pcr_data);
- ASSERT(p_input);
- ASSERT(p_es);
+ ASSERT( p_pcr_data );
+ ASSERT( p_input );
+ ASSERT( p_es );
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 ! */
- pcr_time = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27;
- sys_time = mdate();
- delta_clock = sys_time - pcr_time;
-
- vlc_mutex_lock( &p_pcr->lock );
+ pcr_time = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27;
+ sys_time = mdate();
+ delta_pcr = sys_time - pcr_time;
if( p_es->b_discontinuity ||
( p_pcr->last_pcr != 0 &&
- ( (p_pcr->last_pcr - pcr_time) > PCR_MAX_GAP
- || (p_pcr->last_pcr - pcr_time) < - PCR_MAX_GAP ) ) )
+ ( (p_pcr->last_pcr - pcr_time) > PCR_MAX_GAP
+ || (p_pcr->last_pcr - pcr_time) < - PCR_MAX_GAP ) ) )
{
intf_DbgMsg("input debug: input_PcrReInit()\n");
input_PcrReInit(p_input);
+ p_pcr->i_synchro_state = SYNCHRO_REINIT;
p_es->b_discontinuity = 0;
}
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)))
- / PCR_MAX_AVERAGE_COUNTER;
+ p_pcr->delta_pcr =
+ ( delta_pcr + (p_pcr->delta_pcr * (PCR_MAX_AVERAGE_COUNTER-1)) )
+ / PCR_MAX_AVERAGE_COUNTER;
}
else
{
- p_pcr->delta_clock = (delta_clock + (p_pcr->delta_clock * p_pcr->c_average))
- / (p_pcr->c_average + 1);
- p_pcr->c_average++;
+ p_pcr->delta_pcr =
+ ( delta_pcr + (p_pcr->delta_pcr * p_pcr->c_average_count) )
+ / ( p_pcr->c_average_count + 1 );
+ p_pcr->c_average_count++;
}
- vlc_mutex_unlock( &p_pcr->lock );
-
-#ifdef STATS
+ if( p_pcr->i_synchro_state == SYNCHRO_NOT_STARTED )
{
- 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->c_average_jitter == PCR_MAX_AVERAGE_COUNTER )
- {
- p_pcr->average_jitter = (jitter + (p_pcr->average_jitter * (PCR_MAX_AVERAGE_COUNTER-1)))
- / 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++;
+ p_pcr->i_synchro_state = SYNCHRO_START;
}
-#endif
}
/******************************************************************************