]> git.sesse.net Git - vlc/commitdiff
Corrections de quelques petits bugs et surtout nouvelle synchro qui ne semble
authorJean-Marc Dressler <polux@videolan.org>
Thu, 17 Feb 2000 00:43:58 +0000 (00:43 +0000)
committerJean-Marc Dressler <polux@videolan.org>
Thu, 17 Feb 2000 00:43:58 +0000 (00:43 +0000)
pas trop mal marcher sur ma machine mais qui j'en suis s�r ne marchera pas du
tout sur la votre.

A noter qu'il existe maintenant 3 synchros que l'on peut choisir en changeant
le define dans vpar_synchro.h (POLUX_SYNCHRO, SAM_SYNCHRO, MEUUH_SYNCHRO)

include/config.h
include/video_output.h
include/vpar_synchro.h
src/input/input.c
src/video_output/video_output.c
src/video_parser/video_parser.c
src/video_parser/vpar_blocks.c
src/video_parser/vpar_headers.c
src/video_parser/vpar_synchro.c

index d4db0df0990fe5a111a9c81068c3555e04341241..f306145a6bf176075c0bb0896309e6b663d0600e 100644 (file)
 
 /* 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
+#define VOUT_SYNCHRO_LEVEL_MAX          15
+#define VOUT_SYNCHRO_HEAP_IDEAL_SIZE    5
index d054908d8d4043d78c2317c8cb03f58e125ec798..00b2ca0e2dfc09d359fda6a3aafe00bca300b37f 100644 (file)
@@ -159,22 +159,26 @@ typedef struct vout_thread_s
      * 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 */
+    mtime_t             p_fps_sample[VOUT_FPS_SAMPLES]; /* FPS samples dates */
 #endif
 
     /* Rendering buffers */
     int                 i_buffer_index;                      /* buffer index */
     vout_buffer_t       p_buffer[2];                   /* buffers properties */
 
-    /* Videos heap and translation tables */
+    /* Videos heap and translation tables */    
     picture_t           p_picture[VOUT_MAX_PICTURES];            /* pictures */
     subpicture_t        p_subpicture[VOUT_MAX_PICTURES];      /* subpictures */
+    int                 i_pictures;                     /* current heap size */
     vout_yuv_t          yuv;                           /* translation tables */
 
     /* Bitmap fonts */
     p_vout_font_t       p_default_font;                      /* default font */
     p_vout_font_t       p_large_font;                          /* large font */
 
+    /* Synchronisation informations - synchro level is updated by the vout
+     * thread and read by decoder threads */
+    int                 i_synchro_level;                   /* trashing level */    
 } vout_thread_t;
 
 /* Output methods */
index 7a0eae41848b329ca9bfeb5b7892ea93600af072..bde125bfc70e2c43884d0ec9cc6ddecc8e2d65b9 100644 (file)
@@ -15,7 +15,7 @@
  *  "video_fifo.h"
  *****************************************************************************/
 
-#define SAM_SYNCHRO
+#define POLUX_SYNCHRO
 
 /*****************************************************************************
  * video_synchro_t and video_synchro_tab_s : timers for the video synchro
@@ -80,7 +80,9 @@ typedef struct video_synchro_s
     double actual_fps;
 
 } video_synchro_t;
-#else
+#endif
+
+#ifdef MEUUH_SYNCHRO
 typedef struct video_synchro_s
 {
     int         kludge_level, kludge_p, kludge_b, kludge_nbp, kludge_nbb;
@@ -93,6 +95,27 @@ typedef struct video_synchro_s
 #define SYNC_DELAY      500000
 #endif
 
+#ifdef POLUX_SYNCHRO
+
+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.r_frame_rate) */
+    mtime_t     i_current_frame_date;
+    mtime_t     i_backward_frame_date;
+
+    /* Frame Trashing Section */
+    
+    int         i_b_nb, i_p_nb;   /* number of decoded P and B between two I */
+    int         i_b_count, i_p_count, i_i_count;
+    int         i_b_trasher;                /* used for brensenham algorithm */
+    
+} video_synchro_t;
+
+#endif
+
 /*****************************************************************************
  * Prototypes
  *****************************************************************************/
