]> git.sesse.net Git - vlc/blobdiff - src/video_parser/vpar_synchro.c
Am�lioration de la synchro.
[vlc] / src / video_parser / vpar_synchro.c
index e14e4707f8ee91fbddb9e7cf3c9cfadd12d37862..bca1d29f5dc06dfc78d91c63568b5001a56c9ecc 100644 (file)
@@ -12,8 +12,6 @@
 #include <unistd.h>
 #include <string.h>
 #include <sys/uio.h>
-#include <X11/Xlib.h>
-#include <X11/extensions/XShm.h>
 
 #include "config.h"
 #include "common.h"
@@ -35,9 +33,9 @@
 
 #include "vpar_blocks.h"
 #include "vpar_headers.h"
-#include "video_fifo.h"
 #include "vpar_synchro.h"
 #include "video_parser.h"
+#include "video_fifo.h"
 
 #define MAX_COUNT 3
 
 /*****************************************************************************
  * vpar_SynchroUpdateTab : Update a mean table in the synchro structure
  *****************************************************************************/
-double vpar_SynchroUpdateTab( video_synchro_tab_t * tab, int count )
+float vpar_SynchroUpdateTab( video_synchro_tab_t * tab, int count )
 {
-    if( tab->count < MAX_COUNT)
-        tab->count++;
-
-    tab->mean = ( (tab->count-1) * tab->mean + count )
-                    / tab->count;
-
-    tab->deviation = ( (tab->count-1) * tab->deviation
-                    + abs (tab->mean - count) ) / tab->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;
 }
@@ -66,28 +60,100 @@ double vpar_SynchroUpdateTab( video_synchro_tab_t * tab, int count )
  * vpar_SynchroUpdateStructures : Update the synchro structures
  *****************************************************************************/
 void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
-                                   int i_coding_type )
+                                   int i_coding_type, int dropped )
 {
-    double candidate_deviation;
-    double optimal_deviation;
-    double predict;
+    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, "  ");
+    }
+    
+    /* 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);
@@ -97,6 +163,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
                 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);
@@ -107,14 +174,18 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
             }
 
            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);
@@ -124,6 +195,7 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
                 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);
@@ -134,12 +206,67 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
             }
 
            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++;
+
 }
 
 /*****************************************************************************
@@ -148,9 +275,51 @@ void vpar_SynchroUpdateStructures( vpar_thread_t * p_vpar,
 boolean_t vpar_SynchroChoose( vpar_thread_t * p_vpar, int i_coding_type,
                               int i_structure )
 {
-//    return( 1 );
-//    return( i_coding_type == I_CODING_TYPE || i_coding_type == P_CODING_TYPE );
-    return( i_coding_type == I_CODING_TYPE );
+    mtime_t i_delay = p_vpar->synchro.i_last_decode_pts - mdate();
+
+    switch( i_coding_type )
+    {
+        case I_CODING_TYPE:
+
+            return( p_vpar->synchro.can_display_i );
+
+        case P_CODING_TYPE:
+
+            if( p_vpar->synchro.can_display_p )
+                return( 1 );
+
+            if( p_vpar->synchro.displayable_p * i_delay
+                < p_vpar->synchro.i_mean_decode_time )
+            {
+                //fprintf( stderr, "trashed a P\n");
+                return( 0 );
+            }
+
+            p_vpar->synchro.displayable_p--;
+            return( 1 );
+   
+        case B_CODING_TYPE:
+
+            if( p_vpar->synchro.can_display_b )
+                return( 1 );
+
+            /* modulo & 0x3 is here to add some randomness */
+            if( i_delay < (1 + (p_vpar->synchro.modulo & 0x3))
+                * p_vpar->synchro.i_mean_decode_time )
+            {
+                //fprintf( stderr, "trashed a B\n");
+                return( 0 );
+            }
+            if( p_vpar->synchro.displayable_b <= 0 )
+                return( 0 );
+
+            p_vpar->synchro.displayable_b--;
+            return( 1 );
+    }
+
+    return( 0 );
+
 }
 
 /*****************************************************************************
@@ -159,19 +328,24 @@ 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);
+    vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 1);
 
 }
 
 /*****************************************************************************
  * vpar_SynchroDecode : Update timers when we decide to decode a picture
  *****************************************************************************/
-mtime_t vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
+void vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
                             int i_structure )
 {
-    vpar_SynchroUpdateStructures (p_vpar, i_coding_type);
+    vpar_SynchroUpdateStructures (p_vpar, i_coding_type, 0);
+
+    p_vpar->synchro.fifo[p_vpar->synchro.i_fifo_stop].i_decode_date = mdate();
+    p_vpar->synchro.fifo[p_vpar->synchro.i_fifo_stop].i_image_type
+        = i_coding_type;
+
+    p_vpar->synchro.i_fifo_stop = (p_vpar->synchro.i_fifo_stop + 1) & 0xf;
 
-    return mdate() + 700000;
 }
 
 /*****************************************************************************
@@ -179,6 +353,46 @@ mtime_t vpar_SynchroDecode( vpar_thread_t * p_vpar, int i_coding_type,
  *****************************************************************************/
 void vpar_SynchroEnd( vpar_thread_t * p_vpar )
 {
+    mtime_t i_decode_time;
+
+    i_decode_time = (mdate() -
+            p_vpar->synchro.fifo[p_vpar->synchro.i_fifo_start].i_decode_date)
+        / (p_vpar->synchro.i_fifo_stop - p_vpar->synchro.i_fifo_start & 0x0f);
+
+    p_vpar->synchro.i_mean_decode_time =
+        ( 7 * p_vpar->synchro.i_mean_decode_time + i_decode_time ) / 8;
+
+    /* fprintf (stderr,
+        "decoding time was %lli\n",
+        p_vpar->synchro.i_mean_decode_time); */
+
+    p_vpar->synchro.i_fifo_start = (p_vpar->synchro.i_fifo_start + 1) & 0xf;
+
+}
+
+/*****************************************************************************
+ * vpar_SynchroDate : When an image has been decoded, ask for its date
+ *****************************************************************************/
+mtime_t vpar_SynchroDate( vpar_thread_t * p_vpar )
+{
+    mtime_t i_displaydate = p_vpar->synchro.i_last_display_pts;
+    
+#if 0
+    static mtime_t i_delta = 0;
+
+    fprintf( stderr,
+        "displaying type %i with delay %lli and delta %lli\n",
+        p_vpar->synchro.fifo[p_vpar->synchro.i_fifo_start].i_image_type,
+        i_displaydate - mdate(),
+        i_displaydate - i_delta );
+
+    fprintf (stderr,
+        "theorical fps: %f - actual fps: %f \n",
+        p_vpar->synchro.theorical_fps, p_vpar->synchro.actual_fps );
+
+    i_delta = i_displaydate;
+#endif
 
+    return i_displaydate;
 }