[vlc-commits] vout: use vlc_clock_t

Thomas Guillem git at videolan.org
Mon Mar 11 10:19:03 CET 2019


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Wed Mar  6 18:40:45 2019 +0100| [f2b2de861eec098e60d426d2bdfb448f1047e160] | committer: Thomas Guillem

vout: use vlc_clock_t

During the transition, the clock argument is not mandatory. If the clock is
NULL, the vout will use ts from the picture_t that were converted from the
decoder.

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

 src/clock/clock.c                |  72 ++++++++---------
 src/clock/clock.h                |  12 +--
 src/video_output/control.h       |   8 ++
 src/video_output/video_output.c  | 162 +++++++++++++++++++++++++++++++--------
 src/video_output/vout_internal.h |  32 ++++++++
 5 files changed, 212 insertions(+), 74 deletions(-)

diff --git a/src/clock/clock.c b/src/clock/clock.c
index 3fae6c9161..15a6cf68e4 100644
--- a/src/clock/clock.c
+++ b/src/clock/clock.c
@@ -38,7 +38,7 @@ struct vlc_clock_main_t
 
     /**
      * Linear function
-     * system = pts * coeff / rate + offset
+     * system = ts * coeff / rate + offset
      */
     clock_point_t last;
     average_t coeff_avg; /* Moving average to smooth out the instant coeff */
@@ -59,12 +59,12 @@ struct vlc_clock_main_t
 struct vlc_clock_t
 {
     vlc_tick_t (*update)(vlc_clock_t *clock, vlc_tick_t system_now,
-                         vlc_tick_t pts, double rate);
+                         vlc_tick_t ts, 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_tick_t ts, double rate);
 
     vlc_clock_main_t *owner;
     vlc_tick_t delay;
@@ -72,12 +72,12 @@ struct vlc_clock_t
 };
 
 static vlc_tick_t main_stream_to_system(vlc_clock_main_t *main_clock,
-                                        vlc_tick_t pts)
+                                        vlc_tick_t ts)
 {
     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);
+        (ts * main_clock->coeff / main_clock->rate + main_clock->offset);
 }
 
 static void vlc_clock_main_reset(vlc_clock_main_t *main_clock)
@@ -94,21 +94,21 @@ static void vlc_clock_main_reset(vlc_clock_main_t *main_clock)
 
 static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
                                           vlc_tick_t system_now,
-                                          vlc_tick_t pts, double rate)
+                                          vlc_tick_t ts, double rate)
 {
     vlc_clock_main_t *main_clock = clock->owner;
 
-    if (unlikely(pts == VLC_TICK_INVALID || system_now == VLC_TICK_INVALID))
+    if (unlikely(ts == VLC_TICK_INVALID || system_now == VLC_TICK_INVALID))
         return VLC_TICK_INVALID;
-    pts += clock->delay;
+    ts += clock->delay;
 
     vlc_mutex_lock(&main_clock->lock);
 
-    if (main_clock->offset != VLC_TICK_INVALID && pts != main_clock->last.stream)
+    if (main_clock->offset != VLC_TICK_INVALID && ts != 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);
+                             / (double)(ts - main_clock->last.stream);
         if (rate == main_clock->rate)
         {
             instant_coeff *= rate;
@@ -120,9 +120,9 @@ static vlc_tick_t vlc_clock_master_update(vlc_clock_t *clock,
         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->offset = system_now - ts * main_clock->coeff / rate;
 
-    main_clock->last = clock_point_Create(system_now, pts);
+    main_clock->last = clock_point_Create(system_now, ts);
 
     main_clock->rate = rate;
     vlc_cond_broadcast(&main_clock->cond);
@@ -196,7 +196,7 @@ static void vlc_clock_master_set_dejitter(vlc_clock_t *clock, vlc_tick_t delay)
 
 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_tick_t ts, double rate)
 {
     vlc_clock_main_t *main_clock = clock->owner;
 
@@ -208,7 +208,7 @@ vlc_clock_monotonic_to_system_locked(vlc_clock_t *clock, vlc_tick_t now,
          * - first PCR). */
         const vlc_tick_t pcr_delay =
             main_clock->first_pcr.system == VLC_TICK_INVALID ? 0 :
-            (pts - main_clock->first_pcr.stream) / rate +
+            (ts - main_clock->first_pcr.stream) / rate +
             main_clock->first_pcr.system - now;
 
         const vlc_tick_t input_delay = main_clock->input_dejitter + pcr_delay;
@@ -216,26 +216,26 @@ vlc_clock_monotonic_to_system_locked(vlc_clock_t *clock, vlc_tick_t now,
         const vlc_tick_t delay =
             __MAX(input_delay, main_clock->output_dejitter);
 
-        main_clock->wait_sync_ref = clock_point_Create(now + delay, pts);
+        main_clock->wait_sync_ref = clock_point_Create(now + delay, ts);
     }
-    return (pts - main_clock->wait_sync_ref.stream) / rate
+    return (ts - 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_tick_t ts, 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);
+    vlc_tick_t system = main_stream_to_system(main_clock, ts);
     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);
+        system = vlc_clock_monotonic_to_system_locked(clock, now, ts, rate);
     }
 
     return system + (clock->delay - main_clock->delay) * rate;
@@ -243,15 +243,15 @@ static vlc_tick_t vlc_clock_slave_to_system_locked(vlc_clock_t *clock,
 
 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_tick_t ts, double rate)
 {
     vlc_clock_main_t *main_clock = clock->owner;
-    vlc_tick_t system = main_stream_to_system(main_clock, pts);
+    vlc_tick_t system = main_stream_to_system(main_clock, ts);
     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);
+        system = vlc_clock_monotonic_to_system_locked(clock, now, ts, rate);
     }
 
     return system + clock->delay * rate;
