[vlc-devel] [PATCH 1/2] vout: add vout_Drain()

Thomas Guillem thomas at gllm.fr
Wed Mar 15 15:33:30 CET 2017


vout_Drain() asks the vout thread to drain its queued pictures. This function
will wait for the last picture to be displayed.

Refs #18105
---
 src/video_output/control.c       | 33 +++++++++++++++++++++++++++++++--
 src/video_output/control.h       |  4 ++++
 src/video_output/video_output.c  | 28 ++++++++++++++++++++++++++++
 src/video_output/vout_control.h  |  5 +++++
 src/video_output/vout_internal.h |  1 +
 5 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/src/video_output/control.c b/src/video_output/control.c
index bbdb8948eb..078c510450 100644
--- a/src/video_output/control.c
+++ b/src/video_output/control.c
@@ -64,6 +64,7 @@ void vout_control_Init(vout_control_t *ctrl)
     ctrl->is_dead = false;
     ctrl->can_sleep = true;
     ctrl->is_processing = false;
+    ctrl->is_draining = false;
     ARRAY_INIT(ctrl->cmd);
 }
 
@@ -98,15 +99,21 @@ void vout_control_WaitEmpty(vout_control_t *ctrl)
     vlc_mutex_unlock(&ctrl->lock);
 }
 
-void vout_control_Push(vout_control_t *ctrl, vout_control_cmd_t *cmd)
+static void vout_control_PushLocked(vout_control_t *ctrl,
+                                    vout_control_cmd_t *cmd)
 {
-    vlc_mutex_lock(&ctrl->lock);
     if (!ctrl->is_dead) {
         ARRAY_APPEND(ctrl->cmd, *cmd);
         vlc_cond_signal(&ctrl->wait_request);
     } else {
         vout_control_cmd_Clean(cmd);
     }
+}
+
+void vout_control_Push(vout_control_t *ctrl, vout_control_cmd_t *cmd)
+{
+    vlc_mutex_lock(&ctrl->lock);
+    vout_control_PushLocked(ctrl, cmd);
     vlc_mutex_unlock(&ctrl->lock);
 }
 
@@ -176,6 +183,28 @@ void vout_control_PushString(vout_control_t *ctrl, int type, const char *string)
     vout_control_Push(ctrl, &cmd);
 }
 