index 54a2ab6b71fcf3af23901e6381f5b94aff2c466c..615bbc4f960769435a7e92fd0661577f6054cc9d 100644 (file)
@@ -893,11 +893,12 @@ static __inline__ void input_DemuxPES( input_thread_t *p_input,
             /* This part of the header does not fit in the current TS packet:
                copy the part of the header we are interested in to the
                p_pes_header_save buffer. The buffer is dynamicly allocated if
-              needed so it's time expensive but this situation almost never
-              occur. */
+               needed so it's time expensive but this situation almost never occur. */
             intf_DbgMsg("Code never tested encountered, WARNING ! (benny)\n");
-           if( !p_pes->p_pes_header_save )
-               p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE);
+            if( !p_pes->p_pes_header_save )
+            {
+                p_pes->p_pes_header_save = malloc(PES_HEADER_SIZE); 
+            }
 
             do
             {
index c82a0fd4ba7bbc270ed3f3f13ae920e66540c477..679ca814acfae5f15165d54bc8b9e379d42cecf8 100644 (file)
@@ -50,6 +50,7 @@ static void     RenderSubPicture  ( vout_thread_t *p_vout,
 static void     RenderInterface   ( vout_thread_t *p_vout );
 static int      RenderIdle        ( 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,
@@ -210,6 +211,10 @@ vout_thread_t * vout_CreateThread   ( char *psz_display, int i_root_window,
         p_vout->p_subpicture[i_index].i_type  = EMPTY_SUBPICTURE;
         p_vout->p_subpicture[i_index].i_status= FREE_SUBPICTURE;
     }
+    p_vout->i_pictures = 0;    
+
+    /* Initialize synchronization informations */
+    p_vout->i_synchro_level     = VOUT_SYNCHRO_LEVEL_START;
 
     /* Create and initialize system-dependant method - this function issues its
      * own error messages */
@@ -599,6 +604,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
                  * can end immediately - this is the best possible case, since no
                  * memory allocation needs to be done */
                 p_vout->p_picture[i_picture].i_status = RESERVED_PICTURE;
+                p_vout->i_pictures++;                
 #ifdef DEBUG_VIDEO
                 intf_DbgMsg("picture %p (in destroyed picture slot)\n",
                             &p_vout->p_picture[i_picture] );
@@ -682,6 +688,7 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
             p_free_picture->i_display_height            = i_height;
             p_free_picture->i_aspect_ratio              = AR_SQUARE_PICTURE;
             p_free_picture->i_refcount                  = 0;
+            p_vout->i_pictures++;            
         }
         else
         {
@@ -711,11 +718,11 @@ picture_t *vout_CreatePicture( vout_thread_t *p_vout, int i_type,
  * This function frees a previously reserved picture or a permanent
  * picture. It is meant to be used when the construction of a picture aborted.
  * Note that the picture will be destroyed even if it is linked !
- * This function does not need locking since reserved pictures are ignored by
- * the output thread.
  *****************************************************************************/
 void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
 {
+   vlc_mutex_lock( &p_vout->picture_lock );   
+
 #ifdef DEBUG
    /* Check if picture status is valid */
    if( (p_pic->i_status != RESERVED_PICTURE) &&
@@ -726,11 +733,13 @@ void vout_DestroyPicture( vout_thread_t *p_vout, picture_t *p_pic )
    }
 #endif
 
-    p_pic->i_status = DESTROYED_PICTURE;
+   p_pic->i_status = DESTROYED_PICTURE;
+   p_vout->i_pictures--;    
 
 #ifdef DEBUG_VIDEO
-    intf_DbgMsg("picture %p\n", p_pic);
+   intf_DbgMsg("picture %p\n", p_pic);
 #endif
+   vlc_mutex_unlock( &p_vout->picture_lock );   
 }
 
 /*****************************************************************************
@@ -772,6 +781,7 @@ void vout_UnlinkPicture( vout_thread_t *p_vout, picture_t *p_pic )
     if( (p_pic->i_refcount == 0) && (p_pic->i_status == DISPLAYED_PICTURE) )
     {
         p_pic->i_status = DESTROYED_PICTURE;
+        p_vout->i_pictures--;        
     }
 
 #ifdef DEBUG_VIDEO
@@ -981,18 +991,35 @@ 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
+#if 0
             if( display_date < current_date )
             {
                 /* Picture is late: it will be destroyed and the thread will sleep and
                  * go to next picture */
+
                 vlc_mutex_lock( &p_vout->picture_lock );
-                p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
-            intf_DbgMsg( "warning: late picture %p skipped refcount=%d\n", p_pic, p_pic->i_refcount );
+                if( p_pic->i_refcount )
+                {
+                    p_pic->i_status = DISPLAYED_PICTURE;                    
+                }
+                else
+                {
+                    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 );
                 vlc_mutex_unlock( &p_vout->picture_lock );
+
                 p_pic =         NULL;
                 display_date =  0;
+
+                /* Update synchronization information as if display delay 
+                 * was 0 */
+                Synchronize( p_vout, 0 );                
             }
-            else if( display_date > current_date + VOUT_DISPLAY_DELAY )
+            else 
+#endif                
+                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 empty loop
@@ -1000,6 +1027,12 @@ static void RunThread( vout_thread_t *p_vout)
                 p_pic =         NULL;
                 display_date =  0;
             }
+            else
+            {
+                /* Picture will be displayed, update synchronization 
+                 * information */
+                Synchronize( p_vout, display_date - current_date );
+            }            
         }
 
         /*
@@ -1033,7 +1066,15 @@ static void RunThread( vout_thread_t *p_vout)
 
             /* Remove picture from heap */
             vlc_mutex_lock( &p_vout->picture_lock );
-            p_pic->i_status = p_pic->i_refcount ? DISPLAYED_PICTURE : DESTROYED_PICTURE;
+            if( p_pic->i_refcount )
+            {
+                p_pic->i_status = DISPLAYED_PICTURE;                    
+            }
+            else
+            {
+                p_pic->i_status = DESTROYED_PICTURE;
+                p_vout->i_pictures--;                    
+            }
             vlc_mutex_unlock( &p_vout->picture_lock );
 
             /* Render interface and subpicture */
@@ -1767,8 +1808,8 @@ static void RenderInfo( vout_thread_t *p_vout )
             break;
         }
     }