@@ -259,12 +259,12 @@ static vlc_tick_t vlc_clock_master_to_system_locked(vlc_clock_t *clock,
 
 static vlc_tick_t vlc_clock_slave_update(vlc_clock_t *clock,
                                          vlc_tick_t system_now,
-                                         vlc_tick_t pts, double rate)
+                                         vlc_tick_t ts, 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_tick_t computed = clock->to_system_locked(clock, system_now, ts, rate);
     vlc_mutex_unlock(&main_clock->lock);
     return computed != INT64_MAX ? computed - system_now : VLC_TICK_INVALID;
 }
@@ -290,7 +290,7 @@ static vlc_tick_t vlc_clock_slave_set_delay(vlc_clock_t *clock, vlc_tick_t delay
     return 0;
 }
 
-int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t pts,
+int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t ts,
                    double rate, vlc_tick_t max_duration)
 {
     vlc_clock_main_t *main_clock = clock->owner;
@@ -303,7 +303,7 @@ int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t pts,
         if (main_clock->pause_date != VLC_TICK_INVALID)
             deadline = INT64_MAX;
         else
-            deadline = clock->to_system_locked(clock, system_now, pts, rate);
+            deadline = clock->to_system_locked(clock, system_now, ts, rate);
         deadline = __MIN(deadline, max_deadline);
 
         if (vlc_cond_timedwait(&main_clock->cond, &main_clock->lock, deadline))
@@ -374,12 +374,12 @@ 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)
+                                vlc_tick_t system_now, vlc_tick_t ts)
 {
     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->first_pcr = clock_point_Create(system_now, ts);
         main_clock->wait_sync_ref =
             clock_point_Create(VLC_TICK_INVALID, VLC_TICK_INVALID);
     }
@@ -433,9 +433,9 @@ void vlc_clock_main_Delete(vlc_clock_main_t *main_clock)
 }
 
 vlc_tick_t vlc_clock_Update(vlc_clock_t *clock, vlc_tick_t system_now,
-                            vlc_tick_t pts, double rate)
+                            vlc_tick_t ts, double rate)
 {
-    return clock->update(clock, system_now, pts, rate);
+    return clock->update(clock, system_now, ts, rate);
 }
 
 void vlc_clock_Reset(vlc_clock_t *clock)
@@ -449,24 +449,24 @@ vlc_tick_t vlc_clock_SetDelay(vlc_clock_t *clock, vlc_tick_t delay)
 }
 
 vlc_tick_t vlc_clock_ConvertToSystem(vlc_clock_t *clock, vlc_tick_t system_now,
-                                     vlc_tick_t pts, double rate)
+                                     vlc_tick_t ts, 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_tick_t system = clock->to_system_locked(clock, system_now, ts, 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,
+                                    vlc_tick_t *ts_array, size_t ts_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);
+    for (size_t i = 0; i < ts_count; ++i)
+        ts_array[i] = clock->to_system_locked(clock, system_now, ts_array[i],
+                                              rate);
     vlc_mutex_unlock(&main_clock->lock);
 }
 
