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

Steve Lhomme robux4 at ycbcr.xyz
Mon Nov 23 13:17:14 CET 2020


On 2020-11-20 21:12, Thomas Guillem wrote:
> 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?

Yes, they are not exclusive. I don't understand the problem.

The decoded picture causes a format change (AR/crop changes). It's kept 
as decoded and filters are recreated. Based on the filter output, if it 
differs from what the display expects, the display is restarted.

Only then the decoded picture is passed through the filters and then fed 
to the (new) display.

> 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
> _______________________________________________
> 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