[FFmpeg-devel] [PATCH] lavfi: add pp filter.

Stefano Sabatini stefasab at gmail.com
Wed Dec 12 13:18:55 CET 2012


On date Wednesday 2012-12-12 04:49:49 +0100, Clément Bœsch encoded:
> Ported from MPlayer. Original author is A'rpi, with various
> contributions from Michael Niedermayer. The original documentation was
> mostly written by Diego Biurrun. See the MPlayer history for full
> credits.
> 
> The filter is under GPL like the original filter, even if it differs
> quite a lot. There is not much point in making it LGPL since pp is under
> GPL.
> 
> TODO: fix FATE
> TODO: bump minor
> TODO: Changelog
> ---
> Some insight about current FATE failure: the 3 first pp tests fail because of a
> mismatch between linesize and width (for the chroma planes), which is not
> present with mp=pp, where linesize==width all the time for some reason. It
> might be a bug in libpostproc, but I need someone familiar with it to confirm
> this.
> 
> A quick and dirty hack to make linesize and width match for the fate test is to
> change the av_image_alloc from 32 to 16 in lavfi/video.c. Of course this is not
> a solution, but it's useful for testing purpose since this change allow to pass
> all the pp FATE tests.
> ---
>  LICENSE                   |   1 +
>  configure                 |   1 +
>  doc/filters.texi          | 164 ++++++++++++++++++++++++++++++++++++++++++++
>  libavfilter/Makefile      |   1 +
>  libavfilter/allfilters.c  |   1 +
>  libavfilter/vf_pp.c       | 169 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/lavfi-regression.sh |  12 ++--
>  7 files changed, 343 insertions(+), 6 deletions(-)
>  create mode 100644 libavfilter/vf_pp.c
> 
> diff --git a/LICENSE b/LICENSE
> index a1204f4..d083e56 100644
> --- a/LICENSE
> +++ b/LICENSE
> @@ -34,6 +34,7 @@ Specifically, the GPL parts of FFmpeg are
>      - vf_hqdn3d.c
>      - vf_hue.c
>      - vf_mp.c
> +    - vf_pp.c
>      - vf_smartblur.c
>      - vf_super2xsai.c
>      - vf_tinterlace.c
> diff --git a/configure b/configure
> index 7f3202e..4c30e63 100755
> --- a/configure
> +++ b/configure
> @@ -1987,6 +1987,7 @@ negate_filter_deps="lut_filter"
>  resample_filter_deps="avresample"
>  ocv_filter_deps="libopencv"
>  pan_filter_deps="swresample"
> +pp_filter_deps="gpl"
>  removelogo_filter_deps="avcodec avformat swscale"
>  scale_filter_deps="swscale"
>  smartblur_filter_deps="gpl swscale"
> diff --git a/doc/filters.texi b/doc/filters.texi
> index b840cac..9e89dd0 100644
> --- a/doc/filters.texi
> +++ b/doc/filters.texi
> @@ -3301,6 +3301,170 @@ format=monow, pixdesctest
>  
>  can be used to test the monowhite pixel format descriptor definition.
>  
> + at section pp
> +
> +Enables the specified chain of postprocessing subfilters using libpostproc.

Nit: "Enable" for overall consistency.

Also mention that this needs libpostproc to be enabled (mentioning
--enable-gpl may also avoid some user complaints).

> +Subfilters must be separated by '/' and can be disabled by prepending a '-'.
> +Each subfilter and some options have a short and a long name that can be used
> +interchangeably, i.e. dr/dering are the same.

Missing description of how to specify options.

> +All subfilters share common options to determine their scope:

I believe that libpp parameters/library deserve a dedicated document
(for the same reason libswresample/libswscale parameters should not be
documented in filters.texi).

