[vlc-devel] [PATCH 1/2] RFC: clock: propagate input dejitter/buffering delay to the output clock (FIXUP)

Thomas Guillem thomas at gllm.fr
Thu Feb 14 17:49:07 CET 2019


This patch invalidate "RFC: output_clock: respect first pts delay (FIXUP)" and
is applied on top of the
https://code.videolan.org/jbk/vlc/commits/clock-core/26 branch.

The dejitter of the vlc_clock is the MAX between the dejitter set by the master
output (currently: 2 * AOUT_MAX_PTS_ADVANCE = 80ms by default) and the input
delay. The input delay is now the same than with the input_clock, that is:

Difference between the first pcr and the first pts, at a given time, taking
into account the buffer duration and the dejitter value set by the demux. Not
invented anything here, I just looked at the input_clock.c code.
---
 src/audio_output/output.c |  2 +-
 src/clock/clock.c         | 84 ++++++++++++++++++++++++---------------
 src/clock/clock.h         |  8 +++-
 src/input/es_out.c        | 22 ++++++++--
 4 files changed, 76 insertions(+), 40 deletions(-)

diff --git a/src/audio_output/output.c b/src/audio_output/output.c
index 8c355368f8..8b1b16c6dd 100644
--- a/src/audio_output/output.c
+++ b/src/audio_output/output.c
@@ -579,7 +579,7 @@ int aout_OutputNew (audio_output_t *aout, audio_sample_format_t *restrict fmt,
     aout_OutputLock(aout);
     vlc_tick_t period = AOUT_MAX_PTS_ADVANCE;
     int ret = aout->start(aout, fmt, &period);
-    vlc_clock_SetDejitter(owner->sync.clock, period * 2, 100);
+    vlc_clock_SetDejitter(owner->sync.clock, period * 2);
     aout_OutputUnlock(aout);
     if (ret)
     {
diff --git a/src/clock/clock.c b/src/clock/clock.c
index 8308c0ffc4..8aaaa458eb 100644
--- a/src/clock/clock.c
+++ b/src/clock/clock.c
@@ -22,6 +22,7 @@
 #endif
 
 #include <vlc_common.h>
+#include <vlc_aout.h>
 #include <assert.h>
 #include "clock.h"
 #include "clock_internal.h"
@@ -49,7 +50,9 @@ struct vlc_clock_main_t
     vlc_tick_t pause_date;
 
     clock_point_t wait_sync_ref; /* When the master */
-    vlc_tick_t dejitter; /* Delay used to absorb the clock jitter */
+    clock_point_t first_pcr;
+    vlc_tick_t output_dejitter; /* Delay used to absorb the output clock jitter */
+    vlc_tick_t input_dejitter; /* Delay used to absorb the input jitter */
     bool abort;
 };
 
@@ -60,12 +63,13 @@ struct vlc_clock_t
     void (*reset)(vlc_clock_t * clock);
     void (*pause)(vlc_clock_t * clock, vlc_tick_t system_now, bool paused);
     vlc_tick_t (*set_delay)(vlc_clock_t * clock, vlc_tick_t delay);
-    void (*set_dejitter)(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg);
+    void (*set_dejitter)(vlc_clock_t * clock, vlc_tick_t delay);
     vlc_tick_t (*to_system_locked)(vlc_clock_t * clock, vlc_tick_t system_now,
                                    vlc_tick_t pts);
 
     vlc_clock_main_t * owner;
     vlc_tick_t delay;
+    vlc_tick_t dejitter;
 };
 
 static vlc_tick_t main_system_to_stream(vlc_clock_main_t * main_clock,
@@ -177,14 +181,16 @@ static void vlc_clock_master_pause(vlc_clock_t * clock, vlc_tick_t now, bool pau
          * Only apply a delay if the clock has a reference point to avoid
          * messing up the timings if the stream was paused then seeked
          */
-        if (main_clock->offset != VLC_TICK_INVALID ||
-            (main_clock->wait_sync_ref.stream != VLC_TICK_INVALID ||
-             main_clock->wait_sync_ref.system != VLC_TICK_INVALID))
+        const vlc_tick_t delay = now - main_clock->pause_date;
+        if (main_clock->offset != VLC_TICK_INVALID)
         {
-            const vlc_tick_t delay = now - main_clock->pause_date;
             main_clock->last.system += delay;
             main_clock->offset += delay;
         }
+        if (main_clock->first_pcr.system != VLC_TICK_INVALID)
+            main_clock->first_pcr.system += delay;
+        if (main_clock->wait_sync_ref.system != VLC_TICK_INVALID)
+            main_clock->wait_sync_ref.system += delay;
         main_clock->pause_date = VLC_TICK_INVALID;
         vlc_cond_broadcast(&main_clock->cond);
     }
@@ -242,29 +248,17 @@ static vlc_tick_t vlc_clock_to_stream(vlc_clock_t * clock, vlc_tick_t system)
     return pts;
 }
 
