[vlc-devel] [RFC PATCH 01/13] clock: add vlc_clock

Thomas Guillem thomas at gllm.fr
Wed Jun 27 14:41:23 CEST 2018


From: Denis Charmet <typx at videolan.org>

---
 src/Makefile.am            |   2 +
 src/clock/clock.c          | 526 +++++++++++++++++++++++++++++++++++++
 src/clock/clock.h          | 117 +++++++++
 src/clock/clock_internal.c |  55 ++--
 src/clock/clock_internal.h |  38 +--
 src/clock/input_clock.c    |  42 +--
 6 files changed, 717 insertions(+), 63 deletions(-)
 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 897c557e55..7b84cca68c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -233,6 +233,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/demux.c \
@@ -244,6 +245,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..ad6b2152ea
--- /dev/null
+++ b/src/clock/clock.c
@@ -0,0 +1,526 @@
+/*****************************************************************************
+ * clock.c: Ouptut modules synchronisation clock
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ *
+ * 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 <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;
+
+    /* FIXME do we need to keep the slaves?*/
+    vlc_clock_t ** slaves;
+    int nslaves;
+
+    /**
+     * Linear function
+     * system = pts * coeff / rate + offset
+     */
+    clock_point_t last;
+    average_t coeff_avg; /* Moving average to smooth out the instant coeff */
+    float coeff;
+    float rate;
+    vlc_tick_t offset;
+    vlc_tick_t delay;
+    vlc_tick_t reset_date;
+
+    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 */
+    bool abort;
+};
+
+struct vlc_clock_t
+{
+    vlc_tick_t (*update)(vlc_clock_t * clock, vlc_tick_t timestamp,
+                      vlc_tick_t system_now, float rate);
+    void (*reset)(vlc_clock_t * clock);
+    void (*pause)(vlc_clock_t * clock, bool paused, vlc_tick_t now);
+    void (*set_dejitter)(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg);
+    vlc_tick_t (*to_system_locked)(vlc_clock_t * clock, vlc_tick_t now, vlc_tick_t pts);
+
+    vlc_clock_main_t * owner;
+    vlc_tick_t delay;
+};
+
+static vlc_tick_t main_system_to_stream(vlc_clock_main_t * main_clock,
+                                       vlc_tick_t system)
+{
+    if (unlikely(main_clock->offset == VLC_TS_INVALID))
+        return VLC_TS_INVALID;
+    return (vlc_tick_t) ((system - main_clock->offset) * main_clock->rate / main_clock->coeff);
+}
+
+static vlc_tick_t main_stream_to_system(vlc_clock_main_t * main_clock,
+                                       vlc_tick_t pts)
+{
+    if (unlikely(main_clock->offset == VLC_TS_INVALID))
+        return VLC_TS_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_TS_INVALID;
+
+    main_clock->wait_sync_ref =
+        main_clock->last = clock_point_Create(VLC_TS_INVALID, VLC_TS_INVALID);
+    vlc_cond_broadcast(&main_clock->cond);
+}
+
+static vlc_tick_t vlc_clock_master_update(vlc_clock_t * clock, vlc_tick_t pts,
+                                       vlc_tick_t system_now, float rate)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+
+    vlc_mutex_lock(&main_clock->lock);
+    assert(main_clock->pause_date == VLC_TS_INVALID);
+
+    if (main_clock->reset_date != VLC_TS_INVALID)
+    {
+        if (system_now < main_clock->reset_date)
+        {
+            vlc_mutex_unlock(&main_clock->lock);
+            return 0;
+        }
+        main_clock->reset_date = VLC_TS_INVALID;
+        vlc_clock_main_reset(main_clock);
+    }
+    main_clock->rate = rate;
+
+    if (unlikely(pts == VLC_TS_INVALID || system_now == VLC_TS_INVALID))
+    {
+        vlc_mutex_unlock(&main_clock->lock);
+        return VLC_TS_INVALID;
+    }
+
+    if (main_clock->offset != VLC_TS_INVALID && pts != main_clock->last.stream)
+    {
+        /* We have a reference so we can update coeff */
+        float instant_coeff =
+            ((float) (system_now - main_clock->last.system))/(pts - main_clock->last.stream);
+        AvgUpdate(&main_clock->coeff_avg, instant_coeff);
+        main_clock->coeff = AvgGet(&main_clock->coeff_avg);
+        /* TODO handle rate change?*/
+    }
+    else
+        main_clock->wait_sync_ref =
+            clock_point_Create(VLC_TS_INVALID, VLC_TS_INVALID);
+
+    main_clock->offset = system_now - pts * main_clock->coeff / rate;
+
+    if (pts != VLC_TS_INVALID && system_now != VLC_TS_INVALID)
+        main_clock->last = clock_point_Create(pts, system_now);
+
+    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);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static void vlc_clock_master_pause(vlc_clock_t * clock, bool paused, vlc_tick_t now)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    assert(paused == (main_clock->pause_date == VLC_TS_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
+         */
+        if (main_clock->offset != VLC_TS_INVALID ||
+            (main_clock->wait_sync_ref.stream != VLC_TS_INVALID ||
+             main_clock->wait_sync_ref.system != VLC_TS_INVALID))
+        {
+            const vlc_tick_t delay = now - main_clock->pause_date;
+            main_clock->last.system += delay;
+            main_clock->offset += delay;
+        }
+        main_clock->pause_date = VLC_TS_INVALID;
+        vlc_cond_broadcast(&main_clock->cond);
+    }
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static float vlc_clock_get_rate(vlc_clock_t * clock)
+{
+    float rate;
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+
+    rate = main_clock->rate;
+
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return rate;
+}
+
+static vlc_tick_t vlc_clock_to_stream(vlc_clock_t * clock, vlc_tick_t system)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_tick_t pts;
+
+    vlc_mutex_lock(&main_clock->lock);
+    pts = main_system_to_stream(main_clock, system);
+    vlc_mutex_unlock(&main_clock->lock);
+    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)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_tick_t dejitter;
+
+    vlc_mutex_lock(&main_clock->lock);
+    dejitter = main_clock->dejitter;
+    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 system = main_stream_to_system(main_clock, pts);
+    if (system == VLC_TS_INVALID)
+    {
+        /**
+         * We don't have a master sync point, let's fallback to a monotonic
+         * ref point
+         */
+        if (main_clock->wait_sync_ref.stream == VLC_TS_INVALID ||
+            main_clock->wait_sync_ref.system == VLC_TS_INVALID)
+        {
+            main_clock->wait_sync_ref =
+                clock_point_Create(pts, now + main_clock->dejitter);
+        }
+        system = (pts - main_clock->wait_sync_ref.stream) / main_clock->rate;
+        system += main_clock->wait_sync_ref.system;
+    }
+    return system;
+}
+
+static vlc_tick_t vlc_clock_slave_to_system_locked(vlc_clock_t * clock, vlc_tick_t now,
+                                                vlc_tick_t pts)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    if (main_clock->pause_date != VLC_TS_INVALID)
+        return INT64_MAX;
+
+    return vlc_clock_main_to_system_locked(main_clock, now, pts)
+         + clock->delay - main_clock->delay;
+}
+
+static vlc_tick_t vlc_clock_master_to_system_locked(vlc_clock_t * clock, vlc_tick_t now,
+                                                 vlc_tick_t pts)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    assert(main_clock->pause_date == VLC_TS_INVALID);
+    return vlc_clock_main_to_system_locked(main_clock, now, pts);
+}
+
+static vlc_tick_t vlc_clock_slave_update(vlc_clock_t * clock, vlc_tick_t timestamp,
+                                      vlc_tick_t system_now, float rate)
+{
+    VLC_UNUSED(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, timestamp);
+    vlc_mutex_unlock(&main_clock->lock);
+    return (computed != INT64_MAX)?(computed - system_now):VLC_TS_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_TS_INVALID, VLC_TS_INVALID);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+static void vlc_clock_slave_pause(vlc_clock_t * clock, bool paused, vlc_tick_t now)
+{
+    VLC_UNUSED(clock);
+    VLC_UNUSED(paused);
+    VLC_UNUSED(now);
+}
+
+int vlc_clock_Wait(vlc_clock_t * clock, vlc_tick_t pts, vlc_tick_t max_duration)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_tick_t now = vlc_tick_now();
+    vlc_tick_t max_deadline = max_duration > 0 ? now + max_duration : INT64_MAX;
+    while (!main_clock->abort)
+    {
+        vlc_tick_t deadline;
+        if (main_clock->pause_date != VLC_TS_INVALID)
+            deadline = INT64_MAX;
+        else
+            deadline = clock->to_system_locked(clock, now, pts);
+        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, int cr_avg)
+{
+    VLC_UNUSED(clock);
+    VLC_UNUSED(delay);
+    VLC_UNUSED(cr_avg);
+}
+
+
+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;
+
+    TAB_INIT(main_clock->nslaves, main_clock->slaves);
+    main_clock->coeff = 1.0f;
+    main_clock->rate = 1.0f;
+    main_clock->offset = VLC_TS_INVALID;
+    main_clock->reset_date = VLC_TS_INVALID;
+    main_clock->delay = 0;
+
+    main_clock->wait_sync_ref =
+        main_clock->last = clock_point_Create(VLC_TS_INVALID, VLC_TS_INVALID);
+
+    main_clock->pause_date = VLC_TS_INVALID;
+    main_clock->dejitter = 200000;
+    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);
+    vlc_mutex_unlock(&main_clock->lock);
+}
+
+void vlc_clock_main_Delete(vlc_clock_main_t * main_clock)
+{
+    while (main_clock->nslaves != 0)
+        vlc_clock_Delete(main_clock->slaves[0]);
+
+    if (main_clock->master != NULL)
+        vlc_clock_Delete(main_clock->master);
+
+    TAB_CLEAN(main_clock->nslaves, main_clock->slaves);
+    vlc_mutex_destroy(&main_clock->lock);
+    vlc_cond_destroy(&main_clock->cond);
+    free(main_clock);
+}
+
+vlc_tick_t vlc_clock_Update(vlc_clock_t * clock, vlc_tick_t timestamp,
+                         vlc_tick_t system_now, float rate)
+{
+    return clock->update(clock, timestamp, system_now, rate);
+}
+
+void vlc_clock_Reset(vlc_clock_t * clock)
+{
+    clock->reset(clock);
+}
+
+void vlc_clock_ChangePause(vlc_clock_t * clock, bool paused, vlc_tick_t system_now)
+{
+    clock->pause(clock, paused, system_now);
+}
+
+float vlc_clock_GetRate(vlc_clock_t * clock)
+{
+    return vlc_clock_get_rate(clock);
+}
+
+vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t * clock, vlc_tick_t pts)
+{
+    vlc_clock_main_t * main_clock = clock->owner;
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_tick_t system = clock->to_system_locked(clock, vlc_tick_now(), pts);
+    vlc_mutex_unlock(&main_clock->lock);
+    return system;
+}
+
+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)
+{
+    return vlc_clock_get_dejitter(clock);
+}
+
+static void vlc_clock_set_master_cbk(vlc_clock_t * clk)
+{
+
+    clk->update = vlc_clock_master_update;
+    clk->reset = vlc_clock_master_reset;
+    clk->pause = vlc_clock_master_pause;
+    clk->set_dejitter = vlc_clock_master_set_dejitter;
+    clk->to_system_locked = vlc_clock_master_to_system_locked;
+}
+
+static void vlc_clock_set_slave_cbk(vlc_clock_t * clk)
+{
+    clk->update = vlc_clock_slave_update;
+    clk->reset = vlc_clock_slave_reset;
+    clk->pause = vlc_clock_slave_pause;
+    clk->set_dejitter = vlc_clock_slave_set_dejitter;
+    clk->to_system_locked = vlc_clock_slave_to_system_locked;
+}
+
+vlc_clock_t * vlc_clock_NewMaster(vlc_clock_main_t * main_clock)
+{
+    vlc_clock_t * clk = malloc(sizeof(vlc_clock_t));
+    if (clk == NULL)
+        return NULL;
+
+    clk->owner = main_clock;
+    clk->delay = 0;
+
+    vlc_mutex_lock(&main_clock->lock);
+    if (main_clock->master != NULL)
+    {
+        vlc_clock_master_reset(main_clock->master);
+        vlc_clock_set_slave_cbk(main_clock->master);
+        TAB_APPEND(main_clock->nslaves, main_clock->slaves, main_clock->master);
+    }
+    vlc_clock_set_master_cbk(clk);
+    main_clock->master = clk;
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return clk;
+}
+
+vlc_clock_t * vlc_clock_NewSlave(vlc_clock_main_t * main_clock)
+{
+    vlc_clock_t * clk = malloc(sizeof(vlc_clock_t));
+    if (clk == NULL)
+        return NULL;
+
+    clk->owner = main_clock;
+    clk->delay = 0;
+
+    vlc_mutex_lock(&main_clock->lock);
+    vlc_clock_set_slave_cbk(clk);
+    TAB_APPEND(main_clock->nslaves, main_clock->slaves, clk);
+    vlc_mutex_unlock(&main_clock->lock);
+
+    return clk;
+}
+
+void vlc_clock_SetMaster(vlc_clock_main_t * main_clock, vlc_clock_t * clk)
+{
+    vlc_mutex_lock(&main_clock->lock);
+    TAB_REMOVE(main_clock->nslaves, main_clock->slaves, clk);
+    if (main_clock->master != NULL)
+    {
+        vlc_clock_master_reset(main_clock->master);
+        vlc_clock_set_slave_cbk(main_clock->master);
+        TAB_APPEND(main_clock->nslaves, main_clock->slaves, main_clock->master);
+    }
+    vlc_clock_set_master_cbk(clk);
+    main_clock->master = clk;
+    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;
+    }
+    else
+        TAB_REMOVE(main_clock->nslaves, main_clock->slaves, clock);
+    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..f5a4df54d0
--- /dev/null
+++ b/src/clock/clock.h
@@ -0,0 +1,117 @@
+/*****************************************************************************
+ * clock.h: Ouptut modules synchronisation clock
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ *
+ * 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 LIBVLC_CLOCK_H
+#define LIBVLC_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);
+
+/**
+ * Abort all the pending vlc_clock_Wait
+ */
+void vlc_clock_main_Abort(vlc_clock_main_t * main);
+
+/**
+ * Reset the vlc_clock_main_t
+ */
+void vlc_clock_main_Reset(vlc_clock_main_t * main);
+
+/**
+ * This function set the allocated interface as the master making the current
+ * master if any a slave.
+ */
+void vlc_clock_SetMaster(vlc_clock_main_t * main, vlc_clock_t * new_master);
+
+/**
+ * This function creates a new slave vlc_clock_t interface.
+ * You must use vlc_clock_Delete to free it.
+ */
+vlc_clock_t * vlc_clock_NewMaster(vlc_clock_main_t * main);
+
+/**
+ * This function creates a new slave vlc_clock_t interface.
+ * You must use vlc_clock_Delete to free it.
+ */
+vlc_clock_t * vlc_clock_NewSlave(vlc_clock_main_t * main);
+
+/**
+ * This function free the resources allocated by vlc_clock_New
+ */
+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 pts,
+                         vlc_tick_t system_now, float rate);
+
+/**
+ * This function resets the clock drift
+ */
+void vlc_clock_Reset(vlc_clock_t * clock);
+
+/**
+ * This function allows changing the pause status.
+ */
+void vlc_clock_ChangePause(vlc_clock_t * clock, bool paused,
+                           vlc_tick_t sysem_now);
+
+/**
+ * This function returns the current rate.
+ */
+float vlc_clock_GetRate(vlc_clock_t * clock);
+
+/**
+ * Wait for a timestamp expressed in stream time
+ */
+int vlc_clock_Wait(vlc_clock_t * clock, vlc_tick_t pts, 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 pts);
+
+/**
+ * This function converts a timestamp from system to stream time
+ */
+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
+ */
+void vlc_clock_SetDejitter(vlc_clock_t * clock, vlc_tick_t delay, int cr_avg);
+
+/**
+ * This function retrieves the synchronization delay
+ */
+vlc_tick_t vlc_clock_GetDejitter(vlc_clock_t * clock);
+
+#endif /*LIBVLC_CLOCK_H*/
diff --git a/src/clock/clock_internal.c b/src/clock/clock_internal.c
index 49711cbf01..b3cf44a02a 100644
--- a/src/clock/clock_internal.c
+++ b/src/clock/clock_internal.c
@@ -30,47 +30,52 @@
 /*****************************************************************************
  * Long term average helpers
  *****************************************************************************/