-    sprintf( psz_buffer, "pic: %d/%d/%d",
-             i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
+    sprintf( psz_buffer, "pic: %d (%d/%d)/%d",
+             p_vout->i_pictures, i_reserved_pic, i_ready_pic, VOUT_MAX_PICTURES );
     Print( p_vout, 0, 0, LEFT_RALIGN, BOTTOM_RALIGN, psz_buffer );
 #endif
 }
@@ -1865,6 +1906,76 @@ 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;
+    //???? gore following
+    static int i_panic_count = 0;
+    static int i_last_synchro_inc = 0;
+    static float r_synchro_level = VOUT_SYNCHRO_LEVEL_START;
+    static int i_truc = 1;
+
+    //?? heap size is p_vout->i_pictures
+    //?? 
+    if( i_delay < 0 )
+    {
+//        intf_Msg("PANIC %d\n", i_panic_count++);
+    }
+/*
+    if( p_vout->i_pictures > VOUT_SYNCHRO_HEAP_IDEAL_SIZE+1 )
+    {
+        i_synchro_inc++;
+    }
+    else if( p_vout->i_pictures < VOUT_SYNCHRO_HEAP_IDEAL_SIZE )
+    {
+        i_synchro_inc--;
+    }
+*/    
+    if( i_delay < 10000 )
+    {
+        i_truc = 4;
+    }
+    
+    if( i_delay < 20000 )
+    {
+        i_synchro_inc--;
+    }   
+    else if( i_delay > 50000 )
+    {
+        i_synchro_inc++;
+    }
+    
+    if( i_synchro_inc*i_last_synchro_inc < 0 )
+    {
+        i_truc = 2;
+    }
+    else
+    {
+        i_truc *= 2;
+    }
+    if( i_truc > VOUT_SYNCHRO_LEVEL_MAX || i_delay == 0 )
+    {
+        i_truc = 2;
+    }
+    
+    r_synchro_level += (float)i_synchro_inc / i_truc;
+    p_vout->i_synchro_level = (int) r_synchro_level;
+    
+    if( r_synchro_level > VOUT_SYNCHRO_LEVEL_MAX )
+    {
+        r_synchro_level = VOUT_SYNCHRO_LEVEL_MAX;
+    }
+
+//    printf( "synchro level : %d, (%d, %d) (%d, %f) - %Ld\n", p_vout->i_synchro_level,
+//            i_last_synchro_inc, i_synchro_inc, i_truc, r_synchro_level, i_delay );    
+    i_last_synchro_inc = i_synchro_inc;    
+}
+
 /*****************************************************************************
  * Manage: manage thread
  *****************************************************************************
index 1bc525264cdb954a6f4e39918f4805ab295c43fa..898de5c8324c4984c9fd610ffd2f81beb756ac65 100644 (file)
@@ -292,7 +292,9 @@ static int InitThread( vpar_thread_t *p_vpar )
         p_vpar->synchro.tab_b[i_dummy].mean = 6;
         p_vpar->synchro.tab_b[i_dummy].deviation = .5;
     }
-#else
+#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;
@@ -300,6 +302,17 @@ static int InitThread( vpar_thread_t *p_vpar )
     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.i_p_nb = 5;
+    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
+    
     /* Mark thread as running and return */
     intf_DbgMsg("vpar debug: InitThread(%p) succeeded\n", p_vpar);
     return( 0 );
