<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="generator" content="pandoc" />
  <title></title>
  <style type="text/css">code{white-space: pre;}</style>
</head>
<body>
<p>Hi Steve,</p>
<p>I am not sure what the status for this patch is after <em>Remi’s</em> comments, I however wrote my reply prior to noticing that there was an on-going discussion, so I will send it to <code>vlc-devel</code> in either case.</p>
<p>On 2017-05-05 10:14, Steve Lhomme wrote:</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> Fixes #18078
 ---
  modules/MODULES_LIST             |   1 +
  modules/video_filter/Makefile.am |   5 +-
  modules/video_filter/chain.c     | 216 +++++++++++++++++++++++++++++++++++++++
  3 files changed, 221 insertions(+), 1 deletion(-)
  create mode 100644 modules/video_filter/chain.c

 diff --git a/modules/MODULES_LIST b/modules/MODULES_LIST
 index 3205a0850b..b1d17da830 100644
 --- a/modules/MODULES_LIST
 +++ b/modules/MODULES_LIST
 @@ -144,6 +144,7 @@ $Id$
   * file_keystore: store secrets on a file, may use a submodule to crypt secrets
   * file_logger: file logger plugin
   * filesystem: Filesystem access module
 + * filterchain: Video filtering using intermediate converter modules
   * fingerprinter: AcoustID audio fingerprinter using chromaprint
   * flac: Flac decoder using libflac
   * flacsys: FLAC demuxer
 diff --git a/modules/video_filter/Makefile.am b/modules/video_filter/Makefile.am
 index 8fcc93c4db..bf4b9ce9ad 100644
 --- a/modules/video_filter/Makefile.am
 +++ b/modules/video_filter/Makefile.am
 @@ -67,6 +67,8 @@ libvhs_plugin_la_SOURCES = video_filter/vhs.c
  libwave_plugin_la_SOURCES = video_filter/wave.c
  libwave_plugin_la_LIBADD = $(LIBM)

 +libfilterchain_plugin_la_SOURCES = video_filter/chain.c
 +
  video_filter_LTLIBRARIES = \
      libadjust_plugin.la \
      libalphamask_plugin.la \
 @@ -105,7 +107,8 @@ video_filter_LTLIBRARIES = \
      libfps_plugin.la \
      libfreeze_plugin.la \
      libpuzzle_plugin.la \
 -    librotate_plugin.la
 +    librotate_plugin.la \
 +    libfilterchain_plugin.la

  libdeinterlace_plugin_la_SOURCES = \
      video_filter/deinterlace/deinterlace.c video_filter/deinterlace/deinterlace.h \
 diff --git a/modules/video_filter/chain.c b/modules/video_filter/chain.c
 new file mode 100644
 index 0000000000..b9ab7083e8
 --- /dev/null
 +++ b/modules/video_filter/chain.c
 @@ -0,0 +1,216 @@
 +/*****************************************************************************
 + * chain.c : chain multiple video filter modules as a last resort solution
 + *****************************************************************************
 + * Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
 + * $Id$
 + *
 + * Authors: Steve Lhomme <robux4@videolabs.io>
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms of the GNU Lesser General Public License as published by
 + * the Free Software Foundation; either version 2.1 of the License, or
 + * (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 + * GNU Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 + *****************************************************************************/
 +
 +/*****************************************************************************
 + * Preamble
 + *****************************************************************************/
 +
 +#ifdef HAVE_CONFIG_H
 +# include "config.h"
 +#endif
 +
 +#include <vlc_common.h>
 +#include <vlc_plugin.h>
 +#include <vlc_filter.h>
 +#include <vlc_picture.h>
 +
 +/*****************************************************************************
 + * Local prototypes.
 + *****************************************************************************/
 +static const vlc_fourcc_t pi_allowed_chromas[] = {
 +    VLC_CODEC_I420,
 +    VLC_CODEC_I422,
 +    VLC_CODEC_I420_10L,
 +    VLC_CODEC_I420_16L,
 +    VLC_CODEC_RGB32,
 +    VLC_CODEC_RGB24,
 +    0
 +};
 +
 +struct filter_sys_t
 +{
 +    filter_chain_t *p_chain;
 +};
 +
 +/*****************************************************************************
 + * Buffer management
 + *****************************************************************************/
 +static picture_t *BufferNew( filter_t *p_filter )
 +{
 +    filter_t *p_parent = p_filter->owner.sys;
 +
 +    return filter_NewPicture( p_parent );
 +}
 +
 +#define CHAIN_LEVEL_MAX 1
 +#define RECURSIVE_STRING (MODULE_STRING "-flevel")
 +
 +/*****************************************************************************
 + * Builders
 + *****************************************************************************/
 +
 +static int BuildShortcutChain( filter_t *p_filter )
 +{
 +    es_format_t fmt_mid;
 +    int i_ret = VLC_EGENERIC;
 +
 +    /* Now try chroma format list */
 +    for( int i = 0; pi_allowed_chromas[i]; i++ )
 +    {
 +        filter_chain_Reset( p_filter->p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out );
 +
 +        const vlc_fourcc_t i_chroma = pi_allowed_chromas[i];
 +        if( i_chroma == p_filter->fmt_in.i_codec ||
 +            i_chroma == p_filter->fmt_out.i_codec )
 +            continue;
 +
 +        msg_Dbg( p_filter, "Trying to use chroma %4.4s as middle man",
 +                 (char*)&i_chroma );
 +
 +        es_format_Copy( &fmt_mid, &p_filter->fmt_in );
 +        fmt_mid.i_codec        =
 +        fmt_mid.video.i_chroma = i_chroma;
 +        fmt_mid.video.i_rmask  = 0;
 +        fmt_mid.video.i_gmask  = 0;
 +        fmt_mid.video.i_bmask  = 0;
 +        video_format_FixRgb(&fmt_mid.video);
 +
 +        if( filter_chain_AppendConverter( p_filter->p_sys->p_chain,
 +                                          NULL, &fmt_mid ) == VLC_SUCCESS )
 +        {
 +            filter_t *found = filter_chain_AppendFilter( p_filter->p_sys->p_chain,
 +                                                         p_filter->shortcut,
 +                                                         p_filter->p_cfg, &fmt_mid,
 +                                                         &fmt_mid, true );
 +            if (found != NULL)
 +            {
 +                if ( p_filter->b_allow_fmt_out_change ||
 +                     filter_chain_AppendConverter(p_filter->p_sys->p_chain, &fmt_mid,
 +                                                  &p_filter->fmt_out) == VLC_SUCCESS)
 +                {
 +                    es_format_Clean( &fmt_mid );
 +                    i_ret = VLC_SUCCESS;
 +                    break;
 +                }
 +            }
 +        }
 +        es_format_Clean( &fmt_mid );
 +    }
 +    if (i_ret != VLC_SUCCESS)
 +        filter_chain_Reset( p_filter->p_sys->p_chain, &p_filter->fmt_in, &p_filter->fmt_out );
 +
 +    var_Destroy( p_filter, RECURSIVE_STRING );
 +    return i_ret;
 +}
 +
 +/*****************************************************************************
 + * Chain
 + *****************************************************************************/
 +static picture_t *Chain( filter_t *p_filter, picture_t *p_pic )
 +{
 +    return filter_chain_VideoFilter( p_filter->p_sys->p_chain, p_pic );
 +}
 +
 +/*****************************************************************************
 + * Activate: allocate a chroma function
 + *****************************************************************************
 + * This function allocates and initializes a chroma function
 + *****************************************************************************/</code></pre>
