* Totally new frame dropping algorithm.
authorChristophe Massiot <massiot@videolan.org>
Mon, 13 Nov 2000 13:58:18 +0000 (13:58 +0000)
committerChristophe Massiot <massiot@videolan.org>
Mon, 13 Nov 2000 13:58:18 +0000 (13:58 +0000)
  * Fixed a bug in video_ouput.c which made the stream go backwards
    sometimes.
  * Fixed a bug in video_ouput.c which trashed more late pictures than
    necessary.
  * Fixed the DEBUG mode in the Makefile.
  * Fixed a bug in mwait() which made us wait too long.

Ca va tuer.

ChangeLog
Makefile.in
include/config.h.in
include/video_output.h
include/vpar_synchro.h
src/misc/mtime.c
src/video_output/video_output.c
src/video_parser/video_parser.c
src/video_parser/vpar_synchro.c

index fa257a3..6855676 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,6 +8,13 @@
     mode.
   * Added --broadcast option for network input.
   * Screen is now emptied when framebuffer output exits.
+  * Totally new frame dropping algorithm.
+  * Fixed a bug in video_ouput.c which made the stream go backwards
+    sometimes.
+  * Fixed a bug in video_ouput.c which trashed more late pictures than
+    necessary.
+  * Fixed the DEBUG mode in the Makefile.
+  * Fixed a bug in mwait() which made us wait too long.
 
 Mon, 28 Aug 2000 02:34:18 +0200
 0.1.99i :
index 403ebf4..d867a08 100644 (file)
@@ -106,10 +106,6 @@ endif
 else
 CFLAGS += -march=pentium
 endif
-# Eventual MMX optimizations for x86
-ifneq (,$(findstring mmx,$(ARCH)))
-CFLAGS += -DHAVE_MMX
-endif
 endif
 
 # Optimizations for PowerPC
@@ -127,9 +123,16 @@ ifneq (,$(findstring sparc,$(ARCH)))
 CFLAGS += -mhard-float
 endif
 
-# End of optimizations
+# /debug
+endif
+
+# Eventual MMX optimizations for x86
+ifneq (,$(findstring mmx,$(ARCH)))
+CFLAGS += -DHAVE_MMX
 endif
 
+# End of optimizations
+
 #
 # C compiler flags: dependancies
 #
index eab84b4..3400baa 100644 (file)
 /* Number of pictures required to computes the FPS rate */
 #define VOUT_FPS_SAMPLES                20
 
+/* Better be in advance when awakening than late... */
+#define VOUT_MWAIT_TOLERANCE            ((int)(0.020*CLOCK_FREQ))
+
 /*
  * Framebuffer settings
  */
  * It should be approximately the time needed to perform a complete picture
  * loop. Since it only happens when the video heap is full, it does not need
  * to be too low, even if it blocks the decoder. */
-#define VPAR_OUTMEM_SLEEP               ((int)(0.050*CLOCK_FREQ))
+#define VPAR_OUTMEM_SLEEP               ((int)(0.020*CLOCK_FREQ))
 
 /* Optimization level, from 0 to 2 - 1 is generally a good compromise. Remember
  * that raising this level dramatically lengthens the compilation time. */
 /* Maximal number of commands which can be saved in history list */
 #define INTF_CONSOLE_MAX_HISTORY        20
 
-/*****************************************************************************
- * Synchro configuration
- *****************************************************************************/
-
-#define VOUT_SYNCHRO_LEVEL_START        5 << 10
-#define VOUT_SYNCHRO_LEVEL_MAX          15 << 10
-#define VOUT_SYNCHRO_HEAP_IDEAL_SIZE    5
-
index 5e44b4e..2949df2 100644 (file)
@@ -135,7 +135,7 @@ typedef struct vout_thread_s
     p_vout_sys_t        p_sys;                       /* system output method */
     vdec_DecodeMacroblock_t *
                         vdec_DecodeMacroblock;    /* decoder function to use */
-
+                                                                   
     /* Current display properties */
     u16                 i_changes;             /* changes made to the thread */
     int                 i_width;              /* current output method width */
@@ -181,6 +181,7 @@ typedef struct vout_thread_s
     boolean_t           b_info;              /* print additional information */
     boolean_t           b_interface;                     /* render interface */
     boolean_t           b_scale;                    /* allow picture scaling */
+    mtime_t             render_time;             /* last picture render time */
 
     /* Idle screens management */
     mtime_t             last_display_date;     /* last non idle display date */
@@ -190,7 +191,6 @@ typedef struct vout_thread_s
 #ifdef STATS
     /* Statistics - these numbers are not supposed to be accurate, but are a
      * good indication of the thread status */
-    mtime_t             render_time;             /* last picture render time */
     count_t             c_fps_samples;                     /* picture counts */
     mtime_t             p_fps_sample[VOUT_FPS_SAMPLES]; /* FPS samples dates */
 #endif
@@ -208,10 +208,6 @@ typedef struct vout_thread_s
     /* Bitmap fonts */
     p_vout_font_t       p_default_font;                      /* default font */
     p_vout_font_t       p_large_font;                          /* large font */
-
-    /* Synchronization informations - synchro level is updated by the vout
-     * thread and read by decoder threads */
-    int                 i_synchro_level;                   /* trashing level */
 } vout_thread_t;
 
 /* Flags for changes - these flags are set in the i_changes field when another
@@ -224,7 +220,9 @@ typedef struct vout_thread_s
 #define VOUT_DEPTH_CHANGE       0x0400                      /* depth changed */
 #define VOUT_GAMMA_CHANGE       0x0010                      /* gamma changed */
 #define VOUT_YUV_CHANGE         0x0800                  /* change yuv tables */
-#define VOUT_NODISPLAY_CHANGE   0xff00    /* changes which forbidden display */
+
+/* Disabled for thread deadlocks issues --Meuuh */
+//#define VOUT_NODISPLAY_CHANGE   0xff00    /* changes which forbidden display */
 
 /*****************************************************************************
  * Macros
index b2e6e7b..d7bec72 100644 (file)
@@ -3,9 +3,7 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors: Samuel Hocevar <sam@via.ecp.fr>
- *          Jean-Marc Dressler <polux@via.ecp.fr>
- *          Christophe Massiot <massiot@via.ecp.fr>
+ * Author: Christophe Massiot <massiot@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *  "video_fifo.h"
  *****************************************************************************/
 
-#define SAM_SYNCHRO
-//#define POLUX_SYNCHRO
-//#define MEUUH_SYNCHRO
-
 /*****************************************************************************
  * video_synchro_t and video_synchro_tab_s : timers for the video synchro
  *****************************************************************************/
