[vlc-devel] [PATCH 17/17] video_output: restart display after filter change
Thomas Guillem
thomas at gllm.fr
Fri Nov 20 21:12:57 CET 2020
Your commit log say that it is restarted when the filter format change.
Looking at the diff, the display is actually restarted before displaying the picture that need a format change, am I right?
On Fri, Nov 20, 2020, at 15:45, Steve Lhomme wrote:
> 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
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
More information about the vlc-devel
mailing list