-void AvgInit( average_t *p_avg, int i_divider )
+void AvgInit(average_t *avg, int range)
 {
-    p_avg->i_divider = i_divider;
-    AvgReset( p_avg );
+    avg->range = range;
+    AvgReset(avg);
 }
 
-void AvgClean( average_t *p_avg )
+void AvgClean(average_t * avg)
 {
-    VLC_UNUSED(p_avg);
+    VLC_UNUSED(avg);
 }
 
-void AvgReset( average_t *p_avg )
+void AvgReset(average_t *avg)
 {
-    p_avg->i_value = 0;
-    p_avg->i_residue = 0;
-    p_avg->i_count = 0;
+    avg->value = 0.0f;
+    avg->count = 0;
 }
 
-void AvgUpdate( average_t *p_avg, vlc_tick_t i_value )
+void AvgUpdate(average_t *avg, float value)
 {
-    const int i_f0 = __MIN( p_avg->i_divider - 1, p_avg->i_count );
-    const int i_f1 = p_avg->i_divider - i_f0;
+    const int new_value_weight = 1;
+    int average_weight;
+    int divider;
+    if (avg->count < avg->range)
+    {
+        average_weight = avg->count++;
+        divider = avg->count;
+    }
+    else
+    {
+        average_weight = avg->range - 1;
+        divider = avg->range;
+    }
 
-    const vlc_tick_t i_tmp = i_f0 * p_avg->i_value + i_f1 * i_value + p_avg->i_residue;
-
-    p_avg->i_value   = i_tmp / p_avg->i_divider;
-    p_avg->i_residue = i_tmp % p_avg->i_divider;
-
-    p_avg->i_count++;
+    const float tmp = average_weight * avg->value + new_value_weight * value;
+    avg->value = tmp / divider;
 }
 
