[vlc-devel] [PATCH v2 17/18] video_output: restart display after filter change

Steve Lhomme robux4 at ycbcr.xyz
Tue Nov 24 11:46:40 CET 2020


This is done in the vout thread loop, immediately after the filter output
change is detected, before processing pictures coming out of the filters. The
filters are untouched (not flushed).

The new display module is created with the format coming out of the last
filter.
---
 src/video_output/video_output.c | 106 ++++++++++++++++++++++++++++----
 1 file changed, 93 insertions(+), 13 deletions(-)

diff --git a/src/video_output/video_output.c b/src/video_output/video_output.c
index 8fb9b44764b..b01d70acb07 100644
--- a/src/video_output/video_output.c
+++ b/src/video_output/video_output.c
@@ -163,6 +163,7 @@ typedef struct vout_thread_sys_t
     vout_display_cfg_t display_cfg;
     vout_display_t *display;
     vlc_mutex_t     display_lock;
+    bool            display_restart; // only accessed in vout thread
 
     /* Video filter2 chain */
     struct {
@@ -942,9 +943,13 @@ typedef struct {
     config_chain_t *cfg;
 } vout_filter_t;
 
-static void ThreadChangeFilters(vout_thread_sys_t *vout)
+static bool ThreadChangeFilters(vout_thread_sys_t *vout)
 {
     vout_thread_sys_t *sys = vout;
+
+    es_format_t prev_es_fmt;
+    es_format_Copy(&prev_es_fmt, filter_chain_GetFmtOut(sys->filter.chain_interactive));
+
     ThreadFilterFlush(vout, true);
     ThreadDelAllFilterCallbacks(vout);
 
@@ -1034,20 +1039,20 @@ static void ThreadChangeFilters(vout_thread_sys_t *vout)
         vlc_array_clear(array);
     }
 
-    if (!es_format_IsSimilar(p_fmt_current, &fmt_target)) {
-        msg_Dbg(&vout->obj, "Adding a filter to compensate for format changes");
-        if (filter_chain_AppendConverter(sys->filter.chain_interactive,
-                                         &fmt_target) != 0) {
-            msg_Err(&vout->obj, "Failed to compensate for the format changes, removing all filters");
-            ThreadDelAllFilterCallbacks(vout);
-            filter_chain_Reset(sys->filter.chain_static,      &fmt_target, vctx_target, &fmt_target);
-            filter_chain_Reset(sys->filter.chain_interactive, &fmt_target, vctx_target, &fmt_target);
-        }
+    sys->filter.changed = false;
+
+    if (!es_format_IsSimilar(p_fmt_current, &prev_es_fmt)) {
+        // we need a new display+converter
+        msg_Dbg(&vout->obj, "filter output  format change detected");
+        es_format_Clean(&fmt_target);
+        es_format_Clean(&prev_es_fmt);
+        return true;
     }
 
     es_format_Clean(&fmt_target);
+    es_format_Clean(&prev_es_fmt);
 
-    sys->filter.changed = false;
+    return false;
 }
 
 
@@ -1068,7 +1073,12 @@ static bool ThreadDisplayPrerenderNext(vout_thread_sys_t *vout, bool reuse_decod
             sys->private.interlacing.has_deint != sys->filter.new_interlaced)
         {
             sys->private.interlacing.has_deint = sys->filter.new_interlaced;
-            ThreadChangeFilters(vout);
+            if (ThreadChangeFilters(vout))
+            {
+                // we can't use the display, trigger a restart
+                sys->display_restart = true;
+                break;
+            }
         }
 
         picture_t *decoded;
@@ -1139,7 +1149,7 @@ static bool ThreadDisplayPrerenderNext(vout_thread_sys_t *vout, bool reuse_decod
 
 
         if (sys->filter.changed)
-            continue; // filter+display update needed, we keep displayed.decoded
+            break; // filter+display update needed, we keep displayed.decoded
 
         picture_Hold(sys->displayed.decoded);
         picture = filter_chain_VideoFilter(sys->filter.chain_static, sys->displayed.decoded);
@@ -1535,6 +1545,8 @@ static int ThreadDisplayPicture(vout_thread_sys_t *vout, vlc_tick_t *deadline)
                         if (likely(pic_system_pts != INT64_MAX))
                             pic_render_deadline = pic_system_pts - render_delay;
                     }
+                    else if (sys->display_restart)
+                        return VLC_SUCCESS; // restart the display immediately
                 }
 
                 if (date_refresh == VLC_TICK_INVALID || pic_render_deadline < date_refresh)