> +
> + at table @option
> + at item a/autoq
> +Automatically switch the subfilter off if the CPU is too slow.
> +
> + at item c/chrom
> +Do chrominance filtering, too (default).
> +
> + at item y/nochrom
> +Do luminance filtering only (no chrominance).
> +
> + at item n/noluma
> +Do chrominance filtering only (no luminance).
> + at end table
> +
> +Available subfilters are:
> +
> + at table @option
> + at item hb/hdeblock[:difference[:flatness]]
> +Horizontal deblocking filter
> + at table @option
> + at item difference
> +Difference factor where higher values mean more deblocking (default: @code{32}).
> + at item flatness
> +Flatness threshold where lower values mean more deblocking (default: @code{39}).
> + at end table
> +
> + at item vb/vdeblock[:difference[:flatness]]
> +Vertical deblocking filter
> + at table @option
> + at item difference
> +Difference factor where higher values mean more deblocking (default: @code{32}).
> + at item flatness
> +Flatness threshold where lower values mean more deblocking (default: @code{39}).
> + at end table
> +
> + at item ha/hadeblock[:difference[:flatness]]
> +Accurate horizontal deblocking filter
> + at table @option
> + at item difference
> +Difference factor where higher values mean more deblocking (default: @code{32}).
> + at item flatness
> +Flatness threshold where lower values mean more deblocking (default: @code{39}).
> + at end table
> +
> + at item va/vadeblock[:difference[:flatness]]
> +Accurate vertical deblocking filter
> + at table @option
> + at item difference
> +Difference factor where higher values mean more deblocking (default: @code{32}).
> + at item flatness
> +Flatness threshold where lower values mean more deblocking (default: @code{39}).
> + at end table
> + at end table
> +
> +The horizontal and vertical deblocking filters share the difference and
> +flatness values so you cannot set different horizontal and vertical
> +thresholds.
> +
> + at table @option
> + at item h1/x1hdeblock
> +Experimental horizontal deblocking filter
> +
> + at item v1/x1vdeblock
> +Experimental vertical deblocking filter
> +
> + at item dr/dering
> +Deringing filter
> +
> + at item tn/tmpnoise[:threshold1[:threshold2[:threshold3]]], temporal noise reducer
> + at table @option
> + at item threshold1
> +larger -> stronger filtering
> + at item threshold2
> +larger -> stronger filtering
> + at item threshold3
> +larger -> stronger filtering
> + at end table
> +
> + at item al/autolevels[:f/fullyrange], automatic brightness / contrast correction
> + at table @option
> + at item f/fullyrange
> +Stretch luminance to @code{0-255}.
> + at end table
> +
> + at item lb/linblenddeint
> +Linear blend deinterlacing filter that deinterlaces the given block by
> +filtering all lines with a @code{(1 2 1)} filter.
> +
> + at item li/linipoldeint
> +Linear interpolating deinterlacing filter that deinterlaces the given block by
> +linearly interpolating every second line.
> +
> + at item ci/cubicipoldeint
> +Cubic interpolating deinterlacing filter deinterlaces the given block by
> +cubically interpolating every second line.
> +
> + at item md/mediandeint
> +Median deinterlacing filter that deinterlaces the given block by applying a
> +median filter to every second line.
> +
> + at item fd/ffmpegdeint
> +FFmpeg deinterlacing filter that deinterlaces the given block by filtering every
> +second line with a @code{(-1 4 2 4 -1)} filter.
> +
> + at item l5/lowpass5
> +Vertically applied FIR lowpass deinterlacing filter that deinterlaces the given
> +block by filtering all lines with a @code{(-1 2 6 2 -1)} filter.
> +
> + at item fq/forceQuant[:quantizer]
> +Overrides the quantizer table from the input with the constant quantizer you
> +specify.
> + at table @option
> + at item quantizer
> +Quantizer to use
> + at end table
> +
> + at item de/default
> +Default pp filter combination (@code{hb:a,vb:a,dr:a})
> +
> + at item fa/fast
> +Fast pp filter combination (@code{h1:a,v1:a,dr:a})
> +
> + at item ac
> +High quality pp filter combination (@code{ha:a:128:7,va:a,dr:a})
> + at end table
> +
> + at subsection Examples
> +

> + at itemize
> + at item
> +Horizontal and vertical deblocking, deringing and automatic brightness/contrast:
> + at example
> +-vf pp=hb/vb/dr/al
> + at end example

Note: we usually omit the -vf part, and for good reasons, since
filters.texi is not meant to be bound to ff* tools syntax.

