[vlc-devel] [PATCH 07/18] vout: use vlc_clock_t

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


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.
---
 src/video_output/control.h       |   8 ++
 src/video_output/video_output.c  | 162 +++++++++++++++++++++++++------
 src/video_output/vout_internal.h |  32 ++++++
 3 files changed, 170 insertions(+), 32 deletions(-)

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 * );
@@ -256,6 +264,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.
  */
-- 
2.20.1



More information about the vlc-devel mailing list