-#ifdef SAM_SYNCHRO
+#define MAX_DECODING_PIC        16
+#define MAX_PIC_AVERAGE         8
+
+/* Read the discussion on top of vpar_synchro.c for more information. */
 typedef struct video_synchro_s
 {
     /* synchro algorithm */
-    int          i_type;
+    int             i_type;
 
     /* fifo containing decoding dates */
-    mtime_t      i_date_fifo[16];
-    unsigned int i_start;
-    unsigned int i_stop;
-
-    /* mean decoding time */
-    mtime_t i_delay;
-    mtime_t i_theorical_delay;
-
-    /* dates */
-    mtime_t i_last_pts;                   /* pts of the last displayed image */
-    mtime_t i_last_seen_I_pts;              /* date of the last I we decoded */
-    mtime_t i_last_kept_I_pts;            /* pts of last non-dropped I image */
-
-    /* P images since the last I */
-    unsigned int i_P_seen;
-    unsigned int i_P_kept;
-    /* B images since the last I */
-    unsigned int i_B_seen;
-    unsigned int i_B_kept;
-
-    /* can we display pictures ? */
-    boolean_t     b_all_I;
-    boolean_t     b_all_P;
-    int           displayable_p;
-    boolean_t     b_all_B;
-    int           displayable_b;
-    boolean_t     b_dropped_last;
-
-} video_synchro_t;
-
-#define FIFO_INCREMENT( i_counter ) \
-    p_vpar->synchro.i_counter = (p_vpar->synchro.i_counter + 1) & 0xf;
-
-#define VPAR_SYNCHRO_DEFAULT   0
-#define VPAR_SYNCHRO_I         1
-#define VPAR_SYNCHRO_Iplus     2
-#define VPAR_SYNCHRO_IP        3
-#define VPAR_SYNCHRO_IPplus    4
-#define VPAR_SYNCHRO_IPB       5
-
+    mtime_t         p_date_fifo[MAX_DECODING_PIC];
+    int             pi_coding_types[MAX_DECODING_PIC];
+    unsigned int    i_start, i_end;
+    vlc_mutex_t     fifo_lock;
+
+    /* stream properties */
+    unsigned int    i_n_p, i_n_b;
+
+    /* decoding values */
+    mtime_t         p_tau[4];                  /* average decoding durations */
+    unsigned int    pi_meaningful[4];            /* number of durations read */
+    /* and p_vout->render_time (read with p_vout->change_lock) */
+
+    /* stream context */
+    unsigned int    i_eta_p, i_eta_b;
+    boolean_t       b_dropped_last;            /* for special synchros below */
+    mtime_t         backward_pts, current_pts;
+
+#ifdef STATS
+    unsigned int    i_B_self, i_B_next, i_B_last, i_B_I;
 #endif
-
-#ifdef MEUUH_SYNCHRO
-typedef struct video_synchro_s
-{
-    int         kludge_level, kludge_p, kludge_b, kludge_nbp, kludge_nbb;
-    int         kludge_nbframes;
-    mtime_t     kludge_date, kludge_prevdate;
-    int         i_coding_type;
 } video_synchro_t;
 
