[vlc-devel] [PATCH 03/18] clock: add vlc_clock

Thomas Guillem thomas at gllm.fr
Thu Mar 7 15:25:25 CET 2019


From: Denis Charmet <typx at videolan.org>

Co-authored-by: RĂ©mi Denis-Courmont <remi at remlab.net>
Co-authored-by: Thomas Guillem <thomas at gllm.fr>
Co-authored-by: Jean-Baptiste Kempf <jb at videolan.org>

Signed-off-by: Thomas Guillem <thomas at gllm.fr>
---
 src/Makefile.am   |   2 +
 src/clock/clock.c | 567 ++++++++++++++++++++++++++++++++++++++++++++++
 src/clock/clock.h | 134 +++++++++++
 3 files changed, 703 insertions(+)
 create mode 100644 src/clock/clock.c
 create mode 100644 src/clock/clock.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 5f90229486..7f6327c34e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -262,6 +262,7 @@ libvlccore_la_SOURCES = \
 	input/access.c \
 	clock/clock_internal.c \
 	clock/input_clock.c \
+	clock/clock.c \
 	input/control.c \
 	input/decoder.c \
 	input/decoder_helpers.c \
@@ -275,6 +276,7 @@ libvlccore_la_SOURCES = \
 	input/info.h \
 	input/meta.c \
 	clock/input_clock.h \
+	clock/clock.h \
 	clock/clock_internal.h \
 	input/decoder.h \
 	input/demux.h \