index 70e13d35427c87faf687f13ed920e1afa8354507..395efb834376d7a121de1037618ffa06211045df 100644 (file)
 #include "video_parser.h"
 #include "video_fifo.h"
 
+
+
+
+
+
+
+static int i_count = 0;
+
+
+
+
+
+
 /*
  * Welcome to vpar_blocks.c ! Here's where the heavy processor-critical parsing
  * task is done. This file is divided in several parts :
@@ -530,9 +543,11 @@ void vpar_InitDCTTables( vpar_thread_t * p_vpar )
     p_vpar->pppl_dct_dc_size[1][0] = pl_dct_dc_chrom_init_table_1;
     p_vpar->pppl_dct_dc_size[1][1] = pl_dct_dc_chrom_init_table_2;
 
-    memset( p_vpar->ppl_dct_coef[0], MB_ERROR, 16 );
-    memset( p_vpar->ppl_dct_coef[1], MB_ERROR, 16 );
-
+    /* ??? MB_ERROR is replaced by 0 because if we use -1 we 
+     * can block in DecodeMPEG2Intra and others */
+    memset( p_vpar->ppl_dct_coef[0], 0, 16 );
+    memset( p_vpar->ppl_dct_coef[1], 0, 16 );
+    
     /* For table B14 & B15, we have a pointer to tables */
     /* We fill the table thanks to the fonction defined above */
     FillDCTTable( p_vpar->ppl_dct_coef[0], pl_DCT_tab0, 256, 60,  4 );
