[vlc-devel] [PATCH 3/6] clock: add vlc_clock_SetDecoderLatency

Thomas Guillem thomas at gllm.fr
Thu Sep 26 16:38:11 CEST 2019


The highest decoder latency of all clocks will be used to setup the initial
dejitter delay.

This function will only succeed if the audio output is not yet started (i.e.
vlc_clock_Update() on the master audio clock has not been called). This is only
possible during the dejitter phase (minimum 80ms).

Most samples will have the video started just after (or just before) the audio,
therefore this new call will very likely succeed with most of them.

In any case, failure *must* be handled by the caller, cf. next commits.
---
 src/clock/clock.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++-
 src/clock/clock.h | 13 ++++++++
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/src/clock/clock.c b/src/clock/clock.c
index a2fd968d15..d0a38606ac 100644
--- a/src/clock/clock.c
+++ b/src/clock/clock.c
@@ -66,14 +66,17 @@ struct vlc_clock_t
     void (*reset)(vlc_clock_t *clock);
     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 (*set_decoder_latency)(vlc_clock_t *clock, vlc_tick_t latency);
     vlc_tick_t (*to_system_locked)(vlc_clock_t *clock, vlc_tick_t system_now,
                                    vlc_tick_t ts, double rate);
 
     vlc_clock_main_t *owner;
     vlc_tick_t delay;
+    vlc_tick_t decoder_latency;
 
     const struct vlc_clock_cbs *cbs;
     void *cbs_data;
+
     struct vlc_list node;
 };
 
@@ -86,6 +89,21 @@ static vlc_tick_t main_stream_to_system(vlc_clock_main_t *main_clock,
         (ts * main_clock->coeff / main_clock->rate + main_clock->offset);
 }
 
+static vlc_tick_t
+vlc_clock_main_get_decoder_latency(vlc_clock_main_t *main_clock)
+{
+    vlc_tick_t decoder_latency = 0;
+    vlc_clock_t *slave;
+
+    vlc_list_foreach(slave, &main_clock->slaves, node)
+    {
+        if (slave->decoder_latency > decoder_latency)
+            decoder_latency = slave->decoder_latency;
+    }
+
+    return decoder_latency;
+}
+
 static void vlc_clock_main_reset(vlc_clock_main_t *main_clock)
 {
     AvgReset(&main_clock->coeff_avg);
@@ -227,6 +245,16 @@ static void vlc_clock_master_set_dejitter(vlc_clock_t *clock, vlc_tick_t delay)
     vlc_mutex_unlock(&main_clock->lock);
 }
 
+static int vlc_clock_master_set_decoder_latency(vlc_clock_t *clock,
+                                                vlc_tick_t latency)
+
+{
+    VLC_UNUSED(clock);
+    VLC_UNUSED(latency);
+
+    return 0;
+}
+
 static vlc_tick_t
 vlc_clock_monotonic_to_system_locked(vlc_clock_t *clock, vlc_tick_t now,
                                      vlc_tick_t ts, double rate)
@@ -247,7 +275,8 @@ vlc_clock_monotonic_to_system_locked(vlc_clock_t *clock, vlc_tick_t now,
         const vlc_tick_t input_delay = main_clock->input_dejitter + pcr_delay;
 
         const vlc_tick_t delay =
-            __MAX(input_delay, main_clock->output_dejitter);
+            __MAX(input_delay, main_clock->output_dejitter)
+            + vlc_clock_main_get_decoder_latency( main_clock );
 
         main_clock->wait_sync_ref = clock_point_Create(now + delay, ts);
     }
@@ -366,6 +395,45 @@ static void vlc_clock_slave_set_dejitter(vlc_clock_t *clock, vlc_tick_t delay)
     VLC_UNUSED(delay);
 }
 