-#define SYNC_TOLERATE   ((int)(0.010*CLOCK_FREQ))                   /* 10 ms */
-#define SYNC_DELAY      ((int)(0.500*CLOCK_FREQ))                  /* 500 ms */
-#endif
-
-#ifdef POLUX_SYNCHRO
-
-#define SYNC_AVERAGE_COUNT 10
-
-typedef struct video_synchro_s
-{
-    /* Date Section */
-
-    /* Dates needed to compute the date of the current frame
-     * We also use the stream frame rate (sequence.i_frame_rate) */
-    mtime_t     i_current_frame_date;
-    mtime_t     i_backward_frame_date;
+#define FIFO_INCREMENT( i_counter )                                         \
+    p_vpar->synchro.i_counter =                                             \
+        (p_vpar->synchro.i_counter + 1) % MAX_DECODING_PIC;
 
-    /* Frame Trashing Section */
-
-    int         i_b_nb, i_p_nb;   /* number of decoded P and B between two I */
-    float       r_b_average, r_p_average;
-    int         i_b_count, i_p_count, i_i_count;
-    int         i_b_trasher;                /* used for brensenham algorithm */
-
-} video_synchro_t;
-
-#endif
+/* Synchro algorithms */
+#define VPAR_SYNCHRO_DEFAULT    0
+#define VPAR_SYNCHRO_I          1
+#define VPAR_SYNCHRO_Iplus      2
+#define VPAR_SYNCHRO_IP         3
+#define VPAR_SYNCHRO_IPplus     4
+#define VPAR_SYNCHRO_IPB        5
 
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
+void vpar_SynchroInit           ( struct vpar_thread_s * p_vpar );
 boolean_t vpar_SynchroChoose    ( struct vpar_thread_s * p_vpar,
                                   int i_coding_type, int i_structure );
 void vpar_SynchroTrash          ( struct vpar_thread_s * p_vpar,
@@ -139,7 +93,3 @@ void vpar_SynchroDecode         ( struct vpar_thread_s * p_vpar,
                                   int i_coding_type, int i_structure );
 void vpar_SynchroEnd            ( struct vpar_thread_s * p_vpar );
 mtime_t vpar_SynchroDate        ( struct vpar_thread_s * p_vpar );
-
-#ifndef SAM_SYNCHRO
-void vpar_SynchroKludge         ( struct vpar_thread_s *, mtime_t );
-#endif
index 9272a11..f019eb9 100644 (file)
@@ -118,7 +118,9 @@ void mwait( mtime_t date )
     gettimeofday( &tv_date, NULL );
 
     /* calculate delay and check if current date is before wished date */
-    delay = date - (mtime_t) tv_date.tv_sec * 1000000 - (mtime_t) tv_date.tv_usec;
+    delay = date - (mtime_t) tv_date.tv_sec * 1000000 - (mtime_t) tv_date.tv_usec - 10000;
+    /* Linux/i386 has a granularity of 10 ms. It's better to be in advance
+     * than to be late. */
     if( delay <= 0 )                 /* wished date is now or already passed */
     {
         return;
index 292c3a1..f34bc68 100644 (file)
@@ -74,7 +74,6 @@ static void     RenderInterface   ( vout_thread_t *p_vout );
 static int      RenderIdle        ( vout_thread_t *p_vout );
 static int      RenderSplash      ( vout_thread_t *p_vout );
 static void     RenderInfo        ( vout_thread_t *p_vout );
-static void     Synchronize       ( vout_thread_t *p_vout, s64 i_delay );
 static int      Manage            ( vout_thread_t *p_vout );
 static int      Align             ( vout_thread_t *p_vout, int *pi_x,
                                     int *pi_y, int i_width, int i_height,
@@ -175,10 +174,10 @@ vout_thread_t * vout_CreateThread   ( char *psz_display, int i_root_window,
     p_vout->last_display_date   = 0;
     p_vout->last_idle_date      = 0;
     p_vout->init_display_date   = mdate();
+    p_vout->render_time         = 10000;
 
 #ifdef STATS
     /* Initialize statistics fields */
-    p_vout->render_time         = 0;
     p_vout->c_fps_samples       = 0;
 #endif
 
@@ -199,9 +198,6 @@ vout_thread_t * vout_CreateThread   ( char *psz_display, int i_root_window,
     }
     p_vout->i_pictures = 0;
 
-    /* Initialize synchronization information */
-    p_vout->i_synchro_level     = VOUT_SYNCHRO_LEVEL_START;
-
     /* Create and initialize system-dependant method - this function issues its
      * own error messages */
     if( p_vout->p_sys_create( p_vout, psz_display, i_root_window, p_data ) )
@@ -950,10 +946,6 @@ static int InitThread( vout_thread_t *p_vout )
  *****************************************************************************/
 static void RunThread( vout_thread_t *p_vout)
 {
-    /* XXX?? welcome to gore land */
-    static int i_trash_count = 0;
-    static mtime_t last_display_date = 0;
-
     int             i_index;                                /* index in heap */
     mtime_t         current_date;                            /* current date */
     mtime_t         display_date;                            /* display date */
@@ -1005,12 +997,7 @@ static void RunThread( vout_thread_t *p_vout)
             /* Computes FPS rate */
             p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ] = display_date;
 #endif
-/* XXX?? */
-i_trash_count++;
-//fprintf( stderr, "gap : %Ld\n", display_date-last_display_date );
-last_display_date = display_date;
-#if 1
-            if( display_date < current_date && i_trash_count > 4 )
+            if( display_date < current_date )
             {
                 /* Picture is late: it will be destroyed and the thread
                  * will sleep and go to next picture */
@@ -1025,20 +1012,12 @@ last_display_date = display_date;
                     p_pic->i_status = DESTROYED_PICTURE;
                     p_vout->i_pictures--;
                 }
-                intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
+                intf_ErrMsg( "warning: late picture skipped (%p)\n", p_pic );
                 vlc_mutex_unlock( &p_vout->picture_lock );
 
-                /* Update synchronization information as if display delay
-                 * was 0 */
-                Synchronize( p_vout, display_date - current_date );
-
-                p_pic =         NULL;
-                display_date =  0;
-                i_trash_count = 0;
+               continue;
             }
-            else
-#endif
-                if( display_date > current_date + VOUT_DISPLAY_DELAY )
+            else if( display_date > current_date + VOUT_DISPLAY_DELAY )
             {
                 /* A picture is ready to be rendered, but its rendering date
                  * is far from the current one so the thread will perform an
@@ -1047,12 +1026,6 @@ last_display_date = display_date;
                 p_pic =         NULL;
                 display_date =  0;
             }
-            else
-            {
-                /* Picture will be displayed, update synchronization
-                 * information */
-                Synchronize( p_vout, display_date - current_date );
-            }
         }
         /*
          * Find the subpictures to display - this operation does not need
@@ -1070,11 +1043,9 @@ last_display_date = display_date;
             }
         }
 
-
         /*
          * Perform rendering, sleep and display rendered picture
          */
-        
         if( p_pic )                        /* picture and perhaps subpicture */
         {
             b_display = p_vout->b_active;
@@ -1173,18 +1144,28 @@ last_display_date = display_date;
          * Sleep, wake up and display rendered picture
          */
 
-#ifdef STATS
-        /* Store render time */
-        p_vout->render_time = mdate() - current_date;
-#endif
+        if( display_date != 0 )
+        {
+            /* Store render time */
+            p_vout->render_time += mdate() - current_date;
+            p_vout->render_time >>= 1;
+        }
 
         /* Give back change lock */
         vlc_mutex_unlock( &p_vout->change_lock );
 
+#ifdef DEBUG_VIDEO
+        {
+            char        psz_date[MSTRTIME_MAX_SIZE];
+            intf_DbgMsg( "picture %p waiting until %s\n", p_pic,
+                    mstrtime(psz_date, display_date),
+        }
+#endif
+
         /* Sleep a while or until a given date */
         if( display_date != 0 )
         {
-            mwait( display_date );
+            mwait( display_date - VOUT_MWAIT_TOLERANCE );
         }
         else
         {
@@ -1196,9 +1177,9 @@ last_display_date = display_date;
         vlc_mutex_lock( &p_vout->change_lock );
 #ifdef DEBUG_VIDEO
         intf_DbgMsg( "picture %p, subpicture %p in buffer %d, display=%d\n", p_pic, p_subpic,
-                     p_vout->i_buffer_index, b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) );
+                     p_vout->i_buffer_index, b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ );
 #endif
-        if( b_display && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) )
+        if( b_display /* && !(p_vout->i_changes & VOUT_NODISPLAY_CHANGE) */ )
         {
             p_vout->p_sys_display( p_vout );
 #ifndef SYS_BEOS
@@ -2017,81 +1998,6 @@ static void RenderInterface( vout_thread_t *p_vout )
     SetBufferArea( p_vout, 0, p_vout->i_height - i_height, p_vout->i_width, i_height );
 }
 
-/*****************************************************************************
- * Synchronize: update synchro level depending of heap state
- *****************************************************************************
- * This function is called during the main vout loop.
- *****************************************************************************/
-static void Synchronize( vout_thread_t *p_vout, s64 i_delay )
-{
-    int i_synchro_inc = 0;
-    /* XXX?? gore following */
-    static int i_panic_count = 0;
-    static int i_last_synchro_inc = 0;
-    static int i_synchro_level = VOUT_SYNCHRO_LEVEL_START;
-    static int i_truc = 10;
-
-    if( i_delay < 0 )
-    {
-        //fprintf( stderr, "PANIC %d\n", i_panic_count );
-        i_panic_count++;
-    }
-
-    i_truc *= 2;
-
-    if( p_vout->i_pictures > VOUT_SYNCHRO_HEAP_IDEAL_SIZE+1 )
-    {
-        i_truc = 40;
-        i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE - 1;
-
-    }
-    else
-    {
-        if( p_vout->i_pictures < VOUT_SYNCHRO_HEAP_IDEAL_SIZE )
-        {
-            i_truc = 32;
-            i_synchro_inc += p_vout->i_pictures - VOUT_SYNCHRO_HEAP_IDEAL_SIZE;
-        }
-    }
-
-    if( i_truc > VOUT_SYNCHRO_LEVEL_MAX >> 5 ||
-        i_synchro_inc*i_last_synchro_inc < 0 )
-    {
-        i_truc = 32;
-    }
-
-    if( i_delay < 6000 )
-    {
-        i_truc = 16;
-        i_synchro_inc -= 2;
-    }
-    else if( i_delay < 70000 )
-    {
-        i_truc = 24+(24*i_delay)/70000;
-        if( i_truc < 16 )
-            i_truc = 16;
-        i_synchro_inc -= 1+(5*(70000-i_delay))/70000;
-    }
-    else if( i_delay > 100000 )
-    {
-        i_synchro_level += 1 << 10;
-        if( i_delay > 130000 )
-            i_synchro_level += 1 << 10;
-    }
-
-    i_synchro_level += ( i_synchro_inc << 10 ) / i_truc;
-    p_vout->i_synchro_level = ( i_synchro_level + (1 << 9) );
-
-    if( i_synchro_level > VOUT_SYNCHRO_LEVEL_MAX )
-    {
-        i_synchro_level = VOUT_SYNCHRO_LEVEL_MAX;
-    }
-
-    //fprintf( stderr, "synchro level : %d, heap : %d (%d, %d) (%d, %f) - %Ld\n", p_vout->i_synchro_level,
-    //        p_vout->i_pictures, i_last_synchro_inc, i_synchro_inc, i_truc, r_synchro_level, i_delay );
-    i_last_synchro_inc = i_synchro_inc;
-}
-
 /*****************************************************************************
  * Manage: manage thread
  *****************************************************************************
@@ -2103,7 +2009,7 @@ static int Manage( vout_thread_t *p_vout )
     if( p_vout->i_changes )
     {
         intf_DbgMsg("changes: 0x%x (no display: 0x%x)\n", p_vout->i_changes,
-                    p_vout->i_changes & VOUT_NODISPLAY_CHANGE );
+                    0 /* p_vout->i_changes & VOUT_NODISPLAY_CHANGE */ );
     }
 #endif
 
index 0af739c..9b58880 100644 (file)
@@ -66,7 +66,6 @@ static int      InitThread          ( vpar_thread_t *p_vpar );
 static void     RunThread           ( vpar_thread_t *p_vpar );
 static void     ErrorThread         ( vpar_thread_t *p_vpar );
 static void     EndThread           ( vpar_thread_t *p_vpar );