@@ -1614,14 +1629,24 @@ static __inline__ void ParseMacroblock(
     static int      pi_x[12] = {0,8,0,8,0,0,0,0,8,8,8,8};
     static int      pi_y[2][12] = { {0,0,8,8,0,0,8,8,0,0,8,8},
                                     {0,0,1,1,0,0,1,1,0,0,1,1} };
-
     int             i_mb, i_b, i_mask;
+    int i_inc;
     macroblock_t *  p_mb;
     yuv_data_t *    p_data1;
     yuv_data_t *    p_data2;
 
-    *pi_mb_address += MacroblockAddressIncrement( p_vpar );
+i_count++;
 
+    i_inc = MacroblockAddressIncrement( p_vpar );
+    *pi_mb_address += i_inc;
+
+    if( i_inc < 0 )
+    {
+        fprintf( stderr, "vpar error: bad address increment (%d)\n", i_inc );
+        p_vpar->picture.b_error = 1;
+        return;
+    }
+    
     if( *pi_mb_address - i_mb_previous - 1 )
     {
         /* Skipped macroblock (ISO/IEC 13818-2 7.6.6). */
@@ -1833,9 +1858,16 @@ static __inline__ void SliceHeader( vpar_thread_t * p_vpar,
         {
             RemoveBits( &p_vpar->bit_stream, 8 );
         }
-    }
+    }    
     *pi_mb_address = (i_vert_code - 1)*p_vpar->sequence.i_mb_width;
 
+    if( *pi_mb_address < i_mb_address_save )
+    {
+        fprintf( stderr, "vpar error: slices do not follow, maybe a PES has been trashed\n" );
+        p_vpar->picture.b_error = 1;
+        return;
+    }
+
     /* Reset DC coefficients predictors (ISO/IEC 13818-2 7.2.1). */
     p_vpar->mb.pi_dc_dct_pred[0] = p_vpar->mb.pi_dc_dct_pred[1]
         = p_vpar->mb.pi_dc_dct_pred[2]
@@ -1851,9 +1883,12 @@ static __inline__ void SliceHeader( vpar_thread_t * p_vpar,
                          i_chroma_format, i_structure,
                          b_second_field );
         i_mb_address_save = *pi_mb_address;
+        if( p_vpar->picture.b_error )
+        {
+            return;
+        }
     }
-    while( ShowBits( &p_vpar->bit_stream, 23 ) && !p_vpar->picture.b_error
-            && !p_vpar->b_die );
+    while( ShowBits( &p_vpar->bit_stream, 23 ) && !p_vpar->b_die );
     NextStartCode( p_vpar );
 }
 
index 78fee08e7bec2b9a80cd3250d5b40c541bcec701..b2c61e74ea4a3ee2f18c059274027220d9b65266 100644 (file)
@@ -156,10 +156,15 @@ static void __inline__ ReferenceUpdate( vpar_thread_t * p_vpar,
             vout_UnlinkPicture( p_vpar->p_vout, p_vpar->sequence.p_forward );
         if( p_vpar->sequence.p_backward != NULL )
         {
+#ifdef POLUX_SYNCHRO
+            vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
+                              vpar_SynchroDate( p_vpar ) );
+#endif
 #ifdef SAM_SYNCHRO
             vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
                               vpar_SynchroDate( p_vpar ) );
-#else
+#endif
+#ifdef MEUUH_SYNCHRO
             mtime_t     date;
             date = vpar_SynchroDate( p_vpar );
             vout_DatePicture( p_vpar->p_vout, p_vpar->sequence.p_backward,
@@ -172,15 +177,14 @@ static void __inline__ ReferenceUpdate( vpar_thread_t * p_vpar,
         p_vpar->sequence.p_backward = p_newref;
         if( p_newref != NULL )
             vout_LinkPicture( p_vpar->p_vout, p_newref );
-#ifndef SAM_SYNCHRO
+#ifdef MEUUH_SYNCHRO
         p_vpar->synchro.i_coding_type = i_coding_type;
 #endif
     }
     else if( p_newref != NULL )
     {
         /* Put date immediately. */
-        vout_DatePicture( p_vpar->p_vout, p_newref,
-                          vpar_SynchroDate( p_vpar ) );
+        vout_DatePicture( p_vpar->p_vout, p_newref, vpar_SynchroDate(p_vpar) );
     }
 }
 