diff --git a/src/clock/clock.h b/src/clock/clock.h
index 0088d89ebe..2261c6caa5 100644
--- a/src/clock/clock.h
+++ b/src/clock/clock.h
@@ -44,7 +44,7 @@ void vlc_clock_main_Abort(vlc_clock_main_t *main_clock);
 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);
+                                vlc_tick_t system_now, vlc_tick_t ts);
 void vlc_clock_main_SetInputDejitter(vlc_clock_main_t *main_clock,
                                      vlc_tick_t delay);
 
@@ -90,7 +90,7 @@ 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);
+                            vlc_tick_t ts, double rate);
 
 /**
  * This function resets the clock drift
@@ -103,25 +103,25 @@ void vlc_clock_Reset(vlc_clock_t *clock);
  * 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);
+vlc_tick_t vlc_clock_SetDelay(vlc_clock_t *clock, vlc_tick_t ts_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,
+int vlc_clock_Wait(vlc_clock_t *clock, vlc_tick_t system_now, vlc_tick_t ts,
                    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);
+                                     vlc_tick_t ts, 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,
+                                    vlc_tick_t *ts_array, size_t ts_count,
                                     double rate);
 
 /**
diff --git a/src/video_output/control.h b/src/video_output/control.h
index 9eb7ac32e3..46b78122e4 100644
--- a/src/video_output/control.h
+++ b/src/video_output/control.h
@@ -71,6 +71,14 @@ typedef struct {
             unsigned width;
             unsigned height;
         } window;
+        struct {
+            int channel;
+            float value;
+        } spu_rate;
+        struct {
+            int channel;
+            vlc_tick_t value;
+        } spu_delay;
         vlc_mouse_t mouse;
         vlc_viewpoint_t viewpoint;
     };
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 7aac04be46..3d75b15961 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -5,7 +5,7 @@
  * It includes functions allowing to open a new thread, send pictures to a
  * thread, and destroy a previously oppened video output thread.
  *****************************************************************************
- * Copyright (C) 2000-2007 VLC authors and VideoLAN
+ * Copyright (C) 2000-2019 VLC authors, VideoLAN and Videolabs SAS
  *
  * Authors: Vincent Seguin <seguin at via.ecp.fr>
  *          Gildas Bazin <gbazin at videolan.org>
@@ -55,6 +55,7 @@
 #include "snapshot.h"
 #include "window.h"
 #include "../misc/variables.h"
+#include "../clock/clock.h"
 
 /* Maximum delay between 2 displayed pictures.
  * XXX it is needed for now but should be removed in the long term.
@@ -268,6 +269,14 @@ int vout_RegisterSubpictureChannel( vout_thread_t *vout )
     return channel;
 }
 
+void vout_SetSubpictureClock( vout_thread_t *vout, vlc_clock_t *clock )
+{
+    vlc_mutex_lock(&vout->p->spu_lock);
+    if (vout->p->spu)
+        spu_clock_Set(vout->p->spu, clock);
+    vlc_mutex_unlock(&vout->p->spu_lock);
+}
+
 void vout_FlushSubpictureChannel( vout_thread_t *vout, int channel )
 {
     vout_thread_sys_t *sys = vout->p;
@@ -818,6 +827,7 @@ static void ThreadChangeFilters(vout_thread_t *vout,
 static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool frame_by_frame)
 {
     bool is_late_dropped = vout->p->is_late_dropped && !vout->p->pause.is_on && !frame_by_frame;
+    vout_thread_sys_t *sys = vout->p;
 
     vlc_mutex_lock(&vout->p->filter.lock);
 
@@ -830,15 +840,19 @@ static int ThreadDisplayPreparePicture(vout_thread_t *vout, bool reuse, bool fra
             decoded = picture_Hold(vout->p->displayed.decoded);
         } else {
             decoded = picture_fifo_Pop(vout->p->decoder_fifo);
+
             if (decoded) {
                 if (is_late_dropped && !decoded->b_force) {
+                    const vlc_tick_t date = vlc_tick_now();
+                    const vlc_tick_t system_pts = !vout->p->clock ? decoded->date :
+                        vlc_clock_ConvertToSystem(vout->p->clock, date,
+                                                  decoded->date, sys->rate);
+                    const vlc_tick_t late = date - system_pts;
                     vlc_tick_t late_threshold;
                     if (decoded->format.i_frame_rate && decoded->format.i_frame_rate_base)
                         late_threshold = VLC_TICK_FROM_MS(500) * decoded->format.i_frame_rate_base / decoded->format.i_frame_rate;
                     else
                         late_threshold = VOUT_DISPLAY_LATE_THRESHOLD;
-                    const vlc_tick_t predicted = vlc_tick_now() + 0; /* TODO improve */
-                    const vlc_tick_t late = predicted - decoded->date;
                     if (late > late_threshold) {
                         msg_Warn(vout, "picture is too late to be displayed (missing %"PRId64" ms)", MS_FROM_VLC_TICK(late));
                         picture_Release(decoded);
@@ -958,12 +972,15 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
      * Get the subpicture to be displayed
      */
     const bool do_snapshot = vout_snapshot_IsRequested(sys->snapshot);
+    vlc_tick_t system_now = vlc_tick_now();
     vlc_tick_t render_subtitle_date;
     if (sys->pause.is_on)
         render_subtitle_date = sys->pause.date;
     else
-        render_subtitle_date = filtered->date > 1 ? filtered->date : vlc_tick_now();
-    vlc_tick_t system_now = vlc_tick_now();
+        render_subtitle_date = filtered->date <= 1 ? system_now :
+            !sys->clock ? filtered->date :
+            vlc_clock_ConvertToSystem(sys->clock, system_now, filtered->date,
+                                      sys->rate);
 
     /*
      * Get the subpicture to be displayed
@@ -1025,9 +1042,8 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
     subpicture_t *subpic = spu_Render(sys->spu,
                                       subpicture_chromas, &fmt_spu_rot,
                                       &vd->source, system_now,
-                                      render_subtitle_date,
-                                      1.f, do_snapshot,
-                                      vd->info.can_scale_spu);
+                                      render_subtitle_date, sys->spu_rate,
+                                      do_snapshot, vd->info.can_scale_spu);
     /*
      * Perform rendering
      *
@@ -1089,8 +1105,13 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
     if (!do_dr_spu && sys->spu_blend != NULL && subpic != NULL)
         picture_BlendSubpicture(todisplay, sys->spu_blend, subpic);
 
+    system_now = vlc_tick_now();
+    const vlc_tick_t pts = todisplay->date;
+    const vlc_tick_t system_pts = !sys->clock ? pts :
+        vlc_clock_ConvertToSystem(sys->clock, system_now, pts, sys->rate);
+
     if (vd->prepare != NULL)
-        vd->prepare(vd, todisplay, do_dr_spu ? subpic : NULL, todisplay->date);
+        vd->prepare(vd, todisplay, do_dr_spu ? subpic : NULL, system_pts);
 
     vout_chrono_Stop(&sys->render);
 #if 0
@@ -1102,21 +1123,33 @@ static int ThreadDisplayRenderPicture(vout_thread_t *vout, bool is_forced)
         }
 #endif
 
-    /* Wait the real date (for rendering jitter) */
-#if 0
-    vlc_tick_t delay = todisplay->date - vlc_tick_now();
-    if (delay < 1000)
-        msg_Warn(vout, "picture is late (%"PRId64" ms)", delay / 1000);
-#endif
     if (!is_forced)
-        vlc_tick_wait(todisplay->date);
+    {
+        if (sys->clock)
+        {
+            system_now = vlc_tick_now();
+            vlc_clock_Wait(sys->clock, system_now, pts, sys->rate,
+                           VOUT_REDISPLAY_DELAY);
+        }
+        else
+            vlc_tick_wait(pts);
+    }
 
     /* Display the direct buffer returned by vout_RenderPicture */
-    sys->displayed.date = vlc_tick_now();
     vout_display_Display(vd, todisplay);
     if (subpic)
         subpicture_Delete(subpic);
 
+    if (!is_forced && sys->clock)
+    {
+        system_now = vlc_tick_now();
+        const vlc_tick_t drift = vlc_clock_Update(sys->clock, system_now,
+                                                  pts, sys->rate);
+        if (drift != VLC_TICK_INVALID)
+            system_now += drift;
+    }
+    sys->displayed.date = system_now;
+
     vout_statistic_AddDisplayed(&sys->statistic, 1);
 
     return VLC_SUCCESS;
@@ -1137,14 +1170,19 @@ static int ThreadDisplayPicture(vout_thread_t *vout, vlc_tick_t *deadline)
         while (!sys->displayed.next && !ThreadDisplayPreparePicture(vout, false, frame_by_frame))
             ;
 
-    const vlc_tick_t date = vlc_tick_now();
+    const vlc_tick_t system_now = vlc_tick_now();
     const vlc_tick_t render_delay = vout_chrono_GetHigh(&sys->render) + VOUT_MWAIT_TOLERANCE;
 
     bool drop_next_frame = frame_by_frame;
     vlc_tick_t date_next = VLC_TICK_INVALID;
+
     if (!paused && sys->displayed.next) {
-        date_next = sys->displayed.next->date - render_delay;
-        if (date_next /* + 0 FIXME */ <= date)
+        const vlc_tick_t next_system_pts = !sys->clock ? sys->displayed.next->date :
+            vlc_clock_ConvertToSystem(sys->clock, system_now,
+                                      sys->displayed.next->date, sys->rate);
+
+        date_next = next_system_pts - render_delay;
+        if (date_next <= system_now)
             drop_next_frame = true;
     }
 
@@ -1162,7 +1200,7 @@ static int ThreadDisplayPicture(vout_thread_t *vout, vlc_tick_t *deadline)
     vlc_tick_t date_refresh = VLC_TICK_INVALID;
     if (sys->displayed.date != VLC_TICK_INVALID) {
         date_refresh = sys->displayed.date + VOUT_REDISPLAY_DELAY - render_delay;
-        refresh = date_refresh <= date;
+        refresh = date_refresh <= vlc_tick_now();
     }
     bool force_refresh = !drop_next_frame && refresh;
 
@@ -1197,17 +1235,20 @@ void vout_ChangePause(vout_thread_t *vout, bool is_paused, vlc_tick_t date)
     assert(!vout->p->pause.is_on || !is_paused);
 
     if (vout->p->pause.is_on) {
-        const vlc_tick_t duration = date - vout->p->pause.date;
-
-        if (vout->p->step.timestamp != VLC_TICK_INVALID)
-            vout->p->step.timestamp += duration;
-        if (vout->p->step.last != VLC_TICK_INVALID)
-            vout->p->step.last += duration;
-        picture_fifo_OffsetDate(vout->p->decoder_fifo, duration);
-        if (vout->p->displayed.decoded)
-            vout->p->displayed.decoded->date += duration;
-        spu_OffsetSubtitleDate(vout->p->spu, duration);
-
+        if (!vout->p->clock)
+        {
+            const vlc_tick_t duration = date - vout->p->pause.date;
+
+            if (vout->p->step.timestamp != VLC_TICK_INVALID)
+                vout->p->step.timestamp += duration;
+            if (vout->p->step.last != VLC_TICK_INVALID)
+                vout->p->step.last += duration;
+            picture_fifo_OffsetDate(vout->p->decoder_fifo, duration);
+            if (vout->p->displayed.decoded)
+                vout->p->displayed.decoded->date += duration;
+            spu_OffsetSubtitleDate(vout->p->spu, duration);
+        }
+ 
         ThreadFilterFlush(vout, false);
     } else {
         vout->p->step.timestamp = VLC_TICK_INVALID;
@@ -1245,6 +1286,20 @@ static void vout_FlushUnlocked(vout_thread_t *vout, bool below,
 
     picture_fifo_Flush(vout->p->decoder_fifo, date, below);
     vout_FilterFlush(vout->p->display);
+
+    if (vout->p->clock)
+    {
+        vlc_clock_Reset(vout->p->clock);
+        vlc_clock_SetDelay(vout->p->clock, vout->p->delay);
+    }
+
+    vlc_mutex_lock(&vout->p->spu_lock);
+    if (vout->p->spu)
+    {
+        spu_clock_Reset(vout->p->spu);
+        spu_clock_SetDelay(vout->p->spu, vout->p->spu_delay);
+    }
+    vlc_mutex_unlock(&vout->p->spu_lock);
 }
 
 void vout_Flush(vout_thread_t *vout, vlc_tick_t date)
@@ -1277,6 +1332,42 @@ void vout_NextPicture(vout_thread_t *vout, vlc_tick_t *duration)
     vout_control_Release(&vout->p->control);
 }
 
+void vout_ChangeDelay(vout_thread_t *vout, vlc_tick_t delay)
+{
+    vout_thread_sys_t *sys = vout->p;
+
+    vout_control_Hold(&sys->control);
+    if (vout->p->clock)
+        vlc_clock_SetDelay(vout->p->clock, delay);
+    vout->p->delay = delay;
+    vout_control_Release(&sys->control);
+}
+
+void vout_ChangeRate(vout_thread_t *vout, float rate)
+{
+    vout_thread_sys_t *sys = vout->p;
+
+    vout_control_Hold(&sys->control);
+    sys->rate = rate;
+    vout_control_Release(&sys->control);
+}
+
+void vout_ChangeSpuDelay(vout_thread_t *vout, vlc_tick_t delay)
+{
+    vlc_mutex_lock(&vout->p->spu_lock);
+    if (vout->p->spu)
+        spu_clock_SetDelay(vout->p->spu, delay);
+    vout->p->spu_delay = delay;
+    vlc_mutex_unlock(&vout->p->spu_lock);
+}
+
+void vout_ChangeSpuRate(vout_thread_t *vout, float rate)
+{
+    vlc_mutex_lock(&vout->p->spu_lock);
+    vout->p->spu_rate = rate;
+    vlc_mutex_unlock(&vout->p->spu_lock);
+}
+
 static void ThreadProcessMouseState(vout_thread_t *vout,
                                     const vlc_mouse_t *win_mouse)
 {
@@ -1587,6 +1678,7 @@ static void vout_StopDisplay(vout_thread_t *vout)
 
     spu_Detach(sys->spu);
     sys->mouse_event = NULL;
+    sys->clock = NULL;
     video_format_Clean(&sys->original);
 }
 
@@ -1788,6 +1880,12 @@ int vout_Request(const vout_configuration_t *cfg, input_thread_t *input)
         sys->window_active = true;
     } else
         vout_UpdateWindowSize(vout);