@@ -1885,6 +1897,8 @@ error:
     return VLC_EGENERIC;
 }
 
+static void ThreadDisplayRestartDisplay(vout_thread_sys_t *);
+
 /*****************************************************************************
  * Thread: video output thread
  *****************************************************************************
@@ -1899,10 +1913,14 @@ static void *Thread(void *object)
 
     vlc_tick_t deadline = VLC_TICK_INVALID;
     bool wait = false;
+    sys->display_restart = false;
 
     for (;;) {
         vout_control_cmd_t cmd;
 
+        if (sys->display_restart)
+            ThreadDisplayRestartDisplay(vout);
+
         if (wait)
         {
             const vlc_tick_t max_deadline = vlc_tick_now() + VLC_TICK_FROM_MS(100);
@@ -2276,6 +2294,68 @@ static void vout_InitSource(vout_thread_sys_t *vout)
     }
 }
 
+static void ThreadDisplayRestartDisplay(vout_thread_sys_t *vout)
+{
+    vout_thread_sys_t *sys = vout;
+
+    vlc_mutex_lock(&sys->window_lock);
+
+    vout_display_cfg_t dcfg = sys->display_cfg;
+    int x = 0, y = 0, w = 0, h = 0;
+    vlc_rational_t dar = (vlc_rational_t) { sys->source.dar.num, sys->source.dar.den };
+    vlc_rational_t crop = {0};
+    switch (sys->source.crop.mode) {
+        case VOUT_CROP_NONE:
+            break;
+        case VOUT_CROP_RATIO:
+            crop = (vlc_rational_t) { sys->source.crop.ratio.num,
+                                      sys->source.crop.ratio.den };
+            break;
+        case VOUT_CROP_WINDOW:
+            x = sys->source.crop.window.x;
+            y = sys->source.crop.window.y;
+            w = sys->source.crop.window.width;
+            h = sys->source.crop.window.height;
+            break;
+        case VOUT_CROP_BORDER:
+            x = sys->source.crop.border.left;
+            y = sys->source.crop.border.top;
+            w = -(int)sys->source.crop.border.right;
+            h = -(int)sys->source.crop.border.bottom;
+            break;
+    }
+
+    vlc_mutex_lock(&sys->filter.lock);
+
+    const es_format_t *filter_out = filter_chain_GetFmtOut(sys->filter.chain_interactive);
+    vlc_video_context *vctx_out = filter_chain_GetVideoCtxOut(sys->filter.chain_interactive);
+
+#ifndef NDEBUG
+    if (vctx_out)
+    {
+        // make sure the decoder device we receive matches the one we have cached
+        vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(vctx_out);
+        assert(dec_device && dec_device == sys->dec_device);
+        vlc_decoder_device_Release(dec_device);
+    }
+#endif
+
+    vlc_mutex_unlock(&sys->window_lock);
+
+    if (likely(sys->display != NULL))
+        vout_ReleaseDisplay(sys);
+
+    vout_StartDisplayLocked(vout, &filter_out->video, vctx_out, &dcfg,
+                            &dar, &crop, x, y, h, w);
+
+    sys->displayed.current  = NULL;
+    sys->displayed.date     = VLC_TICK_INVALID;
+
+    vlc_mutex_unlock(&sys->filter.lock);
+
+    sys->display_restart = false;
+}
+
 int vout_Request(const vout_configuration_t *cfg, vlc_video_context *vctx, input_thread_t *input)
 {
     vout_thread_sys_t *vout = VOUT_THREAD_TO_SYS(cfg->vout);
-- 
2.26.2



More information about the vlc-devel mailing list