-static void vlc_clock_master_set_dejitter(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg)
-{
-    VLC_UNUSED(cr_avg);
-    vlc_clock_main_t * main_clock = clock->owner;
-
-    vlc_mutex_lock(&main_clock->lock);
-    main_clock->dejitter = delay;
-    vlc_mutex_unlock(&main_clock->lock);
-}
-
-static vlc_tick_t vlc_clock_get_dejitter(vlc_clock_t * clock)
+static void vlc_clock_master_set_dejitter(vlc_clock_t * clock, vlc_tick_t delay)
 {
     vlc_clock_main_t * main_clock = clock->owner;
-    vlc_tick_t dejitter;
 
     vlc_mutex_lock(&main_clock->lock);
-    dejitter = main_clock->dejitter;
+    main_clock->output_dejitter = delay;
     vlc_mutex_unlock(&main_clock->lock);
-    return dejitter;
 }
 
 static vlc_tick_t vlc_clock_main_to_system_locked(vlc_clock_main_t * main_clock,
-                                               vlc_tick_t now, vlc_tick_t pts)
+                                                  vlc_tick_t now, vlc_tick_t pts)
 {
     vlc_tick_t system = main_stream_to_system(main_clock, pts);
     if (system == VLC_TICK_INVALID)
@@ -276,8 +270,15 @@ static vlc_tick_t vlc_clock_main_to_system_locked(vlc_clock_main_t * main_clock,
         if (main_clock->wait_sync_ref.stream == VLC_TICK_INVALID ||
             main_clock->wait_sync_ref.system == VLC_TICK_INVALID)
         {
-            main_clock->wait_sync_ref =
-                clock_point_Create(pts, now + main_clock->dejitter);
+            const vlc_tick_t pcr_delay =
+                main_clock->first_pcr.system != VLC_TICK_INVALID ?
+                pts - main_clock->first_pcr.stream + main_clock->first_pcr.system - now : 0;
+
+            const vlc_tick_t input_delay = main_clock->input_dejitter + pcr_delay;
+            const vlc_tick_t delay =
+                __MAX(input_delay, main_clock->output_dejitter);
+
+            main_clock->wait_sync_ref = clock_point_Create(pts, now + delay);
         }
         system = (pts - main_clock->wait_sync_ref.stream) / main_clock->rate;
         system += main_clock->wait_sync_ref.system;
@@ -373,11 +374,10 @@ int vlc_clock_Wait(vlc_clock_t * clock, vlc_tick_t pts, vlc_tick_t max_duration)
     return 1;
 }
 
-static void vlc_clock_slave_set_dejitter(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg)
+static void vlc_clock_slave_set_dejitter(vlc_clock_t * clock, vlc_tick_t delay)
 {
     VLC_UNUSED(clock);
     VLC_UNUSED(delay);
-    VLC_UNUSED(cr_avg);
 }
 
 
@@ -398,11 +398,13 @@ vlc_clock_main_t * vlc_clock_main_New(void)
     main_clock->offset = VLC_TICK_INVALID;
     main_clock->delay = 0;
 
+    main_clock->first_pcr = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
     main_clock->wait_sync_ref =
         main_clock->last = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
 
     main_clock->pause_date = VLC_TICK_INVALID;
-    main_clock->dejitter = 40000;
+    main_clock->input_dejitter = DEFAULT_PTS_DELAY;
+    main_clock->output_dejitter = AOUT_MAX_PTS_ADVANCE * 2;
     main_clock->abort = false;
 
     AvgInit(&main_clock->coeff_avg, 10);
@@ -423,6 +425,27 @@ void vlc_clock_main_Reset(vlc_clock_main_t * main_clock)
 {
     vlc_mutex_lock(&main_clock->lock);
     vlc_clock_main_reset(main_clock);
+    main_clock->first_pcr = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+void vlc_clock_main_SetFirstPcr(vlc_clock_main_t * main_clock,
+                                vlc_tick_t system_now, vlc_tick_t pts)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    if (main_clock->first_pcr.system == VLC_TICK_INVALID)
+    {
+        main_clock->first_pcr = clock_point_Create(pts, system_now);
+        main_clock->wait_sync_ref =
+            clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
+    }
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+void vlc_clock_main_SetInputDejitter(vlc_clock_main_t * main_clock, vlc_tick_t delay)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    main_clock->input_dejitter = delay;
     vlc_mutex_unlock(&main_clock->lock);
 }
 
@@ -485,14 +508,9 @@ vlc_tick_t vlc_clock_ConvertToStream(vlc_clock_t * clock, vlc_tick_t system)
     return vlc_clock_to_stream(clock, system);
 }
 