diff --git a/src/clock/clock.c b/src/clock/clock.c
new file mode 100644
index 0000000000..3fae6c9161
--- /dev/null
+++ b/src/clock/clock.c
@@ -0,0 +1,567 @@
+/*****************************************************************************
+ * clock.c: Output modules synchronisation clock
+ *****************************************************************************
+ * Copyright (C) 2018-2019 VLC authors, VideoLAN and Videolabs SAS
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_aout.h>
+#include <assert.h>
+#include "clock.h"
+#include "clock_internal.h"
+
+struct vlc_clock_main_t
+{
+    vlc_mutex_t lock;
+    vlc_cond_t cond;
+
+    vlc_clock_t *master;
+
+    unsigned rc;
+
+    /**
+     * Linear function
+     * system = pts * coeff / rate + offset
+     */
+    clock_point_t last;
+    average_t coeff_avg; /* Moving average to smooth out the instant coeff */
+    double rate;
+    double coeff;
+    vlc_tick_t offset;
+    vlc_tick_t delay;
+
+    vlc_tick_t pause_date;
+
+    clock_point_t wait_sync_ref; /* When the master */
+    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;
+};
+
+struct vlc_clock_t
+{
+    vlc_tick_t (*update)(vlc_clock_t *clock, vlc_tick_t system_now,
+                         vlc_tick_t pts, double rate);
+    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);
+    vlc_tick_t (*to_system_locked)(vlc_clock_t *clock, vlc_tick_t system_now,
+                                   vlc_tick_t pts, double rate);
+
+    vlc_clock_main_t *owner;
+    vlc_tick_t delay;
+    vlc_tick_t dejitter;
+};
+
+static vlc_tick_t main_stream_to_system(vlc_clock_main_t *main_clock,
+                                        vlc_tick_t pts)
+{
+    if (main_clock->offset == VLC_TICK_INVALID)
+        return VLC_TICK_INVALID;
+    return (vlc_tick_t)
+        (pts * main_clock->coeff / main_clock->rate + main_clock->offset);
+}
+
+static void vlc_clock_main_reset(vlc_clock_main_t *main_clock)
+{
+    AvgReset(&main_clock->coeff_avg);
+    main_clock->coeff = 1.0f;
+    main_clock->rate = 1.0f;
+    main_clock->offset = VLC_TICK_INVALID;
+
+    main_clock->wait_sync_ref =
+        main_clock->last = clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
+    vlc_cond_broadcast(&main_clock->cond);
+}
+
+static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
+                                          vlc_tick_t system_now,
+                                          vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+
+    if (unlikely(pts == VLC_TICK_INVALID || system_now == VLC_TICK_INVALID))
+        return VLC_TICK_INVALID;
+    pts += clock->delay;
+
+    vlc_mutex_lock(&main_clock->lock);
+
+    if (main_clock->offset != VLC_TICK_INVALID && pts != main_clock->last.stream)
+    {
+        /* We have a reference so we can update coeff */
+        double instant_coeff = (system_now - main_clock->last.system)
+                             / (double)(pts - main_clock->last.stream);
+        if (rate == main_clock->rate)
+        {
+            instant_coeff *= rate;
+            AvgUpdate(&main_clock->coeff_avg, instant_coeff);
+            main_clock->coeff = AvgGet(&main_clock->coeff_avg);
+        }
+    }
+    else
+        main_clock->wait_sync_ref =
+            clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
+
+    main_clock->offset = system_now - pts * main_clock->coeff / rate;
+
+    main_clock->last = clock_point_Create(system_now, pts);
+
+    main_clock->rate = rate;
+    vlc_cond_broadcast(&main_clock->cond);
+    vlc_mutex_unlock(&main_clock->lock);
+    return 0;
+}
+
+static void vlc_clock_master_reset(vlc_clock_t *clock)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_clock_main_reset(main_clock);
+
+    assert(main_clock->delay <= 0);
+    assert(clock->delay >= 0);
+    /* Move the delay from the slaves to the master */
+    if (clock->delay != 0 && main_clock->delay != 0)
+    {
+        vlc_tick_t delta = clock->delay + main_clock->delay;
+        if (delta > 0)
+        {
+            clock->delay = delta;
+            main_clock->delay = 0;
+        }
+        else
+        {
+            clock->delay = 0;
+            main_clock->delay = delta;
+        }
+    }
+
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static vlc_tick_t vlc_clock_master_set_delay(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+
+    vlc_tick_t delta = delay - clock->delay;
+
+    if (delta > 0)
+    {
+        /* The master clock is delayed */
+        main_clock->delay = 0;
+        clock->delay = delay;
+    }
+    else
+    {
+        /* Delay all slaves clock instead of advancing the master one */
+        main_clock->delay = delta;
+    }
+
+    assert(main_clock->delay <= 0);
+    assert(clock->delay >= 0);
+
+    vlc_cond_broadcast(&main_clock->cond);
+    vlc_mutex_unlock(&main_clock->lock);
+    return delta;
+}
+
+static void vlc_clock_master_set_dejitter(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+
+    vlc_mutex_lock(&main_clock->lock);
+    main_clock->output_dejitter = delay;
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static vlc_tick_t
+vlc_clock_monotonic_to_system_locked(vlc_clock_t *clock, vlc_tick_t now,
+                                     vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+
+    if (main_clock->wait_sync_ref.system == VLC_TICK_INVALID)
+    {
+        /* XXX: This input_delay calculation is needed until we (finally) get
+         * ride of the input clock. This code is adapted from input_clock.c and
+         * is used to introduce the same delay than the input clock (first PTS
+         * - first PCR). */
+        const vlc_tick_t pcr_delay =
+            main_clock->first_pcr.system == VLC_TICK_INVALID ? 0 :
+            (pts - main_clock->first_pcr.stream) / rate +
+            main_clock->first_pcr.system - 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);
+
+        main_clock->wait_sync_ref = clock_point_Create(now + delay, pts);
+    }
+    return (pts - main_clock->wait_sync_ref.stream) / rate
+        + main_clock->wait_sync_ref.system;
+}
+
+static vlc_tick_t vlc_clock_slave_to_system_locked(vlc_clock_t *clock,
+                                                   vlc_tick_t now,
+                                                   vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    if (main_clock->pause_date != VLC_TICK_INVALID)
+        return INT64_MAX;
+
+    vlc_tick_t system = main_stream_to_system(main_clock, pts);
+    if (system == VLC_TICK_INVALID)
+    {
+        /* We don't have a master sync point, let's fallback to a monotonic ref
+         * point */
+        system = vlc_clock_monotonic_to_system_locked(clock, now, pts, rate);
+    }
+
+    return system + (clock->delay - main_clock->delay) * rate;
+}
+
+static vlc_tick_t vlc_clock_master_to_system_locked(vlc_clock_t *clock,
+                                                    vlc_tick_t now,
+                                                    vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_tick_t system = main_stream_to_system(main_clock, pts);
+    if (system == VLC_TICK_INVALID)
+    {
+        /* We don't have a master sync point, let's fallback to a monotonic ref
+         * point */
+        system = vlc_clock_monotonic_to_system_locked(clock, now, pts, rate);
+    }
+
+    return system + clock->delay * rate;
+}
+
+static vlc_tick_t vlc_clock_slave_update(vlc_clock_t *clock,
+                                         vlc_tick_t system_now,
+                                         vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+
+    vlc_tick_t computed = clock->to_system_locked(clock, system_now, pts, rate);
+    vlc_mutex_unlock(&main_clock->lock);
+    return computed != INT64_MAX ? computed - system_now : VLC_TICK_INVALID;
+}
+
+static void vlc_clock_slave_reset(vlc_clock_t *clock)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    main_clock->wait_sync_ref =
+        clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static vlc_tick_t vlc_clock_slave_set_delay(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+
+    clock->delay = delay;
+
+    vlc_cond_broadcast(&main_clock->cond);
+    vlc_mutex_unlock(&main_clock->lock);
+    return 0;
+}
+
+int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t pts,
+                   double rate, vlc_tick_t max_duration)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    const vlc_tick_t max_deadline =
+        max_duration > 0 ? system_now + max_duration : INT64_MAX;
+    while (!main_clock->abort)
+    {
+        vlc_tick_t deadline;
+        if (main_clock->pause_date != VLC_TICK_INVALID)
+            deadline = INT64_MAX;
+        else
+            deadline = clock->to_system_locked(clock, system_now, pts, rate);
+        deadline = __MIN(deadline, max_deadline);
+
+        if (vlc_cond_timedwait(&main_clock->cond, &main_clock->lock, deadline))
+        {
+            vlc_mutex_unlock(&main_clock->lock);
+            return 0;
+        }
+    }
+    vlc_mutex_unlock(&main_clock->lock);
+    return -1;
+}
+
+static void vlc_clock_slave_set_dejitter(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    VLC_UNUSED(clock);
+    VLC_UNUSED(delay);
+}
+
+
+vlc_clock_main_t *vlc_clock_main_New(void)
+{
+    vlc_clock_main_t *main_clock = malloc(sizeof(vlc_clock_main_t));
+
+    if (main_clock == NULL)
+        return NULL;
+
+    vlc_mutex_init(&main_clock->lock);
+    vlc_cond_init(&main_clock->cond);
+    main_clock->master = NULL;
+    main_clock->rc = 1;
+
+    main_clock->coeff = 1.0f;
+    main_clock->rate = 1.0f;
+    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->input_dejitter = DEFAULT_PTS_DELAY;
+    main_clock->output_dejitter = AOUT_MAX_PTS_ADVANCE * 2;
+    main_clock->abort = false;
+
+    AvgInit(&main_clock->coeff_avg, 10);
+
+    return main_clock;
+}
+
+void vlc_clock_main_Abort(vlc_clock_main_t *main_clock)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    main_clock->abort = true;
+    vlc_cond_broadcast(&main_clock->cond);
+
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+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(system_now, pts);
+        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);
+}
+
+void vlc_clock_main_ChangePause(vlc_clock_main_t *main_clock, vlc_tick_t now,
+                                bool paused)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    assert(paused == (main_clock->pause_date == VLC_TICK_INVALID));
+
+    if (paused)
+        main_clock->pause_date = now;
+    else
+    {
+        /**
+         * Only apply a delay if the clock has a reference point to avoid
+         * messing up the timings if the stream was paused then seeked
+         */
+        const vlc_tick_t delay = now - main_clock->pause_date;
+        if (main_clock->offset != VLC_TICK_INVALID)
+        {
+            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);
+    }
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+void vlc_clock_main_Delete(vlc_clock_main_t *main_clock)
+{
+    vlc_mutex_destroy(&main_clock->lock);
+    vlc_cond_destroy(&main_clock->cond);
+    assert(main_clock->rc == 1);
+    free(main_clock);
+}
+
+vlc_tick_t vlc_clock_Update(vlc_clock_t *clock, vlc_tick_t system_now,
+                            vlc_tick_t pts, double rate)
+{
+    return clock->update(clock, system_now, pts, rate);
+}
+
+void vlc_clock_Reset(vlc_clock_t *clock)
+{
+    clock->reset(clock);
+}
+
+vlc_tick_t vlc_clock_SetDelay(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    return clock->set_delay(clock, delay);
+}
+
+vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
+                                     vlc_tick_t pts, double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_tick_t system = clock->to_system_locked(clock, system_now, pts, rate);
+    vlc_mutex_unlock(&main_clock->lock);
+    return system;
+}
+
+void vlc_clock_ConvertArrayToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
+                                    vlc_tick_t *pts_array, size_t pts_count,
+                                    double rate)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    for (size_t i = 0; i < pts_count; ++i)
+        pts_array[i] = clock->to_system_locked(clock, system_now, pts_array[i],
+                                               rate);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+void vlc_clock_SetDejitter(vlc_clock_t *clock, vlc_tick_t delay)
+{
+    clock->set_dejitter(clock, delay);
+}
+
+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->to_system_locked = vlc_clock_master_to_system_locked;
+}
+
+static void vlc_clock_set_slave_callbacks(vlc_clock_t *clock)
+{
+    clock->update = vlc_clock_slave_update;
+    clock->reset = vlc_clock_slave_reset;
+    clock->set_delay = vlc_clock_slave_set_delay;
+    clock->set_dejitter = vlc_clock_slave_set_dejitter;
+    clock->to_system_locked = vlc_clock_slave_to_system_locked;
+}
+
+vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock)
+{
+    vlc_clock_t *clock = malloc(sizeof(vlc_clock_t));
+    if (clock == NULL)
+        return NULL;
+
+    clock->owner = main_clock;
+    clock->delay = 0;
+
+    vlc_mutex_lock(&main_clock->lock);
+    if (main_clock->master != NULL)
+    {
+        vlc_clock_master_reset(main_clock->master);
+        vlc_clock_set_slave_callbacks(main_clock->master);
+    }
+    vlc_clock_set_master_callbacks(clock);
+    main_clock->master = clock;
+    main_clock->rc++;
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return clock;
+}
+
+vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock)
+{
+    vlc_clock_t *clock = malloc(sizeof(vlc_clock_t));
+    if (clock == NULL)
+        return NULL;
+
+    clock->owner = main_clock;
+    clock->delay = 0;
+
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_clock_set_slave_callbacks(clock);
+    main_clock->rc++;
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return clock;
+}
+
+vlc_clock_t *vlc_clock_CreateSlave(const vlc_clock_t *clock)
+{
+    return vlc_clock_main_CreateSlave(clock->owner);
+}
+
+void vlc_clock_main_SetMaster(vlc_clock_main_t *main_clock, vlc_clock_t *clock)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    if (main_clock->master != NULL)
+    {
+        vlc_clock_master_reset(main_clock->master);
+        vlc_clock_set_slave_callbacks(main_clock->master);
+    }
+    vlc_clock_set_master_callbacks(clock);
+    main_clock->master = clock;
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+
+void vlc_clock_Delete(vlc_clock_t *clock)
+{
+    vlc_clock_main_t *main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    if (clock == main_clock->master)
+    {
+        vlc_clock_main_reset(main_clock);
+        main_clock->master = NULL;
+    }
+    main_clock->rc--;
+    vlc_mutex_unlock(&main_clock->lock);
+    free(clock);
+}
diff --git a/src/clock/clock.h b/src/clock/clock.h
new file mode 100644
index 0000000000..0088d89ebe
--- /dev/null
+++ b/src/clock/clock.h
@@ -0,0 +1,134 @@
+/*****************************************************************************
+ * clock.h: Output modules synchronisation clock
+ *****************************************************************************
+ * Copyright (C) 2018-2019 VLC authors, VideoLAN and Videolabs SAS
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef VLC_CLOCK_H
+#define VLC_CLOCK_H
+
+typedef struct vlc_clock_main_t vlc_clock_main_t;
+typedef struct vlc_clock_t vlc_clock_t;
+
+/**
+ * This function creates the vlc_clock_main_t of the program
+ */
+vlc_clock_main_t *vlc_clock_main_New(void);
+
+/**
+ * Destroy the clock main
+ */
+void vlc_clock_main_Delete(vlc_clock_main_t *main_clock);
+
+/**
+ * Abort all the pending vlc_clock_Wait
+ */
+void vlc_clock_main_Abort(vlc_clock_main_t *main_clock);
+
+/**
+ * Reset the vlc_clock_main_t
+ */
+void vlc_clock_main_Reset(vlc_clock_main_t *main_clock);
+
+void vlc_clock_main_SetFirstPcr(vlc_clock_main_t *main_clock,
+                                vlc_tick_t system_now, vlc_tick_t pts);
+void vlc_clock_main_SetInputDejitter(vlc_clock_main_t *main_clock,
+                                     vlc_tick_t delay);
+
+/**
+ * This function allows changing the pause status.
+ */
+void vlc_clock_main_ChangePause(vlc_clock_main_t *clock, vlc_tick_t system_now,
+                                bool paused);
+
+/**
+ * This function set the allocated interface as the master making the current
+ * master if any a slave.
+ */
+void vlc_clock_main_SetMaster(vlc_clock_main_t *main_clock, vlc_clock_t *clock);
+
+/**
+ * This function creates a new master vlc_clock_t interface
+ *
+ * You must use vlc_clock_Delete to free it.
+ */
+vlc_clock_t *vlc_clock_main_CreateMaster(vlc_clock_main_t *main_clock);
+
+/**
+ * This function creates a new slave vlc_clock_t interface
+ *
+ * You must use vlc_clock_Delete to free it.
+ */
+vlc_clock_t *vlc_clock_main_CreateSlave(vlc_clock_main_t *main_clock);
+
+/**
+ * This function creates a new slave vlc_clock_t interface
+ *
+ * You must use vlc_clock_Delete to free it.
+ */
+vlc_clock_t *vlc_clock_CreateSlave(const vlc_clock_t *clock);
+
+/**
+ * This function free the resources allocated by vlc_clock*Create*()
+ */
+void vlc_clock_Delete(vlc_clock_t *clock);
+
+/**
+ * This function will update the clock drift and returns the drift
+ */
+vlc_tick_t vlc_clock_Update(vlc_clock_t *clock, vlc_tick_t system_now,
+                            vlc_tick_t pts, double rate);
+
+/**
+ * This function resets the clock drift
+ */
+void vlc_clock_Reset(vlc_clock_t *clock);
+
+/**
+ * This functions change the clock delay
+ *
+ * It returns the amount of time the clock owner need to wait in order to reach
+ * the time introduced by the new positive delay.
+ */
+vlc_tick_t vlc_clock_SetDelay(vlc_clock_t *clock, vlc_tick_t pts_delay);
+
+/**
+ * Wait for a timestamp expressed in stream time
+ */
+int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t pts,
+                   double rate, vlc_tick_t max_duration);
+
+/**
+ * This function converts a timestamp from stream to system
+ */
+vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
+                                     vlc_tick_t pts, double rate);
+
+/**
+ * This functon converts an array of timestamp from stream to system
+ */
+void vlc_clock_ConvertArrayToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
+                                    vlc_tick_t *pts_array, size_t pts_count,
+                                    double rate);
+
+/**
+ * This function sets the dejitter delay to absorb the clock jitter
+ *
+ * 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);
+
+#endif /*VLC_CLOCK_H*/
-- 
2.20.1



More information about the vlc-devel mailing list