-vlc_tick_t AvgGet( average_t *p_avg )
+float AvgGet(average_t *avg)
 {
-    return p_avg->i_value;
+    return avg->value;
 }
 
-void AvgRescale( average_t *p_avg, int i_divider )
+void AvgRescale(average_t *avg, int range)
 {
-    const vlc_tick_t i_tmp = p_avg->i_value * p_avg->i_divider + p_avg->i_residue;
+    const float tmp = avg->value * avg->range;
 
-    p_avg->i_divider = i_divider;
-    p_avg->i_value   = i_tmp / p_avg->i_divider;
-    p_avg->i_residue = i_tmp % p_avg->i_divider;
+    avg->range = range;
+    avg->value = tmp / avg->range;
 }
diff --git a/src/clock/clock_internal.h b/src/clock/clock_internal.h
index 21da59c075..eeaab8cdca 100644
--- a/src/clock/clock_internal.h
+++ b/src/clock/clock_internal.h
@@ -20,6 +20,8 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
+#ifndef LIBVLC_CLOCK_INTERNAL_H
+#define LIBVLC_CLOCK_INTERNAL_H
 
 #include <vlc_common.h>
 
@@ -27,36 +29,38 @@
  * Structures
  *****************************************************************************/
 
- /**
- * This structure holds long term average
+/**
+ * This structure holds long term moving average
  */
 typedef struct
 {
-    vlc_tick_t i_value;
-    int     i_residue;
-
-    int     i_count;
-    int     i_divider;
+    float value; /* The average value */
+    int count; /* The number of sample evaluated */
+    int range; /* The maximum range of sample on which we calculate the average*/
 } average_t;
 