-void vlc_clock_SetDejitter(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg)
-{
-    clock->set_dejitter(clock, delay, cr_avg);
-}
-
-vlc_tick_t vlc_clock_GetDejitter(vlc_clock_t * clock)
+void vlc_clock_SetDejitter(vlc_clock_t * clock, vlc_tick_t delay)
 {
-    return vlc_clock_get_dejitter(clock);
+    clock->set_dejitter(clock, delay);
 }
 
 static void vlc_clock_set_master_cbk(vlc_clock_t * clk)
diff --git a/src/clock/clock.h b/src/clock/clock.h
index e079440af6..b63cccca82 100644
--- a/src/clock/clock.h
+++ b/src/clock/clock.h
@@ -51,6 +51,10 @@ void vlc_clock_main_Abort(vlc_clock_main_t * main);
  */
 void vlc_clock_main_Reset(vlc_clock_main_t * main);
 
+void vlc_clock_main_SetFirstPcr(vlc_clock_main_t * main, vlc_tick_t system_now,
+                                vlc_tick_t pts);
+void vlc_clock_main_SetInputDejitter(vlc_clock_main_t * main, vlc_tick_t delay);
+
 /**
  * This function set the allocated interface as the master making the current
  * master if any a slave.
@@ -126,9 +130,9 @@ vlc_tick_t vlc_clock_ConvertToStream(vlc_clock_t * clock, vlc_tick_t system);
 
 /**
  * This function sets the dejitter delay to absorb the clock jitter
- * also used as the ma1ximum delay before the synchro is considered to kick in
+ * also used as the maximum delay before the synchro is considered to kick in
  */
-void vlc_clock_SetDejitter(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg);
+void vlc_clock_SetDejitter(vlc_clock_t * clock, vlc_tick_t delay);
 
 /**
  * This function retrieves the synchronization delay
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 5d8be99f9f..b6a956285d 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -820,12 +820,19 @@ static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
     /* Here is a good place to destroy unused vout with every demuxer */
     input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
 
+
     /* */
     const vlc_tick_t i_wakeup_delay = VLC_TICK_FROM_MS(10); /* FIXME CLEANUP thread wake up time*/
     const vlc_tick_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : vlc_tick_now();
 
-    input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_input_clock, true,
-                                    i_current_date + i_wakeup_delay - i_buffering_duration );
+    const vlc_tick_t update = i_current_date + i_wakeup_delay - i_buffering_duration;
+
+    /* Send the first PCR to the output clock. This will be used as a reference
+     * point for the sync point. */
+    vlc_clock_main_SetFirstPcr(p_sys->p_pgrm->p_main_clock, update,
+                               i_stream_start);
+
+    input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_input_clock, true, update );
 
     foreach_es_then_es_slaves(p_es)
     {
@@ -1154,6 +1161,7 @@ static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
     if( p_sys->b_paused )
         input_clock_ChangePause( p_pgrm->p_input_clock, p_sys->b_paused, p_sys->i_pause_date );
     input_clock_SetJitter( p_pgrm->p_input_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
+    vlc_clock_main_SetInputDejitter( p_pgrm->p_main_clock, p_sys->i_pts_delay );
 
     /* Append it */
     vlc_list_append(&p_pgrm->node, &p_sys->programs);
@@ -3061,9 +3069,15 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         p_sys->i_cr_average = i_cr_average;
 
         if (b_change_clock)
+        {
             vlc_list_foreach(pgrm, &p_sys->programs, node)
-                 input_clock_SetJitter(pgrm->p_input_clock, i_pts_delay
-                                       + i_pts_jitter, i_cr_average);
+            {
+                input_clock_SetJitter(pgrm->p_input_clock, i_pts_delay
+                                      + i_pts_jitter, i_cr_average);
+                vlc_clock_main_SetInputDejitter(pgrm->p_main_clock,
+                                                i_pts_delay + i_pts_jitter);
+            }
+        }
         return VLC_SUCCESS;
     }
 
-- 
2.20.1



More information about the vlc-devel mailing list