+void vout_control_Drained(vout_control_t *ctrl)
+{
+    vlc_mutex_lock(&ctrl->lock);
+    ctrl->is_draining = false;
+    vlc_cond_broadcast(&ctrl->wait_acknowledge);
+    vlc_mutex_unlock(&ctrl->lock);
+}
+
+void vout_control_Drain(vout_control_t *ctrl)
+{
+    vout_control_cmd_t cmd;
+
+    vout_control_cmd_Init(&cmd, VOUT_CONTROL_DRAIN);
+
+    vlc_mutex_lock(&ctrl->lock);
+    ctrl->is_draining = true;
+    vout_control_PushLocked(ctrl, &cmd);
+    while (ctrl->is_draining && !ctrl->is_dead)
+        vlc_cond_wait(&ctrl->wait_acknowledge, &ctrl->lock);
+    vlc_mutex_unlock(&ctrl->lock);
+}
+
 int vout_control_Pop(vout_control_t *ctrl, vout_control_cmd_t *cmd,
                      mtime_t deadline)
 {
diff --git a/src/video_output/control.h b/src/video_output/control.h
index 14eec3468d..c41a444aa6 100644
--- a/src/video_output/control.h
+++ b/src/video_output/control.h
@@ -48,6 +48,7 @@ enum {
 
     VOUT_CONTROL_PAUSE,
     VOUT_CONTROL_FLUSH,                 /* time */
+    VOUT_CONTROL_DRAIN,                 /* void */
     VOUT_CONTROL_STEP,                  /* time_ptr */
 
     VOUT_CONTROL_FULLSCREEN,            /* bool */
@@ -115,6 +116,7 @@ typedef struct {
     bool is_dead;
     bool can_sleep;
     bool is_processing;
+    bool is_draining;
     DECL_ARRAY(vout_control_cmd_t) cmd;
 } vout_control_t;
 
@@ -124,6 +126,7 @@ void vout_control_Clean(vout_control_t *);
 
 /* controls outside of the vout thread */
 void vout_control_WaitEmpty(vout_control_t *);
+void vout_control_Drain(vout_control_t *);
 
 void vout_control_Push(vout_control_t *, vout_control_cmd_t *);
 void vout_control_PushVoid(vout_control_t *, int type);
@@ -138,5 +141,6 @@ void vout_control_Wake(vout_control_t *);
 /* control inside of the vout thread */
 int vout_control_Pop(vout_control_t *, vout_control_cmd_t *, mtime_t deadline);
 void vout_control_Dead(vout_control_t *);
+void vout_control_Drained(vout_control_t *);
 
 #endif
diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 155d6a9e30..16e3704f7c 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -332,6 +332,11 @@ void vout_Flush(vout_thread_t *vout, mtime_t date)
     vout_control_WaitEmpty(&vout->p->control);
 }
 
+void vout_Drain(vout_thread_t *vout)
+{
+    vout_control_Drain(&vout->p->control);
+}
+
 bool vout_IsEmpty(vout_thread_t *vout)
 {
     picture_t *picture = picture_fifo_Peek(vout->p->decoder_fifo);
@@ -1067,6 +1072,25 @@ static int ThreadDisplayPicture(vout_thread_t *vout, mtime_t *deadline)
     const mtime_t date = mdate();
     const mtime_t render_delay = vout_chrono_GetHigh(&vout->p->render) + VOUT_MWAIT_TOLERANCE;
 
+    if (vout->p->draining && vout->p->displayed.next == NULL)
+    {
+        /* We reached the last picture to display */
+        if (vout->p->displayed.date <= VLC_TS_INVALID
+         || vout->p->displayed.date + render_delay <= date)
+        {
+            /* Notify the input (the caller of vout_Drain()) that the vout is
+             * drained */
+            vout_control_Drained(&vout->p->control);
+        }
+        else
+        {
+            /* Wait a little more before notifying the input, this function
+             * will be called again after the deadline. */
+            *deadline = vout->p->displayed.date + render_delay;
+        }
+        return VLC_EGENERIC;
+    }
+
     bool drop_next_frame = frame_by_frame;
     mtime_t date_next = VLC_TS_INVALID;
     if (!paused && vout->p->displayed.next) {
@@ -1450,6 +1474,7 @@ static void ThreadInit(vout_thread_t *vout)
     vout->p->is_late_dropped = var_InheritBool(vout, "drop-late-frames");
     vout->p->pause.is_on     = false;
     vout->p->pause.date      = VLC_TS_INVALID;
+    vout->p->draining        = false;
 
     vout_chrono_Init(&vout->p->render, 5, 10000); /* Arbitrary initial time */
 }
@@ -1571,6 +1596,9 @@ static int ThreadControl(vout_thread_t *vout, vout_control_cmd_t cmd)
     case VOUT_CONTROL_FLUSH:
         ThreadFlush(vout, false, cmd.u.time);
         break;
+    case VOUT_CONTROL_DRAIN:
+        vout->p->draining = true;
+        break;
     case VOUT_CONTROL_STEP:
         ThreadStep(vout, cmd.u.time_ptr);
         break;
diff --git a/src/video_output/vout_control.h b/src/video_output/vout_control.h
index 25bae8e9aa..e12b8eb169 100644
--- a/src/video_output/vout_control.h
+++ b/src/video_output/vout_control.h
@@ -50,6 +50,11 @@ void vout_GetResetStatistic( vout_thread_t *p_vout, unsigned *pi_displayed,
  */
 void vout_Flush( vout_thread_t *p_vout, mtime_t i_date );
 
+/**
+ * This function will wait for all queued pictures to be displayed.
+ */
+void vout_Drain( vout_thread_t *p_vout );
+
 /*
  * Cancel the vout, if cancel is true, it won't return any pictures after this
  * call.
diff --git a/src/video_output/vout_internal.h b/src/video_output/vout_internal.h
index fec54f38eb..b441786089 100644
--- a/src/video_output/vout_internal.h
+++ b/src/video_output/vout_internal.h
@@ -74,6 +74,7 @@ struct vout_thread_sys_t
     /* Thread & synchronization */
     vlc_thread_t    thread;
     bool            dead;
+    bool            draining;
     vout_control_t  control;
 
     /* */
-- 
2.11.0



More information about the vlc-devel mailing list