[vlc-devel] commit: Automatically compute the latency(pts_delay) needed after a buffer underflow. (Laurent Aimar )

git version control git at videolan.org
Fri Oct 23 23:14:52 CEST 2009


vlc | branch: 1.0-bugfix | Laurent Aimar <fenrir at videolan.org> | Mon Jul 13 21:04:44 2009 +0200| [a96be7b6ab8d870081b786705355edaaf6a2e039] | committer: Laurent Aimar 

Automatically compute the latency(pts_delay) needed after a buffer underflow.

The latency is increased by monitoring the last buffer underflows and by
filtering the values obtained (median 3).
It is simple and pretty robust (tested with http and sshfs over wireless).
(cherry picked from commit dc5be23723fea2b03d3ae9cb5534c4513aa9b6fb)

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a96be7b6ab8d870081b786705355edaaf6a2e039
---

 src/input/clock.c  |   52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/input/clock.h  |    6 ++++++
 src/input/es_out.c |   16 ++++++++++++++--
 3 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/src/input/clock.c b/src/input/clock.c
index 9cad368..6c0e327 100644
--- a/src/input/clock.c
+++ b/src/input/clock.c
@@ -123,6 +123,9 @@ static inline clock_point_t clock_point_Create( mtime_t i_stream, mtime_t i_syst
 }
 
 /* */
+#define INPUT_CLOCK_LATE_COUNT (3)
+
+/* */
 struct input_clock_t
 {
     /* */
@@ -143,6 +146,13 @@ struct input_clock_t
     mtime_t i_next_drift_update;
     average_t drift;
 
+    /* Late statistics */
+    struct
+    {
+        mtime_t  pi_value[INPUT_CLOCK_LATE_COUNT];
+        unsigned i_index;
+    } late;
+
     /* Current modifiers */
     int     i_rate;
     mtime_t i_pts_delay;
@@ -173,6 +183,10 @@ input_clock_t *input_clock_New( int i_rate )
     cl->i_next_drift_update = VLC_TS_INVALID;
     AvgInit( &cl->drift, 10 );
 
+    cl->late.i_index = 0;
+    for( int i = 0; i < INPUT_CLOCK_LATE_COUNT; i++ )
+        cl->late.pi_value[i] = 0;
+
     cl->i_rate = i_rate;
     cl->i_pts_delay = 0;
     cl->b_paused = false;
@@ -251,7 +265,13 @@ void input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
     /* It does not take the decoder latency into account but it is not really
      * the goal of the clock here */
     const mtime_t i_system_expected = ClockStreamToSystem( cl, i_ck_stream + AvgGet( &cl->drift ) );
-    *pb_late = i_system_expected < i_ck_system - cl->i_pts_delay;
+    const mtime_t i_late = ( i_ck_system - cl->i_pts_delay ) - i_system_expected;
+    *pb_late = i_late > 0;
+    if( i_late > 0 )
+    {
+        cl->late.pi_value[cl->late.i_index] = i_late;
+        cl->late.i_index = ( cl->late.i_index + 1 ) % INPUT_CLOCK_LATE_COUNT;
+    }
 
     vlc_mutex_unlock( &cl->lock );
 }
@@ -437,6 +457,14 @@ void input_clock_SetJitter( input_clock_t *cl,
 {
     vlc_mutex_lock( &cl->lock );
 
+    /* Update late observations */
+    const mtime_t i_delay_delta = i_pts_delay - cl->i_pts_delay;
+    for( int i = 0; i < INPUT_CLOCK_LATE_COUNT; i++ )
+    {
+        if( cl->late.pi_value[i] > 0 )
+            cl->late.pi_value[i] = __MAX( cl->late.pi_value[i] - i_delay_delta, 0 );
+    }
+
     /* TODO always save the value, and when rebuffering use the new one if smaller
      * TODO when increasing -> force rebuffering
      */
@@ -453,6 +481,28 @@ void input_clock_SetJitter( input_clock_t *cl,
     vlc_mutex_unlock( &cl->lock );
 }
 
+mtime_t input_clock_GetJitter( input_clock_t *cl )
+{
+    vlc_mutex_lock( &cl->lock );
+
+#if INPUT_CLOCK_LATE_COUNT != 3
+#   error "unsupported INPUT_CLOCK_LATE_COUNT"
+#endif
+    /* Find the median of the last late values
+     * It works pretty well at rejecting bad values
+     *
+     * XXX we only increase pts_delay over time, decreasing it is
+     * not that easy if we want to be robust.
+     */
+    const mtime_t *p = cl->late.pi_value;
+    mtime_t i_late_median = p[0] + p[1] + p[2] - __MIN(__MIN(p[0],p[1]),p[2]) - __MAX(__MAX(p[0],p[1]),p[2]);
+    mtime_t i_pts_delay = cl->i_pts_delay ;
+
+    vlc_mutex_unlock( &cl->lock );
+
+    return i_pts_delay + i_late_median;
+}
+
 /*****************************************************************************
  * ClockStreamToSystem: converts a movie clock to system date
  *****************************************************************************/
diff --git a/src/input/clock.h b/src/input/clock.h
index b5f97b9..abe23aa 100644
--- a/src/input/clock.h
+++ b/src/input/clock.h
@@ -121,5 +121,11 @@ int input_clock_GetState( input_clock_t *,
 void input_clock_SetJitter( input_clock_t *,
                             mtime_t i_pts_delay, int i_cr_average );
 
+/**
+ * This function returns an estimation of the pts_delay needed to avoid rebufferization.
+ * XXX in the current implementation, the pts_delay will never be decreased.
+ */
+mtime_t input_clock_GetJitter( input_clock_t * );
+
 #endif
 
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 1109186..e91a6a7 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -2263,11 +2263,23 @@ static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
                 }
                 else if( b_late )
                 {
+                    mtime_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_clock );
+
+                    /* Avoid dangerously high value */
+                    const mtime_t i_pts_delay_max = 30000000;
+                    if( i_pts_delay > i_pts_delay_max )
+                        i_pts_delay = __MAX( i_pts_delay_max, p_sys->i_pts_delay );
+
                     /* Force a rebufferization when we are too late */
-                    msg_Err( p_sys->p_input, "ES_OUT_SET_(GROUP_)PCR  is called too late" );
+                    msg_Err( p_sys->p_input,
+                             "ES_OUT_SET_(GROUP_)PCR  is called too late, increasing pts_delay to %d ms",
+                             (int)(i_pts_delay/1000) );
+
                     /* It is not really good, as we throw away already buffered data
                      * TODO have a mean to correctly reenter bufferization */
-                    EsOutChangePosition( out );
+                    es_out_Control( out, ES_OUT_RESET_PCR );
+
+                    es_out_Control( out, ES_OUT_SET_JITTER, i_pts_delay, p_sys->i_cr_average );
                 }
             }
             return VLC_SUCCESS;




More information about the vlc-devel mailing list