-static int      SynchroType         ( );
 
 /*****************************************************************************
  * vpar_CreateThread: create a generic parser thread
@@ -78,7 +77,8 @@ static int      SynchroType         ( );
  *****************************************************************************/
 #include "main.h"
 #include "interface.h"
-extern main_t* p_main;
+extern main_t *     p_main;
+
 vpar_thread_t * vpar_CreateThread( /* video_cfg_t *p_cfg, */ input_thread_t *p_input /*,
                                    vout_thread_t *p_vout, int *pi_status */ )
 {
@@ -277,54 +277,7 @@ static int InitThread( vpar_thread_t *p_vpar )
     /*
      * Initialize the synchro properties
      */
-#ifdef SAM_SYNCHRO
-    /* Get an possible synchro algorithm */
-    p_vpar->synchro.i_type = SynchroType();
-
-    /* last seen PTS */
-    p_vpar->synchro.i_last_pts = 0;
-
-    /* for i frames */
-    p_vpar->synchro.i_last_seen_I_pts = 0;
-    p_vpar->synchro.i_last_kept_I_pts = 0;
-
-    /* the fifo */
-    p_vpar->synchro.i_start  = 0;
-    p_vpar->synchro.i_stop   = 0;
-
-    /* mean decoding time - at least 200 ms for a slow machine */
-    p_vpar->synchro.i_delay            = 200000;
-    p_vpar->synchro.i_theorical_delay  = 40000; /* 25 fps */
-    /* assume we can display all Is and 2 Ps */
-    p_vpar->synchro.b_all_I = 1 << 10;
-    p_vpar->synchro.b_all_P = 0;
-    p_vpar->synchro.displayable_p = 2 << 10;
-    p_vpar->synchro.b_all_B = 0;
-    p_vpar->synchro.displayable_b = 0;
-    p_vpar->synchro.b_dropped_last = 0;
-    /* assume there were about 3 P and 6 B images between I's */
-    p_vpar->synchro.i_P_seen = p_vpar->synchro.i_P_kept = 1 << 10;
-    p_vpar->synchro.i_B_seen = p_vpar->synchro.i_B_kept = 1 << 10;
-#endif
-
-#ifdef MEUUH_SYNCHRO
-    p_vpar->synchro.kludge_level = 5;
-    p_vpar->synchro.kludge_nbp = p_vpar->synchro.kludge_p = 5;
-    p_vpar->synchro.kludge_nbb = p_vpar->synchro.kludge_b = 6;
-    p_vpar->synchro.kludge_b = 0;
-    p_vpar->synchro.kludge_prevdate = 0;
-#endif
-
-#ifdef POLUX_SYNCHRO
-    p_vpar->synchro.i_current_frame_date = 0;
-    p_vpar->synchro.i_backward_frame_date = 0;
-
-    p_vpar->synchro.r_p_average = p_vpar->synchro.i_p_nb = 6;
-    p_vpar->synchro.r_b_average = p_vpar->synchro.i_b_nb = 6;
-    p_vpar->synchro.i_p_count = 0;
-    p_vpar->synchro.i_b_count = 0;
-    p_vpar->synchro.i_i_count = 0;
-#endif
+    vpar_SynchroInit( p_vpar );
 
     /* Mark thread as running and return */
     intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
@@ -476,61 +429,3 @@ static void EndThread( vpar_thread_t *p_vpar )
 
     intf_DbgMsg("vpar debug: EndThread(%p)\n", p_vpar);
 }
-
-/*****************************************************************************
- * SynchroType: Get the user's synchro type
- *****************************************************************************
- * This function is called at initialization.
- *****************************************************************************/
-static int SynchroType( )
-{
-    char * psz_synchro = main_GetPszVariable( VPAR_SYNCHRO_VAR, NULL );
-
-    if( psz_synchro == NULL )
-    {
-        return VPAR_SYNCHRO_DEFAULT;
-    }
-
-    switch( *psz_synchro++ )
-    {
-      case 'i':
-      case 'I':
-        switch( *psz_synchro++ )
-        {
-          case '\0':
-            return VPAR_SYNCHRO_I;
-
-          case '+':
-            if( *psz_synchro ) return 0;
-            return VPAR_SYNCHRO_Iplus;
-
-          case 'p':
-          case 'P':
-            switch( *psz_synchro++ )
-            {
-              case '\0':
-                return VPAR_SYNCHRO_IP;
-
-              case '+':
-                if( *psz_synchro ) return 0;
-                return VPAR_SYNCHRO_IPplus;
-
-              case 'b':
-              case 'B':
-                if( *psz_synchro ) return 0;
-                return VPAR_SYNCHRO_IPB;
-
-              default:
-                return VPAR_SYNCHRO_DEFAULT;
-                
-            }
-
-          default:
-            return VPAR_SYNCHRO_DEFAULT;
-        }
-    }
-
-    return VPAR_SYNCHRO_DEFAULT;
-
-}
-
index a9b06b2..daf0cd5 100644 (file)
@@ -3,9 +3,9 @@
  *****************************************************************************
  * Copyright (C) 1999, 2000 VideoLAN
  *
- * Authors: Samuel Hocevar <sam@via.ecp.fr>
- *          Jean-Marc Dressler <polu@via.ecp.fr>
- *          Christophe Massiot <massiot@via.ecp.fr>
+ * Authors: Christophe Massiot <massiot@via.ecp.fr>
+ *          Samuel Hocevar <sam@via.ecp.fr>
+ *          Jean-Marc Dressler <polux@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
+/*
+ * DISCUSSION : How to Write an efficient Frame-Dropping Algorithm
+ * ==========
+ *
+ * This implementation is based on mathematical and statistical
+ * developments. Older implementations used an enslavement, considering
+ * that if we're late when reading an I picture, we will decode one frame
+ * less. It had a tendancy to derive, and wasn't responsive enough, which
+ * would have caused trouble with the stream control stuff.
+ *
+ * 1. Structure of a picture stream
+ *    =============================
+ * Between 2 I's, we have for instance :
+ *    I   B   P   B   P   B   P   B   P   B   P   B   I
+ *    t0  t1  t2  t3  t4  t5  t6  t7  t8  t9  t10 t11 t12
+ * Please bear in mind that B's and IP's will be inverted when displaying
+ * (decoding order != presentation order). Thus, t1 < t0.
+ *
+ * 2. Definitions
+ *    ===========
+ * t[0..12]     : Presentation timestamps of pictures 0..12.
+ * t            : Current timestamp, at the moment of the decoding.
+ * T            : Picture period, T = 1/frame_rate.
+ * tau[I,P,B]   : Mean time to decode an [I,P,B] picture.
+ * tauYUV       : Mean time to render a picture (given by the video_output).
+ * tau´[I,P,B] = 2 * tau[I,P,B] + tauYUV
+ *              : Mean time + typical difference (estimated to tau, that
+ *                needs to be confirmed) + render time.
+ * DELTA        : A given error margin.
+ *
+ * 3. Decoding of an I picture
+ *    ========================
+ * On fast machines (ie. those who can decode all Is), we decode all I.
+ * Otherwise :
+ * We can decode an I picture if we simply have enough time to decode it 
+ * before displaying :
+ *      t0 - t > tau´I + DELTA
+ *
+ * 4. Decoding of a P picture
+ *    =======================
+ * On fast machines (ie. those who can decode all Ps), we decode all P.
+ * Otherwise :
+ * First criterion : have time to decode it.
+ *      t2 - t > tau´P + DELTA
+ *
+ * Second criterion : it shouldn't prevent us from decoding the forthcoming I
+ * picture, which is more important.
+ *      t12 - t > tau´P + tau´I + DELTA
+ *
+ * 5. Decoding of a B picture
+ *    =======================
+ * First criterion : have time to decode it.
+ *      t1 - t > tau´B + DELTA
+ *
+ * Second criterion : it shouldn't prevent us from decoding all P pictures
+ * until the next I, which are more important.
+ *      t4 - t > tau´B + tau´P + DELTA
+ *      [...]
+ *      t10 - t > tau´B + 4 * tau´P + DELTA
+ * It is possible to demonstrate that if the first and the last inequations
+ * are verified, the inequations in between will be verified too.
+ *
+ * Third criterion : it shouldn't prevent us from decoding the forthcoming I
+ * picture, which is more important.
+ *      t12 - t > tau´B + 4 * tau´P + tau´I + DELTA
+ *
+ * If STATS is defined, the counters in p_vpar->synchro will refer to the
+ * number of failures of these inequations.
+ *
+ * I hope you will have a pleasant flight and do not forget your life
+ * jacket.
+ *                                                  --Meuuh (2000-11-09)
+ */
+
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
 #include "vpar_synchro.h"
 #include "video_parser.h"
 