</blockquote>
<p>Doxygen comments?</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +static int Activate( vlc_object_t *p_this )
 +{
 +    filter_t *p_filter = (filter_t *)p_this;
 +    filter_sys_t *p_sys;
 +    int i_ret;
 +
 +    if (p_filter->shortcut == NULL)
 +        return VLC_EGENERIC;
 +
 +    p_sys = p_filter->p_sys = calloc( 1, sizeof( *p_sys ) );
 +    if( !p_sys )</code></pre>
</blockquote>
<p>As long as we have <code>unlikely</code> and <code>likely</code> in the codebase, I personally prefer us to use it where applicable.</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +        return VLC_ENOMEM;
 +
 +    filter_owner_t owner = {
 +        .sys = p_filter,
 +        .video = {
 +            .buffer_new = BufferNew,
 +        },
 +    };
 +
 +    p_sys->p_chain = filter_chain_NewVideo( p_filter, false, &owner );
 +    if( !p_sys->p_chain )
 +    {
 +        free( p_sys );
 +        return VLC_EGENERIC;
 +    }
 +
 +    int type = VLC_VAR_INTEGER;
 +    if( var_Type( p_filter->obj.parent, RECURSIVE_STRING ) != 0 )
 +        type |= VLC_VAR_DOINHERIT;
 +
 +    var_Create( p_filter, RECURSIVE_STRING, type );
 +    /* Note: atomicity is not actually needed here. */
 +    var_IncInteger( p_filter, RECURSIVE_STRING );
 +
 +    int level = var_GetInteger( p_filter, RECURSIVE_STRING );
 +    if( level < 0 || level > CHAIN_LEVEL_MAX )
 +        msg_Err( p_filter, "Too high level of recursion (%d)", level );
 +    else
 +        i_ret = BuildShortcutChain( p_filter );
 +
 +    if( i_ret )</code></pre>
</blockquote>
<p><code>i_ret</code> is potentially uninitialized (on error).</p>
<blockquote style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;color:#500050">
<pre><code> +    {
 +        /* Hum ... looks like this really isn't going to work. Too bad. */
 +        var_Destroy( p_filter, RECURSIVE_STRING );
 +        filter_chain_Delete( p_sys->p_chain );
 +        free( p_sys );
 +        return VLC_EGENERIC;
 +    }
 +
 +    if ( p_filter->b_allow_fmt_out_change )
 +    {
 +        es_format_Clean( &p_filter->fmt_out );
 +        es_format_Copy( &p_filter->fmt_out, filter_chain_GetFmtOut(p_sys->p_chain) );
 +    }
 +
 +    /* */
 +    p_filter->pf_video_filter = Chain;
 +    return VLC_SUCCESS;
 +}
 +
 +static void Destroy( vlc_object_t *p_this )
 +{
 +    filter_t *p_filter = (filter_t *)p_this;
 +
 +    var_Destroy( p_filter, RECURSIVE_STRING );
 +    filter_chain_Delete( p_filter->p_sys->p_chain );
 +    free( p_filter->p_sys );
 +}
 +
 +/*****************************************************************************
 + * Module descriptor
 + *****************************************************************************/
 +vlc_module_begin ()
 +    set_description( N_("Video filter using a chain of video converter modules") )
 +    set_capability( "video filter", 1 )
 +    set_callbacks( Activate, Destroy )
 +vlc_module_end ()</code></pre>
</blockquote>
</body>
</html>