[vlc-devel] [PATCH 17/17] video_output: restart display after filter change
Steve Lhomme
robux4 at ycbcr.xyz
Fri Nov 20 15:45:07 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 563a7b18122..d83c859adfb 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_ReleaseDisplayAlone(sys);
+
+ vout_StartDisplayAloneLocked(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