@@ -525,7 +529,7 @@ static void PictureHeader( vpar_thread_t * p_vpar )
     RemoveBits( &p_vpar->bit_stream, 10 ); /* temporal_reference */
     p_vpar->picture.i_coding_type = GetBits( &p_vpar->bit_stream, 3 );
     RemoveBits( &p_vpar->bit_stream, 16 ); /* vbv_delay */
-
+    
     if( p_vpar->picture.i_coding_type == P_CODING_TYPE
         || p_vpar->picture.i_coding_type == B_CODING_TYPE )
     {
@@ -646,15 +650,21 @@ static void PictureHeader( vpar_thread_t * p_vpar )
                                p_vpar->picture.i_coding_type, i_structure );
         }
     }
-
+#ifdef POLUX_SYNCHRO
+    else if( !p_vpar->picture.i_current_structure )
+    {
+        vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure );
+    }
+#endif
+    
     if( !b_parsable )
     {
         /* Update the reference pointers. */
         ReferenceUpdate( p_vpar, p_vpar->picture.i_coding_type, NULL );
-
+#ifndef POLUX_SYNCHRO
         /* Warn Synchro we have trashed a picture. */
         vpar_SynchroTrash( p_vpar, p_vpar->picture.i_coding_type, i_structure );
-
+#endif
         /* Update context. */
         if( i_structure != FRAME_STRUCTURE )
             p_vpar->picture.i_current_structure = i_structure;
index 55aa5d7cb84a20424a8c2aae2675cf3e9546090d..05c6758e367ee1feaa86f5b09638a937728209c5 100644 (file)
@@ -399,7 +399,9 @@ mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
     return i_displaydate;
 }
 
-#else
+#endif
+
+#ifdef MEUUH_SYNCHRO
 
 /* synchro a deux balles backportee du decodeur de reference. NE MARCHE PAS
 AVEC LES IMAGES MONOTRAMES */
@@ -516,3 +518,145 @@ void vpar_SynchroKludge( vpar_thread_t * p_vpar, mtime_t date )
 }
 
 #endif
+
+
+#ifdef POLUX_SYNCHRO
+
+void vpar_SynchroSetCurrentDate( 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]; 
+
+    
+    switch( i_coding_type )
+    {
+    case B_CODING_TYPE:
+        if( p_pes->b_has_pts )
+        {
+            if( p_pes->i_pts < p_vpar->synchro.i_current_frame_date )
+            {
+                fprintf( stderr, "vpar warning: pts_date < current_date\n" );
+            }
+            p_vpar->synchro.i_current_frame_date = p_pes->i_pts;
+            p_pes->b_has_pts = 0;
+        }
+        else
+        {
+            p_vpar->synchro.i_current_frame_date += 1000000/(1+p_vpar->sequence.r_frame_rate);
+        }
+        break;
+        
+    default:
+
+        if( p_vpar->synchro.i_backward_frame_date == 0 )
+        {
+            p_vpar->synchro.i_current_frame_date += 1000000/(1+p_vpar->sequence.r_frame_rate);
+        }
+        else
+        {
+            if( p_vpar->synchro.i_backward_frame_date < p_vpar->synchro.i_current_frame_date )
+            {
+                fprintf( stderr, "vpar warning: backward_date < current_date (%Ld)\n",
+                         p_vpar->synchro.i_backward_frame_date - p_vpar->synchro.i_current_frame_date );
+            }
+            p_vpar->synchro.i_current_frame_date = p_vpar->synchro.i_backward_frame_date;
+            p_vpar->synchro.i_backward_frame_date = 0;
+        }
+
+        if( p_pes->b_has_pts )
+        {
+            p_vpar->synchro.i_backward_frame_date = 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:
+       if( p_vpar->synchro.i_i_count != 0 )
+        {
+            p_vpar->synchro.i_p_nb = p_vpar->synchro.i_p_count;
+            p_vpar->synchro.i_b_nb = p_vpar->synchro.i_b_count;
+        }
+        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 )
+{
+//fprintf( stderr, "delay : %Ld\n" , mdate() - p_vpar->synchro.i_current_frame_date );
+    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