+
+    sys->delay = sys->spu_delay = 0;
+    sys->rate = sys->spu_rate = 1.f;
+    sys->clock = cfg->clock;
+    sys->delay = sys->spu_delay = 0;
+
     vlc_mutex_unlock(&vout->p->window_lock);
 
     if (vout_Start(vout, cfg)
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index 59da8d95cd..b43d323fb0 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -45,6 +45,7 @@
  */
 typedef struct {
     vout_thread_t        *vout;
+    vlc_clock_t          *clock;
     const video_format_t *fmt;
     unsigned             dpb_size;
     vlc_mouse_event      mouse_event;
@@ -64,6 +65,12 @@ struct vout_thread_sys_t
     /* Splitter module if used */
     char            *splitter_name;
 
+    vlc_clock_t     *clock;
+    float           rate;
+    float           spu_rate;
+    vlc_tick_t      delay;
+    vlc_tick_t      spu_delay;
+
     /* */
     video_format_t  original;   /* Original format ie coming from the decoder */
     struct {
@@ -241,6 +248,7 @@ int vout_OpenWrapper(vout_thread_t *, const char *,
 void vout_CloseWrapper(vout_thread_t *);
 
 /* */
+void vout_SetSubpictureClock(vout_thread_t *vout, vlc_clock_t *clock);
 int spu_ProcessMouse(spu_t *, const vlc_mouse_t *, const video_format_t *);
 void spu_Attach( spu_t *, input_thread_t *input );
 void spu_Detach( spu_t * );
@@ -257,6 +265,30 @@ void spu_SetHighlight(spu_t *, const vlc_spu_highlight_t*);
 void vout_ChangePause( vout_thread_t *, bool b_paused, vlc_tick_t i_date );
 
 /**
+ * This function will change the rate of the vout
+ * It is thread safe
+ */
+void vout_ChangeRate( vout_thread_t *, float rate );
+
+/**
+ * This function will change the delay of the vout
+ * It is thread safe
+ */
+void vout_ChangeDelay( vout_thread_t *, vlc_tick_t delay );
+
+/**
+ * This function will change the rate of the spu channel
+ * It is thread safe
+ */
+void vout_ChangeSpuRate( vout_thread_t *, float rate );
+/**
+ * This function will change the delay of the spu channel
+ * It is thread safe
+ */
+void vout_ChangeSpuDelay( vout_thread_t *, vlc_tick_t delay );
+
+
+/**
  * Updates the pointing device state.
  */
 void vout_MouseState(vout_thread_t *, const vlc_mouse_t *);



More information about the vlc-commits mailing list