> +
> + at item
> +Default filters without brightness/contrast correction:
> + at example
> +-vf pp=de/-al
> + at end example
> +
> + at item
> +Enable default filters & temporal denoiser:
> + at example
> +-vf pp=default/tmpnoise:1:2:3
> + at end example
> +
> + at item

> +Horizontal deblocking on luminance only and switch vertical deblocking on or

The verb missing.

> +off automatically depending on available CPU time:

> + at example
> +-vf pp=hb:y/vb:a
> + at end example
> + at end itemize
> +
>  @section removelogo
>  
>  Suppress a TV station logo, using an image file to determine which
> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> index 191e3e1..dddcd6f 100644
> --- a/libavfilter/Makefile
> +++ b/libavfilter/Makefile
> @@ -122,6 +122,7 @@ OBJS-$(CONFIG_OCV_FILTER)                    += vf_libopencv.o
>  OBJS-$(CONFIG_OVERLAY_FILTER)                += vf_overlay.o
>  OBJS-$(CONFIG_PAD_FILTER)                    += vf_pad.o
>  OBJS-$(CONFIG_PIXDESCTEST_FILTER)            += vf_pixdesctest.o
> +OBJS-$(CONFIG_PP_FILTER)                     += vf_pp.o
>  OBJS-$(CONFIG_REMOVELOGO_FILTER)             += bbox.o lswsutils.o lavfutils.o vf_removelogo.o
>  OBJS-$(CONFIG_SCALE_FILTER)                  += vf_scale.o
>  OBJS-$(CONFIG_SELECT_FILTER)                 += vf_select.o
> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> index ffde5ce..c100de4 100644
> --- a/libavfilter/allfilters.c
> +++ b/libavfilter/allfilters.c
> @@ -114,6 +114,7 @@ void avfilter_register_all(void)
>      REGISTER_FILTER (OVERLAY,     overlay,     vf);
>      REGISTER_FILTER (PAD,         pad,         vf);
>      REGISTER_FILTER (PIXDESCTEST, pixdesctest, vf);
> +    REGISTER_FILTER (PP,          pp,          vf);
>      REGISTER_FILTER (REMOVELOGO,  removelogo,  vf);
>      REGISTER_FILTER (SCALE,       scale,       vf);
>      REGISTER_FILTER (SELECT,      select,      vf);
> diff --git a/libavfilter/vf_pp.c b/libavfilter/vf_pp.c
> new file mode 100644
> index 0000000..32b0674
> --- /dev/null
> +++ b/libavfilter/vf_pp.c
> @@ -0,0 +1,169 @@
> +/*
> + * Copyright (c) 2002 A'rpi
> + * Copyright (C) 2012 Clément Bœsch
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * FFmpeg 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 General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
> + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +/**
> + * @file
> + * libpostproc filter, ported from MPlayer.
> + */
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/opt.h"
> +#include "internal.h"
> +
> +#include "libpostproc/postprocess.h"
> +
> +typedef struct {
> +    int mode_id;
> +    pp_mode *modes[PP_QUALITY_MAX + 1];
> +    void *pp_ctx;
> +} PPFilterContext;
> +
> +static av_cold int pp_init(AVFilterContext *ctx, const char *args)
> +{
> +    int i;
> +    PPFilterContext *pp = ctx->priv;
> +
> +    if (!args || !*args)
> +        args = "de";
> +
> +    for (i = 0; i <= PP_QUALITY_MAX; i++) {
> +        pp->modes[i] = pp_get_mode_by_name_and_quality(args, i);
> +        if (!pp->modes[i])
> +            return AVERROR_EXTERNAL;
> +    }
> +    pp->mode_id = PP_QUALITY_MAX;
> +    return 0;

Not blocking, but maybe we can think about adding support for
options. For example it may be useful to be able to set quality.

> +}
> +
> +static int pp_process_command(AVFilterContext *ctx, const char *cmd, const char *args,
> +                              char *res, int res_len, int flags)
> +{
> +    PPFilterContext *pp = ctx->priv;
> +
> +    if (!strcmp(cmd, "quality")) {
> +        pp->mode_id = av_clip(strtol(args, NULL, 10), 0, PP_QUALITY_MAX);
> +        return 0;
> +    }
> +    return AVERROR(ENOSYS);
> +}
> +
> +static int pp_query_formats(AVFilterContext *ctx)
> +{
> +    static const enum PixelFormat pix_fmts[] = {
> +        AV_PIX_FMT_YUV420P,
> +        AV_PIX_FMT_YUV422P,
> +        AV_PIX_FMT_YUV411P,
> +        AV_PIX_FMT_YUV444P,
> +        AV_PIX_FMT_NONE
> +    };
> +    ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
> +    return 0;
> +}
> +
> +static int pp_config_props(AVFilterLink *inlink)
> +{
> +    int flags = PP_CPU_CAPS_AUTO;
> +    PPFilterContext *pp = inlink->dst->priv;
> +
> +    switch (inlink->format) {
> +    case AV_PIX_FMT_YUV420P: flags |= PP_FORMAT_420; break;
> +    case AV_PIX_FMT_YUV422P: flags |= PP_FORMAT_422; break;
> +    case AV_PIX_FMT_YUV411P: flags |= PP_FORMAT_411; break;
> +    case AV_PIX_FMT_YUV444P: flags |= PP_FORMAT_444; break;
> +    default: av_assert0(0);
> +    }
> +
> +    pp->pp_ctx = pp_get_context(inlink->w, inlink->h, flags);
> +    if (!pp->pp_ctx)
> +        return AVERROR(ENOMEM);
> +    return 0;
> +}
> +