-#define MAX_COUNT 3
+#include "main.h"
 
 /*
  * Local prototypes
  */
+static int  SynchroType( void );
+static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type );
 
-#ifdef SAM_SYNCHRO
+/* Error margins */
+#define DELTA_I                 (int)(0.010*CLOCK_FREQ)
+#define DELTA_P                 (int)(0.010*CLOCK_FREQ)
+#define DELTA_B                 (int)(0.060*CLOCK_FREQ)
+
+#define DEFAULT_NB_P            5
+#define DEFAULT_NB_B            1
 
 /*****************************************************************************
- * vpar_SynchroUpdateStructures : Update the synchro structures
+ * vpar_SynchroInit : You know what ?
  *****************************************************************************/
-void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
-                                   int i_coding_type, boolean_t b_kept )
+void vpar_SynchroInit( vpar_thread_t * p_vpar )
 {
-    int             i_can_display;
-    mtime_t         i_pts;
-    pes_packet_t *  p_pes = p_vpar->bit_stream.p_decoder_fifo->buffer[
-                               p_vpar->bit_stream.p_decoder_fifo->i_start ];
-
-    /* try to guess the current DTS and PTS */
-    if( p_pes->b_has_pts )
-    {
-        i_pts = p_pes->i_pts;
-
-        /* if the image is I type, then the presentation timestamp is
-         * the PTS of the PES. Otherwise, we calculate it with the
-         * theorical framerate value */
-        if( i_coding_type == I_CODING_TYPE )
-        {
-            p_vpar->synchro.i_last_pts = p_pes->i_pts;
-        }
-        else
-        {
-            p_vpar->synchro.i_last_pts += p_vpar->synchro.i_theorical_delay;
-        }
-
-        p_pes->b_has_pts = 0;
-    }
-    else
-    {
-        p_vpar->synchro.i_last_pts += p_vpar->synchro.i_theorical_delay;
-        i_pts = p_vpar->synchro.i_last_pts;
-    }
-
-    /* update structures */
-    switch(i_coding_type)
-    {
-        case P_CODING_TYPE:
-
-            p_vpar->synchro.i_P_seen += 1024;
-            if( b_kept ) p_vpar->synchro.i_P_kept += 1024;
-            break;
-
-        case B_CODING_TYPE:
-            p_vpar->synchro.i_B_seen += 1024;
-            if( b_kept ) p_vpar->synchro.i_B_kept += 1024;
-            break;
-
-        case I_CODING_TYPE:
-
-            /* update the last I PTS we have, we need it to
-             * calculate the theorical framerate */
-            if (i_pts != p_vpar->synchro.i_last_seen_I_pts)
-            {
-                if ( p_vpar->synchro.i_last_seen_I_pts )
-                {
-                    p_vpar->synchro.i_theorical_delay =
-                      1024 * ( i_pts - p_vpar->synchro.i_last_seen_I_pts )
-                          / ( 1024 + p_vpar->synchro.i_B_seen
-                                + p_vpar->synchro.i_P_seen);
-                }
-                p_vpar->synchro.i_last_seen_I_pts = i_pts;
-            }
-
-            /* now we calculated all statistics, it's time to
-             * decide what we have the time to display */
-            i_can_display = 
-                ( (i_pts - p_vpar->synchro.i_last_kept_I_pts) << 10 )
-                                / p_vpar->synchro.i_delay;
-
-            p_vpar->synchro.b_all_I = 0;
-            p_vpar->synchro.b_all_B = 0;
-            p_vpar->synchro.b_all_P = 0;
-            p_vpar->synchro.displayable_p = 0;
-            p_vpar->synchro.displayable_b = 0;
-
-            if( ( p_vpar->synchro.b_all_I = ( i_can_display >= 1024 ) ) )
-            {
-                i_can_display -= 1024;
-
-                if( !( p_vpar->synchro.b_all_P
-                        = ( i_can_display > p_vpar->synchro.i_P_seen ) ) )
-                {
-                    p_vpar->synchro.displayable_p = i_can_display;
-                }
-                else
-                {
-                    i_can_display -= p_vpar->synchro.i_P_seen;
-
-                    if( !( p_vpar->synchro.b_all_B
-                            = ( i_can_display > p_vpar->synchro.i_B_seen ) ) )
-                    {
-                        p_vpar->synchro.displayable_b = i_can_display;
-                    }
-                }
-            }
-
-#if 0
-            if( p_vpar->synchro.b_all_I )
-                intf_ErrMsg( "  I: 1024/1024  " );
-
-            if( p_vpar->synchro.b_all_P )
-                intf_ErrMsg( "P: %i/%i  ", p_vpar->synchro.i_P_seen,
-                                           p_vpar->synchro.i_P_seen );
-            else if( p_vpar->synchro.displayable_p > 0 )
-                intf_ErrMsg( "P: %i/%i  ", p_vpar->synchro.displayable_p,
-                                             p_vpar->synchro.i_P_seen );
-            else
-                intf_ErrMsg( "                " );
-
-            if( p_vpar->synchro.b_all_B )
-                intf_ErrMsg( "B: %i/%i", p_vpar->synchro.i_B_seen,
-                                         p_vpar->synchro.i_B_seen );
-            else if( p_vpar->synchro.displayable_b > 0 )
-                intf_ErrMsg( "B: %i/%i", p_vpar->synchro.displayable_b,
-                                           p_vpar->synchro.i_B_seen );
-            else
-                intf_ErrMsg( "                " );
-
-            intf_ErrMsg( "\rDecoding: " );
-            /*intf_ErrMsg( "\n" );*/
-#endif
-            p_vpar->synchro.i_P_seen = 0;
-            p_vpar->synchro.i_B_seen = 0;
-
-            /* update some values */
-            if( b_kept )
-            {
-                p_vpar->synchro.i_last_kept_I_pts = i_pts;
-                p_vpar->synchro.i_P_kept = 0;
-                p_vpar->synchro.i_B_kept = 0;
-            }
-
-            break;
-    }
+    p_vpar->synchro.i_type = SynchroType();
+    p_vpar->synchro.i_start = p_vpar->synchro.i_end = 0;
+    vlc_mutex_init( &p_vpar->synchro.fifo_lock );
+
+    /* We use a fake stream pattern, which is often right. */
+    p_vpar->synchro.i_n_p = p_vpar->synchro.i_eta_p = DEFAULT_NB_P;
+    p_vpar->synchro.i_n_b = p_vpar->synchro.i_eta_b = DEFAULT_NB_B;
+    memset( p_vpar->synchro.p_tau, 0, 4 * sizeof(mtime_t) );
+    memset( p_vpar->synchro.pi_meaningful, 0, 4 * sizeof(unsigned int) );
+    p_vpar->synchro.b_dropped_last = 0;
+    p_vpar->synchro.current_pts = mdate() + INPUT_PTS_DELAY;
+    p_vpar->synchro.backward_pts = 0;
 }
 
 /*****************************************************************************
@@ -206,26 +168,22 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
 boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                               int i_structure )
 {
-    mtime_t i_delay = p_vpar->synchro.i_last_pts - mdate();
+    /* For clarity reasons, we separated the special synchros code from the
+     * mathematical synchro */
 