-void    AvgInit( average_t *, int i_divider );
-void    AvgClean( average_t * );
+void AvgInit(average_t *, int range);
+void AvgClean(average_t *);
+
+void AvgReset(average_t *);
+
+/*  calculates (previous_average * (range - 1) + new_value)/range */
+void AvgUpdate(average_t *, float value);
 
-void    AvgReset( average_t * );
-void    AvgUpdate( average_t *, vlc_tick_t i_value );
-vlc_tick_t AvgGet( average_t * );
-void    AvgRescale( average_t *, int i_divider );
+float AvgGet(average_t *);
+void AvgRescale(average_t *, int range);
 
 /* */
 typedef struct
 {
-    vlc_tick_t i_stream;
-    vlc_tick_t i_system;
+    vlc_tick_t stream;
+    vlc_tick_t system;
 } clock_point_t;
 
-static inline clock_point_t clock_point_Create( vlc_tick_t i_stream, vlc_tick_t i_system )
+static inline clock_point_t clock_point_Create( vlc_tick_t stream, vlc_tick_t system )
 {
-    clock_point_t p = { .i_stream = i_stream, .i_system = i_system };
+    clock_point_t p = { .stream = stream, .system = system };
     return p;
 }
 
+#endif /* LIBVLC_CLOCK_INTERNAL_H */
diff --git a/src/clock/input_clock.c b/src/clock/input_clock.c
index 247d78ddfa..f20fa532a3 100644
--- a/src/clock/input_clock.c
+++ b/src/clock/input_clock.c
@@ -216,9 +216,9 @@ void input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
         /* */
         b_reset_reference= true;
     }
