[vlc-devel] [PATCH 01/11] vout: trigger filters commands

Rémi Denis-Courmont remi at remlab.net
Mon May 29 19:23:01 CEST 2017


Le maanantaina 29. toukokuuta 2017, 18.52.55 EEST Thomas Guillem a écrit :
> ---
>  src/video_output/video_output.c  | 94
> +++++++++++++++++++++++++++++++++++++++- src/video_output/vout_internal.h |
>  1 +
>  2 files changed, 94 insertions(+), 1 deletion(-)
> 
> diff --git a/src/video_output/video_output.c
> b/src/video_output/video_output.c index 730b902b24..a1d3ec1911 100644
> --- a/src/video_output/video_output.c
> +++ b/src/video_output/video_output.c
> @@ -46,12 +46,14 @@
>  #include <vlc_spu.h>
>  #include <vlc_vout_osd.h>
>  #include <vlc_image.h>
> +#include <vlc_plugin.h>
> 
>  #include <libvlc.h>
>  #include "vout_internal.h"
>  #include "interlacing.h"
>  #include "display.h"
>  #include "window.h"
> +#include "../modules/modules.h"
> 
>  /**************************************************************************
> *** * Local prototypes
> @@ -140,6 +142,8 @@ static vout_thread_t *VoutCreate(vlc_object_t *object,
> 
>      vout_snapshot_Init(&vout->p->snapshot);
> 
> +    vlc_array_init(&vout->p->filter.callbacks);
> +
>      /* Initialize locks */
>      vlc_mutex_init(&vout->p->filter.lock);
>      vlc_mutex_init(&vout->p->spu_lock);
> @@ -649,6 +653,85 @@ int vout_HideWindowMouse(vout_thread_t *vout, bool
> hide) }
> 
>  /* */
> +struct filter_callback
> +{
> +    filter_t *  filter;
> +    const char *psz_name;
> +    int         type;

You should not need to track the type. Just use var_Set().

> +};
> +
> +static int FilterProxyCallback(vlc_object_t *p_this, char const *psz_var,
> +                         vlc_value_t oldval, vlc_value_t newval,
> +                         void *p_data)
> +{
> +    (void) p_this; (void) oldval;
> +    struct filter_callback *callback = p_data;
> +    var_SetChecked(callback->filter, psz_var, callback->type, newval);
> +    return 0;
> +}
> +
> +static void ThreadDelFilterCallbacks(vout_thread_t *vout)
> +{
> +    for (size_t i = 0; i < vlc_array_count(&vout->p->filter.callbacks);
> ++i) +    {
> +        struct filter_callback *callback =
> +            vlc_array_item_at_index(&vout->p->filter.callbacks, i);
> +        var_DelCallback(vout, callback->psz_name, FilterProxyCallback,
> callback);
> +        var_Destroy(vout, callback->psz_name);
> +        free(callback);
> +    }
> +    vlc_array_clear(&vout->p->filter.callbacks);
> +}
> +
> +static int ThreadAddFilterCallbacks(vout_thread_t *vout, filter_t *filter)
> +{
> +    /* Duplicate every command variables from the filter to the vout, and
> add a +     * proxy callback to trigger filters events from the vout. */ +
> +    vlc_plugin_t *plugin = filter->p_module->plugin;
> +    for (size_t i = 0; i < plugin->conf.size; ++i)
> +    {
> +        module_config_t *config = &plugin->conf.items[i];
> +        switch (config->i_type)
> +        {
> +            case CONFIG_ITEM_FLOAT:
> +            case CONFIG_ITEM_INTEGER:
> +            case CONFIG_ITEM_BOOL:
> +            case CONFIG_ITEM_STRING:
> +                break;
> +            default:
> +                continue;
> +        }

> +        int var_type = var_Type(filter, config->psz_name);

AFAIK, a specific filter instance might not register a callback, or even 
create a variable at all, out of a given configuration item of the module that 
is was intantiated from. Also conversely, it might create a variable and 
register a callback for an item from another module. And finally, this will 
not preserve limits and what-not, such as if var_Change() is used.

If you want to use introspection to avoid patching all filters, you are most 
probably better off introspecting the filter object variables than the module 
items.

> +        if (var_type & VLC_VAR_ISCOMMAND)
> +        {
> +#ifndef NDEBUG
> +            /* Make sure that each option is unique */
> +            for (size_t i = 0; i <
> vlc_array_count(&vout->p->filter.callbacks);
> +                 ++i)
> +            {
> +                struct filter_callback *callback =
> +                    vlc_array_item_at_index(&vout->p->filter.callbacks, i);
> +                assert(strcmp(callback->psz_name, config->psz_name) != 0);
> +            }
> +#endif
> +            struct filter_callback *callback = malloc(sizeof(*callback));
> +            if (unlikely(callback == NULL))
> +                return VLC_ENOMEM;
> +
> +            callback->filter = filter;
> +            callback->psz_name = config->psz_name;
> +            callback->type = var_type & VLC_VAR_CLASS;
> +            vlc_array_append(&vout->p->filter.callbacks, callback);
> +
> +            var_Create(vout, callback->psz_name, var_type |
> VLC_VAR_DOINHERIT);
> +            var_AddCallback(vout, callback->psz_name,
> FilterProxyCallback,
> +                            callback);

Note that this will inherit the same race conditions as vlc_object_find_name() 
had. Also I don´t know what would happen if a filter removed a variable before 
deactivation.

This is acceptable for the GUI, since it is not a regression there. But it 
would not scale up to programmatic use through LibVLC.

> +        }
> +    }
> +    return VLC_SUCCESS;
> +}
> +
>  static picture_t *VoutVideoFilterInteractiveNewPicture(filter_t *filter)
>  {
>      vout_thread_t *vout = filter->owner.sys;
> @@ -702,6 +785,7 @@ static void ThreadChangeFilters(vout_thread_t *vout,
>                                  bool is_locked)
>  {
>      ThreadFilterFlush(vout, is_locked);
> +    ThreadDelFilterCallbacks(vout);
> 
>      vlc_array_t array_static;
>      vlc_array_t array_interactive;
> @@ -770,10 +854,16 @@ static void ThreadChangeFilters(vout_thread_t *vout,
>          for (size_t i = 0; i < vlc_array_count(array); i++) {
>              vout_filter_t *e = vlc_array_item_at_index(array, i);
>              msg_Dbg(vout, "Adding '%s' as %s", e->name, a == 0 ? "static" :
> "interactive"); -            if (!filter_chain_AppendFilter(chain, e->name,
> e->cfg, NULL, NULL)) { +            filter_t *filter =
> filter_chain_AppendFilter(chain, e->name, e->cfg, +                        
>       NULL, NULL);
> +            if (filter)
> +                ThreadAddFilterCallbacks(vout, filter);
> +            else
> +            {
>                  msg_Err(vout, "Failed to add filter '%s'", e->name);
>                  config_ChainDestroy(e->cfg);
>              }
> +
>              free(e->name);
>              free(e);
>          }
> @@ -1429,6 +1519,7 @@ static int ThreadStart(vout_thread_t *vout,
> vout_display_state_t *state) video_format_Print(VLC_OBJECT(vout), "original
> format", &vout->p->original); return VLC_SUCCESS;
>  error:
> +    ThreadDelFilterCallbacks(vout);
>      if (vout->p->filter.chain_interactive != NULL)
>          filter_chain_Delete(vout->p->filter.chain_interactive);
>      if (vout->p->filter.chain_static != NULL)
> @@ -1454,6 +1545,7 @@ static void ThreadStop(vout_thread_t *vout,
> vout_display_state_t *state) }
> 
>      /* Destroy the video filters2 */
> +    ThreadDelFilterCallbacks(vout);
>      filter_chain_Delete(vout->p->filter.chain_interactive);
>      filter_chain_Delete(vout->p->filter.chain_static);
>      video_format_Clean(&vout->p->filter.format);
> diff --git a/src/video_output/vout_internal.h
> b/src/video_output/vout_internal.h index 400bcb8b61..cb64544d3d 100644
> --- a/src/video_output/vout_internal.h
> +++ b/src/video_output/vout_internal.h
> @@ -125,6 +125,7 @@ struct vout_thread_sys_t
>          struct filter_chain_t *chain_static;
>          struct filter_chain_t *chain_interactive;
>          bool            has_deint;
> +        vlc_array_t     callbacks;
>      } filter;
> 
>      /* */


-- 
雷米‧德尼-库尔蒙
https://www.remlab.net/



More information about the vlc-devel mailing list