-    switch( i_coding_type )
+    if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
     {
+        switch( i_coding_type )
+        {
         case I_CODING_TYPE:
-
-            if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
+            /* I, IP, IP+, IPB */
+            if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus )
             {
-                /* I, IP, IP+, IPB */
-                if( p_vpar->synchro.i_type == VPAR_SYNCHRO_Iplus )
-                {
-                    p_vpar->synchro.b_dropped_last = 1;
-                }
-                return( 1 );
+                p_vpar->synchro.b_dropped_last = 1;
             }
-
-            return( p_vpar->synchro.b_all_I );
+            return( 1 );
 
         case P_CODING_TYPE:
-
             if( p_vpar->synchro.i_type == VPAR_SYNCHRO_I ) /* I */
             {
                 return( 0 );
@@ -244,71 +202,161 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                 }
             }
 
-            if( p_vpar->synchro.i_type >= VPAR_SYNCHRO_IP ) /* IP, IP+, IPB */
+            return( 1 ); /* IP, IP+, IPB */
+
+        case B_CODING_TYPE:
+            if( p_vpar->synchro.i_type <= VPAR_SYNCHRO_IP ) /* I, IP */
             {
-                return( 1 );
+                return( 0 );
             }
-
-            if( p_vpar->synchro.b_all_P )
+            else if( p_vpar->synchro.i_type == VPAR_SYNCHRO_IPB ) /* IPB */
             {
                 return( 1 );
             }
 
-            if( p_vpar->synchro.displayable_p * i_delay
-                < p_vpar->synchro.i_delay )
-            {
-                return( 0 );
-            }
+            p_vpar->synchro.b_dropped_last ^= 1; /* IP+ */
+            return( !p_vpar->synchro.b_dropped_last );
+        }
+        return( 0 ); /* never reached but gcc yells at me */
+    }
+    else
+    {
+#define TAU_PRIME( coding_type )    (p_vpar->synchro.p_tau[(coding_type)] \
+                                 + (p_vpar->synchro.p_tau[(coding_type)] >> 1) \
+                                            + tau_yuv)
+#define S                           p_vpar->synchro
+        /* VPAR_SYNCHRO_DEFAULT */
+        mtime_t         now, pts, period, tau_yuv;
+        boolean_t       b_decode = 0, b_decode2;
 
-            p_vpar->synchro.displayable_p -= 1024;
+        now = mdate();
+        period = 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
 
-            return( 1 );
+        //vlc_mutex_lock( &p_vpar->p_vout->change_lock );
+        tau_yuv = p_vpar->p_vout->render_time;
+        //vlc_mutex_unlock( &p_vpar->p_vout->change_lock );
 
-        case B_CODING_TYPE:
+        vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
 
-            if( p_vpar->synchro.i_type != VPAR_SYNCHRO_DEFAULT )
+        switch( i_coding_type )
+        {
+        case I_CODING_TYPE:
+            /* Stream structure changes */
+            S.i_n_p = S.i_eta_p || DEFAULT_NB_P;
+
+            if( S.backward_pts )
             {
-                if( p_vpar->synchro.i_type <= VPAR_SYNCHRO_IP ) /* I, IP */
-                {
-                    return( 0 );
-                }
-                else if( p_vpar->synchro.i_type == VPAR_SYNCHRO_IPB ) /* IPB */
-                {
-                    return( 1 );
-                }
+                pts = S.backward_pts;
+            }
+            else
+            {
+                pts = S.current_pts + period * S.i_n_b;
+            }
 
-                if( p_vpar->synchro.b_dropped_last ) /* IP+ */
-                {
-                    p_vpar->synchro.b_dropped_last = 0;
-                    return( 1 );
-                }
+            b_decode = ( (1 + S.i_n_p * (S.i_n_b + 1)) * period > 
+                           S.p_tau[I_CODING_TYPE] ) ||
+                       ( (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA_I) );
+            if( !b_decode )
+                intf_Msg("vpar synchro: trashing I\n");
+            break;
 
-                p_vpar->synchro.b_dropped_last = 1;
-                return( 0 );
-            }
+        case P_CODING_TYPE:
+            /* Stream structure changes */
+            S.i_n_b = S.i_eta_b || DEFAULT_NB_B;
+            if( S.i_eta_p + 1 > S.i_n_p )
+                S.i_n_p++;
 
-            if( p_vpar->synchro.b_all_B )
+            if( S.backward_pts )
             {
-                return( 1 );
+                pts = S.backward_pts;
             }
-
-            if( p_vpar->synchro.displayable_b <= 0 )
+            else
             {
-                return( 0 );
+                pts = S.current_pts + period * S.i_n_b;
             }
 
-            if( i_delay < 0 )
+            if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
             {
-                p_vpar->synchro.displayable_b -= 512;
-                return( 0 );
+                b_decode = (pts - now > 0);
+            }
+            else
+            {
+                b_decode = (pts - now) > (TAU_PRIME(P_CODING_TYPE) + DELTA_P);
+                /* next I */
+                b_decode &= (pts - now
+                              + period
+                          * ( (S.i_n_p - S.i_eta_p - 1) * (1 + S.i_n_b) - 1 ))
+                            > (TAU_PRIME(P_CODING_TYPE)
+                                + TAU_PRIME(I_CODING_TYPE) + DELTA_P);
             }
+            break;
 
-            p_vpar->synchro.displayable_b -= 1024;
-            return( 1 );
-    }
+        case B_CODING_TYPE:
+            /* Stream structure changes */
+            if( S.i_eta_b + 1 > S.i_n_b )
+                S.i_n_b++;
 
-    return( 0 );
+            pts = S.current_pts;
 