-    else if( cl->last.i_stream != VLC_TS_INVALID &&
-             ( (cl->last.i_stream - i_ck_stream) > CR_MAX_GAP ||
-               (cl->last.i_stream - i_ck_stream) < -CR_MAX_GAP ) )
+    else if( cl->last.stream != VLC_TS_INVALID &&
+             ( (cl->last.stream - i_ck_stream) > CR_MAX_GAP ||
+               (cl->last.stream - i_ck_stream) < -CR_MAX_GAP ) )
     {
         /* Stream discontinuity, for which we haven't received a
          * warning from the stream control facilities (dd-edited
@@ -265,7 +265,7 @@ void input_clock_Update( input_clock_t *cl, vlc_object_t *p_log,
         /* Try to bufferize more than necessary by reading
          * CR_BUFFERING_RATE/256 faster until we have CR_BUFFERING_TARGET.
          */
-        const vlc_tick_t i_duration = __MAX( i_ck_stream - cl->last.i_stream, 0 );
+        const vlc_tick_t i_duration = __MAX( i_ck_stream - cl->last.stream, 0 );
 
         cl->i_buffering_duration += ( i_duration * CR_BUFFERING_RATE + 255 ) / 256;
         if( cl->i_buffering_duration > CR_BUFFERING_TARGET )
@@ -316,7 +316,7 @@ void input_clock_ChangeRate( input_clock_t *cl, int i_rate )
     {
         /* Move the reference point (as if we were playing at the new rate
          * from the start */
-        cl->ref.i_system = cl->last.i_system - (cl->last.i_system - cl->ref.i_system) * i_rate / cl->i_rate;
+        cl->ref.system = cl->last.system - (cl->last.system - cl->ref.system) * i_rate / cl->i_rate;
     }
     cl->i_rate = i_rate;
 
@@ -337,8 +337,8 @@ void input_clock_ChangePause( input_clock_t *cl, bool b_paused, vlc_tick_t i_dat
 
         if( cl->b_has_reference && i_duration > 0 )
         {
-            cl->ref.i_system += i_duration;
-            cl->last.i_system += i_duration;
+            cl->ref.system += i_duration;
+            cl->last.system += i_duration;
         }
     }
     cl->i_pause_date = i_date;
@@ -358,7 +358,7 @@ vlc_tick_t input_clock_GetWakeup( input_clock_t *cl )
 
     /* Synchronized, we can wait */
     if( cl->b_has_reference )
-        i_wakeup = ClockStreamToSystem( cl, cl->last.i_stream + AvgGet( &cl->drift ) - cl->i_buffering_duration );
+        i_wakeup = ClockStreamToSystem( cl, cl->last.stream + AvgGet( &cl->drift ) - cl->i_buffering_duration );
 
     vlc_mutex_unlock( &cl->lock );
 
@@ -450,11 +450,11 @@ int input_clock_GetState( input_clock_t *cl,
         return VLC_EGENERIC;
     }
 
-    *pi_stream_start = cl->ref.i_stream;
-    *pi_system_start = cl->ref.i_system;
+    *pi_stream_start = cl->ref.stream;
+    *pi_system_start = cl->ref.system;
 
-    *pi_stream_duration = cl->last.i_stream - cl->ref.i_stream;
-    *pi_system_duration = cl->last.i_system - cl->ref.i_system;
+    *pi_stream_duration = cl->last.stream - cl->ref.stream;
+    *pi_system_duration = cl->last.system - cl->ref.system;
 
     vlc_mutex_unlock( &cl->lock );
 
@@ -469,7 +469,7 @@ void input_clock_ChangeSystemOrigin( input_clock_t *cl, bool b_absolute, vlc_tic
     vlc_tick_t i_offset;
     if( b_absolute )
     {
-        i_offset = i_system - cl->ref.i_system - ClockGetTsOffset( cl );
+        i_offset = i_system - cl->ref.system - ClockGetTsOffset( cl );
     }
     else
     {
@@ -481,8 +481,8 @@ void input_clock_ChangeSystemOrigin( input_clock_t *cl, bool b_absolute, vlc_tic
         i_offset = i_system - cl->i_external_clock;
     }
 
-    cl->ref.i_system += i_offset;
-    cl->last.i_system += i_offset;
+    cl->ref.system += i_offset;
+    cl->last.system += i_offset;
 
     vlc_mutex_unlock( &cl->lock );
 }
@@ -493,7 +493,7 @@ void input_clock_GetSystemOrigin( input_clock_t *cl, vlc_tick_t *pi_system, vlc_
 
     assert( cl->b_has_reference );
 
-    *pi_system = cl->ref.i_system;
+    *pi_system = cl->ref.system;
     if( pi_delay )
         *pi_delay  = cl->i_pts_delay;
 
@@ -534,7 +534,7 @@ void input_clock_SetJitter( input_clock_t *cl,
     if( i_cr_average < 10 )
         i_cr_average = 10;
 
-    if( cl->drift.i_divider != i_cr_average )
+    if( cl->drift.range != i_cr_average )
         AvgRescale( &cl->drift, i_cr_average );
 
     vlc_mutex_unlock( &cl->lock );
@@ -570,8 +570,8 @@ static vlc_tick_t ClockStreamToSystem( input_clock_t *cl, vlc_tick_t i_stream )
     if( !cl->b_has_reference )
         return VLC_TS_INVALID;
 
-    return ( i_stream - cl->ref.i_stream ) * cl->i_rate / INPUT_RATE_DEFAULT +
-           cl->ref.i_system;
+    return ( i_stream - cl->ref.stream ) * cl->i_rate / INPUT_RATE_DEFAULT +
+           cl->ref.system;
 }
 
 /*****************************************************************************
@@ -582,8 +582,8 @@ static vlc_tick_t ClockStreamToSystem( input_clock_t *cl, vlc_tick_t i_stream )
 static vlc_tick_t ClockSystemToStream( input_clock_t *cl, vlc_tick_t i_system )
 {
     assert( cl->b_has_reference );
-    return ( i_system - cl->ref.i_system ) * INPUT_RATE_DEFAULT / cl->i_rate +
-            cl->ref.i_stream;
+    return ( i_system - cl->ref.system ) * INPUT_RATE_DEFAULT / cl->i_rate +
+            cl->ref.stream;
 }
 
 /**
-- 
2.18.0



More information about the vlc-devel mailing list