+static int vlc_clock_slave_set_decoder_latency(vlc_clock_t *clock,
+                                                vlc_tick_t latency)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+
+    int ret;
+    if (main_clock->offset == VLC_TICK_INVALID)
+    {
+        /* The master clock is not yet updated */
+
+        if (main_clock->wait_sync_ref.system != VLC_TICK_INVALID)
+        {
+            /* Update the monotonic clock delay */
+
+            const vlc_tick_t last_latency =
+                vlc_clock_main_get_decoder_latency(main_clock);
+
+            /* The latency can only goes up, the audio output won't be able to
+             * cope with a decrease of the next play date. */
+            if (latency > last_latency)
+                main_clock->wait_sync_ref.system += latency - last_latency;
+        } /* else the next monotonic update will handle this latency */
+
+        clock->decoder_latency = latency;
+        ret = 0;
+    }
+    else
+    {
+        /* It is impossible to use this new latency when the master clock is
+         * already started. Indeed, in that case, the master output would have
+         * to be delayed or fastened, causing visual or audio glitches. */
+        ret = -1;
+    }
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return ret;
+}
+
 vlc_clock_main_t *vlc_clock_main_New(void)
 {
     vlc_clock_main_t *main_clock = malloc(sizeof(vlc_clock_main_t));
@@ -528,12 +596,18 @@ void vlc_clock_SetDejitter(vlc_clock_t *clock, vlc_tick_t delay)
     clock->set_dejitter(clock, delay);
 }
 
+int vlc_clock_SetDecoderLatency(vlc_clock_t *clock, vlc_tick_t latency)
+{
+    return clock->set_decoder_latency(clock, latency);
+}
+
 static void vlc_clock_set_master_callbacks(vlc_clock_t *clock)
 {
     clock->update = vlc_clock_master_update;
     clock->reset = vlc_clock_master_reset;
     clock->set_delay = vlc_clock_master_set_delay;
     clock->set_dejitter = vlc_clock_master_set_dejitter;
+    clock->set_decoder_latency = vlc_clock_master_set_decoder_latency;
     clock->to_system_locked = vlc_clock_master_to_system_locked;
 }
 
@@ -543,6 +617,7 @@ static void vlc_clock_set_slave_callbacks(vlc_clock_t *clock)
     clock->reset = vlc_clock_slave_reset;
     clock->set_delay = vlc_clock_slave_set_delay;
     clock->set_dejitter = vlc_clock_slave_set_dejitter;
+    clock->set_decoder_latency = vlc_clock_slave_set_decoder_latency;
     clock->to_system_locked = vlc_clock_slave_to_system_locked;
 }
 
@@ -556,6 +631,7 @@ static vlc_clock_t *vlc_clock_main_Create(vlc_clock_main_t *main_clock,
 
     clock->owner = main_clock;
     clock->delay = 0;
+    clock->decoder_latency = 0;
     clock->cbs = cbs;
     clock->cbs_data = cbs_data;
     assert(!cbs || cbs->on_update);
diff --git a/src/clock/clock.h b/src/clock/clock.h
index 8e9e6eb681..4f699f4540 100644
--- a/src/clock/clock.h
+++ b/src/clock/clock.h
@@ -181,4 +181,17 @@ void vlc_clock_ConvertArrayToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
  */
 void vlc_clock_SetDejitter(vlc_clock_t *clock, vlc_tick_t delay);
 
+/**
+ * This functon sets the decoder latency of the clock
+ *
+ * The highest decoder latency of all clocks will be used to setup the initial
+ * dejitter delay.
+ *
+ * @return 0 in case of success (the latency was set during the dejitter
+ * phase) or -1 otherwise. In case the error, the decoder should not use any
+ * extra latency (by disabling multi-threading for example).
+ */
+VLC_USED
+int vlc_clock_SetDecoderLatency(vlc_clock_t *clock, vlc_tick_t latency);
+
 #endif /*VLC_CLOCK_H*/
-- 
2.20.1



More information about the vlc-devel mailing list