+            if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
+            {
+                b_decode = (pts - now) > (TAU_PRIME(B_CODING_TYPE) + DELTA_B);
+#ifdef STATS
+                S.i_B_self += !b_decode;
+#endif
+                /* Remember that S.i_eta_b is for the moment only eta_b - 1. */
+                if( S.i_eta_p != S.i_n_p ) /* next P */
+                {
+                    b_decode2 = (pts - now
+                                  + period
+                                  * ( 2 * S.i_n_b - S.i_eta_b - 1))
+                                    > (TAU_PRIME(B_CODING_TYPE)
+                                        + TAU_PRIME(P_CODING_TYPE) + DELTA_B);
+                    b_decode &= b_decode2;
+#ifdef STATS
+                    S.i_B_next += !b_decode2;
+#endif
+                }
+                if( S.i_eta_p < S.i_n_p - 1 ) /* last P */
+                {
+                    b_decode2 = (pts - now
+                                  + period
+                                  * ( (S.i_n_p - S.i_eta_p) * (1 + S.i_n_b)
+                                        + S.i_n_b - (S.i_eta_b + 1) + 1))
+                                    > (TAU_PRIME(B_CODING_TYPE)
+                                        + (S.i_n_p - S.i_eta_p)
+                                        * TAU_PRIME(P_CODING_TYPE)
+                                        + DELTA_B);
+                    b_decode &= b_decode2;
+#ifdef STATS
+                    S.i_B_last += !b_decode2;
+#endif
+                }
+                b_decode2 = (pts - now
+                              + period
+                              * ( (S.i_n_p - S.i_eta_p + 1) * (1 + S.i_n_b)
+                                        + S.i_n_b - (S.i_eta_b + 1) + 1 ))
+                                    > (TAU_PRIME(B_CODING_TYPE)
+                                        + (S.i_n_p - S.i_eta_p)
+                                        * TAU_PRIME(P_CODING_TYPE)
+                                        + TAU_PRIME(I_CODING_TYPE)
+                                        + DELTA_B);
+                b_decode &= b_decode2;
+#ifdef STATS
+                S.i_B_I += !b_decode2;
+#endif
+            }
+            else
+            {
+                b_decode = 0;
+            }
+        }
+
+        vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
+        return( b_decode );
+#undef S
+#undef TAU_PRIME
+    }
 }
 
 /*****************************************************************************
@@ -317,22 +365,33 @@ boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
 void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
                         int i_structure )
 {
-    vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 0);
-
+    SynchroNewPicture( p_vpar, i_coding_type );
 }
 
 /*****************************************************************************
  * vpar_SynchroDecode : Update timers when we decide to decode a picture
  *****************************************************************************/
 void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
-                            int i_structure )
+                         int i_structure )
 {
-    vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 1);
+    vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
 
-    p_vpar->synchro.i_date_fifo[p_vpar->synchro.i_stop] = mdate();
+    if( ((p_vpar->synchro.i_end + 1 - p_vpar->synchro.i_start)
+            % MAX_DECODING_PIC) )
+    {
+        p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_end] = mdate();
+        p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_end] = i_coding_type;
 
-    FIFO_INCREMENT( i_stop );
+        FIFO_INCREMENT( i_end );
+    }
+    else
+    {
+        /* FIFO full, panic() */
+        intf_ErrMsg("vpar error: synchro fifo full, estimations will be biased\n");
+    }
+    vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
 
+    SynchroNewPicture( p_vpar, i_coding_type );
 }
 
 /*****************************************************************************
@@ -340,29 +399,27 @@ void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
  *****************************************************************************/
 void vpar_SynchroEnd( vpar_thread_t * p_vpar )
 {
-    if( p_vpar->synchro.i_stop != p_vpar->synchro.i_start )
-    {
-        mtime_t i_delay;
+    mtime_t     tau;
+    int         i_coding_type;
 
-        i_delay = ( mdate() -
-            p_vpar->synchro.i_date_fifo[p_vpar->synchro.i_start] )
-              / ( (p_vpar->synchro.i_stop - p_vpar->synchro.i_start) & 0x0f );
+    vlc_mutex_lock( &p_vpar->synchro.fifo_lock );
 
-        p_vpar->synchro.i_delay =
-            ( 7 * p_vpar->synchro.i_delay + i_delay ) >> 3;
+    tau = mdate() - p_vpar->synchro.p_date_fifo[p_vpar->synchro.i_start];
+    i_coding_type = p_vpar->synchro.pi_coding_types[p_vpar->synchro.i_start];
 
-#if 0
-        intf_ErrMsg( "decode %lli (mean %lli, theorical %lli)\n",
-                     i_delay, p_vpar->synchro.i_delay,
-                     p_vpar->synchro.i_theorical_delay );
-#endif
-    }
-    else
+    /* Mean with average tau, to ensure stability. */
+    p_vpar->synchro.p_tau[i_coding_type] =
+        (p_vpar->synchro.pi_meaningful[i_coding_type]
+          * p_vpar->synchro.p_tau[i_coding_type] + tau)
+        / (p_vpar->synchro.pi_meaningful[i_coding_type] + 1);
+    if( p_vpar->synchro.pi_meaningful[i_coding_type] < MAX_PIC_AVERAGE )
     {
-        intf_ErrMsg( "vpar error: critical ! fifo full\n" );
+        p_vpar->synchro.pi_meaningful[i_coding_type]++;
     }
 
     FIFO_INCREMENT( i_start );
+
+    vlc_mutex_unlock( &p_vpar->synchro.fifo_lock );
 }
 
 /*****************************************************************************
@@ -370,174 +427,137 @@ void vpar_SynchroEnd( vpar_thread_t * p_vpar )
  *****************************************************************************/
 mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
 {
-#if 0
+    /* No need to lock, since PTS are only used by the video parser. */
+    return( p_vpar->synchro.current_pts );
+}
 
-    mtime_t i_displaydate = p_vpar->synchro.i_last_pts;
+/*****************************************************************************
+ * SynchroType: Get the user's synchro type
+ *****************************************************************************
+ * This function is called at initialization.
+ *****************************************************************************/
+static int SynchroType( void )
+{
+    char * psz_synchro = main_GetPszVariable( VPAR_SYNCHRO_VAR, NULL );
 
-    static mtime_t i_delta = 0;
+    if( psz_synchro == NULL )
+    {
+        return VPAR_SYNCHRO_DEFAULT;
+    }
 
-    intf_ErrMsg( "displaying image with delay %lli and delta %lli\n",
-        i_displaydate - mdate(),
-        i_displaydate - i_delta );
+    switch( *psz_synchro++ )
+    {
+      case 'i':
+      case 'I':
+        switch( *psz_synchro++ )
+        {
+          case '\0':
+            return VPAR_SYNCHRO_I;
 
-    intf_ErrMsg ( "theorical fps: %f - actual fps: %f \n",
-        1000000.0 / p_vpar->synchro.i_theorical_delay, 1000000.0 / p_vpar->synchro.i_delay );
+          case '+':
+            if( *psz_synchro ) return 0;
+            return VPAR_SYNCHRO_Iplus;
 
-    i_delta = i_displaydate;
+          case 'p':
+          case 'P':
+            switch( *psz_synchro++ )
+            {
+              case '\0':
+                return VPAR_SYNCHRO_IP;
 
-    return i_displaydate;
-#else
-    static s64 i_last_date = 0;
-//printf("%d: %lld\n", p_vpar->picture.i_coding_type, p_vpar->synchro.i_last_pts - i_last_date);
-//i_last_date = p_vpar->synchro.i_last_pts;
-    return p_vpar->synchro.i_last_pts;
+              case '+':
+                if( *psz_synchro ) return 0;
+                return VPAR_SYNCHRO_IPplus;
 
-#endif
-}
+              case 'b':
+              case 'B':
+                if( *psz_synchro ) return 0;
+                return VPAR_SYNCHRO_IPB;
 
-#endif
+              default:
+                return VPAR_SYNCHRO_DEFAULT;
+                
+            }
 
+          default:
+            return VPAR_SYNCHRO_DEFAULT;
+        }
+    }
 
-#ifdef POLUX_SYNCHRO
+    return VPAR_SYNCHRO_DEFAULT;
+}
 
