+#ifdef SAM_SYNCHRO
+/*****************************************************************************
+ * vpar_SynchroUpdateTab : Update a mean table in the synchro structure
+ *****************************************************************************/
+float vpar_SynchroUpdateTab( video_synchro_tab_t * tab, int count )
+{
+
+ tab->mean = ( tab->mean + MAX_COUNT * count ) / ( MAX_COUNT + 1 );
+ tab->deviation = ( tab->deviation + MAX_COUNT * abs (tab->mean - count) )
+ / ( MAX_COUNT + 1 );
+
+ return tab->deviation;
+}
+
+/*****************************************************************************
+ * vpar_SynchroUpdateStructures : Update the synchro structures
+ *****************************************************************************/
+void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
+ int i_coding_type, int dropped )
+{
+ float candidate_deviation;
+ float optimal_deviation;
+ float predict;
+ mtime_t i_current_pts;
+ mtime_t i_delay;
+ mtime_t i_displaydate;
+ decoder_fifo_t * decoder_fifo = p_vpar->bit_stream.p_decoder_fifo;
+
+ /* interpolate the current _decode_ PTS */
+ i_current_pts = decoder_fifo->buffer[decoder_fifo->i_start]->b_has_pts ?
+ decoder_fifo->buffer[decoder_fifo->i_start]->i_pts :
+ 0;
+ if( !i_current_pts )
+ {
+ i_current_pts = p_vpar->synchro.i_last_decode_pts
+ + 1000000.0 / (1 + p_vpar->synchro.actual_fps);
+ }
+ p_vpar->synchro.i_last_decode_pts = i_current_pts;
+
+ /* see if the current image has a pts - if not, set to 0 */
+ p_vpar->synchro.fifo[p_vpar->synchro.i_fifo_stop].i_pts
+ = i_current_pts;
+
+ /* update display time */
+ i_displaydate = decoder_fifo->buffer[decoder_fifo->i_start]->b_has_pts ?
+ decoder_fifo->buffer[decoder_fifo->i_start]->i_pts :
+ 0;
+ if( !i_displaydate || i_coding_type != I_CODING_TYPE )
+ {
+ if (!p_vpar->synchro.i_images_since_pts )
+ p_vpar->synchro.i_images_since_pts = 10;
+
+ i_displaydate = p_vpar->synchro.i_last_display_pts
+ + 1000000.0 / (p_vpar->synchro.theorical_fps);
+ //fprintf (stderr, " ");
+ }
+
+ decoder_fifo->buffer[decoder_fifo->i_start]->b_has_pts = 0;
+
+ /* else fprintf (stderr, "R ");
+ if (dropped) fprintf (stderr, " "); else fprintf (stderr, "* ");
+ fprintf (stderr, "%i ", i_coding_type);
+ fprintf (stderr, "pts %lli delta %lli\n", i_displaydate, i_displaydate - p_vpar->synchro.i_last_display_pts); */
+
+ p_vpar->synchro.i_images_since_pts--;
+ p_vpar->synchro.i_last_display_pts = i_displaydate;
+
+
+
+ /* update structures */
+ switch(i_coding_type)
+ {
+ case P_CODING_TYPE:
+
+ p_vpar->synchro.current_p_count++;
+ if( !dropped ) p_vpar->synchro.nondropped_p_count++;
+ break;
+
+ case B_CODING_TYPE:
+ p_vpar->synchro.current_b_count++;
+ if( !dropped ) p_vpar->synchro.nondropped_b_count++;
+ break;
+
+ case I_CODING_TYPE:
+
+ /* update information about images we can decode */
+ if (i_current_pts != p_vpar->synchro.i_last_i_pts)
+ {
+ if ( p_vpar->synchro.i_last_i_pts && i_current_pts != p_vpar->synchro.i_last_i_pts)
+ {
+ p_vpar->synchro.theorical_fps = (p_vpar->synchro.theorical_fps + 1000000.0 * (1 + p_vpar->synchro.current_b_count + p_vpar->synchro.current_p_count) / (i_current_pts - p_vpar->synchro.i_last_i_pts)) / 2;
+ }
+ p_vpar->synchro.i_last_i_pts = i_current_pts;
+ }
+
+ if( !dropped )
+ {
+ if ( p_vpar->synchro.i_last_nondropped_i_pts && i_current_pts != p_vpar->synchro.i_last_nondropped_i_pts)
+ {
+ p_vpar->synchro.actual_fps = (p_vpar->synchro.actual_fps + 1000000.0 * (1 + p_vpar->synchro.nondropped_b_count + p_vpar->synchro.nondropped_p_count) / (i_current_pts - p_vpar->synchro.i_last_nondropped_i_pts)) / 2;
+ }
+
+ }
+
+
+ /* update all the structures for P images */
+
+ /* period == 1 */
+ optimal_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_p[0],
+ p_vpar->synchro.current_p_count);
+ predict = p_vpar->synchro.tab_p[0].mean;
+
+ /* period == 2 */
+ candidate_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_p[1 + (p_vpar->synchro.modulo & 0x1)],
+ p_vpar->synchro.current_p_count);
+ if (candidate_deviation < optimal_deviation)
+ {
+ optimal_deviation = candidate_deviation;
+ predict = p_vpar->synchro.tab_p[1 + (p_vpar->synchro.modulo & 0x1)].mean;
+ }
+
+ /* period == 3 */
+ candidate_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_p[3 + (p_vpar->synchro.modulo % 3)],
+ p_vpar->synchro.current_p_count);
+ if (candidate_deviation < optimal_deviation)
+ {
+ optimal_deviation = candidate_deviation;
+ predict = p_vpar->synchro.tab_p[1 + (p_vpar->synchro.modulo % 3)].mean;
+ }
+
+ p_vpar->synchro.p_count_predict = predict;
+ p_vpar->synchro.current_p_count = 0;
+
+
+ /* update all the structures for B images */
+
+ /* period == 1 */
+ optimal_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_b[0],
+ p_vpar->synchro.current_b_count);
+ predict = p_vpar->synchro.tab_b[0].mean;
+
+ /* period == 2 */
+ candidate_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_b[1 + (p_vpar->synchro.modulo & 0x1)],
+ p_vpar->synchro.current_b_count);
+ if (candidate_deviation < optimal_deviation)
+ {
+ optimal_deviation = candidate_deviation;
+ predict = p_vpar->synchro.tab_b[1 + (p_vpar->synchro.modulo & 0x1)].mean;
+ }
+
+ /* period == 3 */
+ candidate_deviation = vpar_SynchroUpdateTab(
+ &p_vpar->synchro.tab_b[3 + (p_vpar->synchro.modulo % 3)],
+ p_vpar->synchro.current_b_count);
+ if (candidate_deviation < optimal_deviation)
+ {
+ optimal_deviation = candidate_deviation;
+ predict = p_vpar->synchro.tab_b[1 + (p_vpar->synchro.modulo % 3)].mean;
+ }
+
+ p_vpar->synchro.b_count_predict = predict;
+ p_vpar->synchro.current_b_count = 0;
+
+ /* now we calculated all statistics, it's time to
+ * decide what we have the time to display
+ */
+ i_delay = i_current_pts - p_vpar->synchro.i_last_nondropped_i_pts;
+
+ p_vpar->synchro.can_display_i
+ = ( p_vpar->synchro.i_mean_decode_time < i_delay );
+
+ p_vpar->synchro.can_display_p
+ = ( p_vpar->synchro.i_mean_decode_time
+ * (1 + p_vpar->synchro.p_count_predict) < i_delay );
+
+ if( !p_vpar->synchro.can_display_p )
+ {
+ p_vpar->synchro.displayable_p
+ = -1 + i_delay / p_vpar->synchro.i_mean_decode_time;
+ if( p_vpar->synchro.displayable_p < 0 )
+ p_vpar->synchro.displayable_p = 0;
+ }
+ else
+ p_vpar->synchro.displayable_p = 0;
+
+ if( p_vpar->synchro.can_display_p
+ && !(p_vpar->synchro.can_display_b
+ = ( p_vpar->synchro.i_mean_decode_time
+ * (1 + p_vpar->synchro.b_count_predict
+ + p_vpar->synchro.p_count_predict)) < i_delay) )
+ {
+ p_vpar->synchro.displayable_b
+ = -2.0 + i_delay / p_vpar->synchro.i_mean_decode_time
+ - p_vpar->synchro.can_display_p;
+ }
+ else
+ p_vpar->synchro.displayable_b = 0;
+
+#if 0
+ fprintf( stderr,
+ "I %i P %i (%f) B %i (%f)\n",
+ p_vpar->synchro.can_display_i,
+ p_vpar->synchro.can_display_p,
+ p_vpar->synchro.displayable_p,
+ p_vpar->synchro.can_display_b,
+ p_vpar->synchro.displayable_b );
+#endif
+
+ /* update some values */
+ if( !dropped )
+ {
+ p_vpar->synchro.i_last_nondropped_i_pts = i_current_pts;
+ p_vpar->synchro.nondropped_p_count = 0;
+ p_vpar->synchro.nondropped_b_count = 0;
+ }
+
+ break;
+
+ }
+
+ p_vpar->synchro.modulo++;
+
+}
+