> +static int pp_filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)

I hate too generic variable names (in... inlink? inframe? inpad?) as
they harm readability and slow me down when reading code.

> +{
> +    AVFilterContext *ctx = inlink->dst;
> +    PPFilterContext *pp = ctx->priv;
> +    AVFilterLink *outlink = ctx->outputs[0];
> +    const int aligned_w = FFALIGN(outlink->w, 8);
> +    const int aligned_h = FFALIGN(outlink->h, 8);
> +    AVFilterBufferRef *out;
> +
> +    out = ff_get_video_buffer(outlink, AV_PERM_WRITE, aligned_w, aligned_h);
> +    if (!out) {
> +        avfilter_unref_buffer(in);
> +        return AVERROR(ENOMEM);
> +    }
> +    avfilter_copy_buffer_ref_props(out, in);
> +
> +    pp_postprocess((const uint8_t **)in->data, in->linesize,
> +                   out->data, out->linesize,
> +                   aligned_w, outlink->h,
> +                   out->video->qp_table,
> +                   out->video->qp_table_linesize,
> +                   pp->modes[pp->mode_id],
> +                   pp->pp_ctx,
> +                   out->video->pict_type);
> +
> +    avfilter_unref_buffer(in);
> +    return ff_filter_frame(outlink, out);
> +}
> +
> +static av_cold void pp_uninit(AVFilterContext *ctx)
> +{
> +    int i;
> +    PPFilterContext *pp = ctx->priv;
> +
> +    for (i = 0; i <= PP_QUALITY_MAX; i++)
> +        pp_free_mode(pp->modes[i]);
> +    if (pp->pp_ctx)
> +        pp_free_context(pp->pp_ctx);
> +}
> +
> +static const AVFilterPad pp_inputs[] = {
> +    {
> +        .name         = "default",
> +        .type         = AVMEDIA_TYPE_VIDEO,
> +        .config_props = pp_config_props,
> +        .filter_frame = pp_filter_frame,
> +        .min_perms    = AV_PERM_READ,
> +    },
> +    { NULL }
> +};
> +
> +static const AVFilterPad pp_outputs[] = {
> +    {
> +        .name = "default",
> +        .type = AVMEDIA_TYPE_VIDEO,
> +    },
> +    { NULL }
> +};
> +
> +AVFilter avfilter_vf_pp = {
> +    .name            = "pp",

> +    .description     = NULL_IF_CONFIG_SMALL("filter video using libpostproc"),

"Filter video ... libpostproc."

[...]
-- 
FFmpeg = Fantastic and Freak Multimedia Problematic Erotic Gem


More information about the ffmpeg-devel mailing list