-void vpar_SynchroSetCurrentDate( vpar_thread_t * p_vpar, int i_coding_type )
+/*****************************************************************************
+ * SynchroNewPicture: Update stream structure and PTS
+ *****************************************************************************/
+static void SynchroNewPicture( vpar_thread_t * p_vpar, int i_coding_type )
 {
-    pes_packet_t * p_pes =
-        p_vpar->bit_stream.p_decoder_fifo->buffer[p_vpar->bit_stream.p_decoder_fifo->i_start];
-
+    pes_packet_t * p_pes;
 
     switch( i_coding_type )
     {
+    case I_CODING_TYPE:
+        p_vpar->synchro.i_eta_p = p_vpar->synchro.i_eta_b = 0;
+#ifdef STATS
+        intf_Msg( "vpar synchro stats: I(%lld) P(%lld) B(%lld)[%d:%d:%d:%d] YUV(%lld)\n",
+                  p_vpar->synchro.p_tau[I_CODING_TYPE],
+                  p_vpar->synchro.p_tau[P_CODING_TYPE],
+                  p_vpar->synchro.p_tau[B_CODING_TYPE],
+                  p_vpar->synchro.i_B_self, p_vpar->synchro.i_B_next,
+                  p_vpar->synchro.i_B_last, p_vpar->synchro.i_B_I,
+                  p_vpar->p_vout->render_time );
+        p_vpar->synchro.i_B_self = p_vpar->synchro.i_B_next =
+            p_vpar->synchro.i_B_last = p_vpar->synchro.i_B_I = 0;
+#endif
+        break;
+    case P_CODING_TYPE:
+        p_vpar->synchro.i_eta_b = 0;
+        p_vpar->synchro.i_eta_p++;
+        break;
     case B_CODING_TYPE:
+        p_vpar->synchro.i_eta_b++;
+        break;
+    }
+
+    p_pes = DECODER_FIFO_START( *p_vpar->bit_stream.p_decoder_fifo );
+
+    if( i_coding_type == B_CODING_TYPE )
+    {
         if( p_pes->b_has_pts )
         {
-            if( p_pes->i_pts < p_vpar->synchro.i_current_frame_date )
+            if( p_pes->i_pts < p_vpar->synchro.current_pts )
             {
-                intf_ErrMsg( "vpar warning: pts_date < current_date\n" );
+                intf_ErrMsg("vpar warning: pts_date < current_date\n");
             }
-            p_vpar->synchro.i_current_frame_date = p_pes->i_pts;
+            p_vpar->synchro.current_pts = p_pes->i_pts;
             p_pes->b_has_pts = 0;
         }
         else
         {
-            p_vpar->synchro.i_current_frame_date += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
+            p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
         }
-        break;
-
-    default:
-
-        if( p_vpar->synchro.i_backward_frame_date == 0 )
+    }
+    else
+    {
+        if( p_vpar->synchro.backward_pts == 0 )
         {
-            p_vpar->synchro.i_current_frame_date += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
+            p_vpar->synchro.current_pts += 1000000 / (p_vpar->sequence.i_frame_rate) * 1001;
         }
         else
         {
-            if( p_vpar->synchro.i_backward_frame_date < p_vpar->synchro.i_current_frame_date )
+            if( p_vpar->synchro.backward_pts < p_vpar->synchro.current_pts )
             {
-                intf_ErrMsg( "vpar warning: backward_date < current_date (%Ld)\n",
-                         p_vpar->synchro.i_backward_frame_date - p_vpar->synchro.i_current_frame_date );
+                intf_ErrMsg("vpar warning: backward_date < current_date\n");
             }
-            p_vpar->synchro.i_current_frame_date = p_vpar->synchro.i_backward_frame_date;
-            p_vpar->synchro.i_backward_frame_date = 0;
+            p_vpar->synchro.current_pts = p_vpar->synchro.backward_pts;
+            p_vpar->synchro.backward_pts = 0;
         }
 
         if( p_pes->b_has_pts )
         {
-            p_vpar->synchro.i_backward_frame_date = p_pes->i_pts;
+            /* Store the PTS for the next time we have to date an I picture. */
+            p_vpar->synchro.backward_pts = p_pes->i_pts;
             p_pes->b_has_pts = 0;
         }
-       break;
-    }
-}
-
-boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
-                              int i_structure )
-{
-    boolean_t b_result = 1;
-    int i_synchro_level = p_vpar->p_vout->i_synchro_level;
-
-    vpar_SynchroSetCurrentDate( p_vpar, i_coding_type );
-
-    /*
-     * The synchro level is updated by the video input (see SynchroLevelUpdate)
-     * so we just use the synchro_level to decide which frame to trash
-     */
-
-    switch( i_coding_type )
-    {
-    case I_CODING_TYPE:
-
-        p_vpar->synchro.r_p_average =
-            (p_vpar->synchro.r_p_average*(SYNC_AVERAGE_COUNT-1)+p_vpar->synchro.i_p_count)/SYNC_AVERAGE_COUNT;
-        p_vpar->synchro.r_b_average =
-            (p_vpar->synchro.r_b_average*(SYNC_AVERAGE_COUNT-1)+p_vpar->synchro.i_b_count)/SYNC_AVERAGE_COUNT;
-
-        p_vpar->synchro.i_p_nb = (int)(p_vpar->synchro.r_p_average+0.5);
-        p_vpar->synchro.i_b_nb = (int)(p_vpar->synchro.r_b_average+0.5);
-
-        p_vpar->synchro.i_p_count = p_vpar->synchro.i_b_count = 0;
-        p_vpar->synchro.i_b_trasher = p_vpar->synchro.i_b_nb / 2;
-        p_vpar->synchro.i_i_count++;
-       break;
-
-    case P_CODING_TYPE:
-        p_vpar->synchro.i_p_count++;
-        if( p_vpar->synchro.i_p_count > i_synchro_level )
-        {
-            b_result = 0;
-        }
-        break;
-
-    case B_CODING_TYPE:
-        p_vpar->synchro.i_b_count++;
-        if( p_vpar->synchro.i_p_nb >= i_synchro_level )
-        {
-            /* We must trash all the B */
-            b_result = 0;
-        }
-        else
-        {
-            /* We use the brensenham algorithm to decide which B to trash */
-            p_vpar->synchro.i_b_trasher +=
-                p_vpar->synchro.i_b_nb - (i_synchro_level-p_vpar->synchro.i_p_nb);
-            if( p_vpar->synchro.i_b_trasher >= p_vpar->synchro.i_b_nb )
-            {
-                b_result = 0;
-                p_vpar->synchro.i_b_trasher -= p_vpar->synchro.i_b_nb;
-            }
-        }
-        break;
     }
-
-    return( b_result );
-}
-
-void vpar_SynchroTrash( vpar_thread_t * p_vpar, int i_coding_type,
-                        int i_structure )
-{
-    vpar_SynchroChoose( p_vpar, i_coding_type, i_structure );
-}
-
-void vpar_SynchroUpdateLevel()
-{
-    //vlc_mutex_lock( &level_lock );
-    //vlc_mutex_unlock( &level_lock );
 }
-
-mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
-{
-    return( p_vpar->synchro.i_current_frame_date );
-}
-
-/* functions with no use */
-
-void vpar_SynchroEnd( vpar_thread_t * p_vpar )
-{
-}
-
-void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
-                            int i_structure )
-{
-}
-
-#endif