[FFmpeg-devel] [PATCH V1] lavfi/superfastblur: add superfastblur filter

mypopy at gmail.com mypopy at gmail.com
Tue Nov 12 12:33:08 EET 2019


On Tue, Nov 12, 2019 at 5:37 PM Paul B Mahol <onemda at gmail.com> wrote:
>
> Isn't this same as boxblur?
>
After going deep into the boxblur, I think the superfastblur same as
the boxblur, please ignore the patch, thx.
> On 11/12/19, Steven Liu <lq at chinaffmpeg.org> wrote:
> >
> >
> >> 在 2019年11月12日,15:51,Jun Zhao <mypopydev at gmail.com> 写道:
> >>
> >> From: Jun Zhao <barryjzhao at tencent.com>
> >>
> >> add superfastblur filter
> >>
> >> Signed-off-by: Jun Zhao <barryjzhao at tencent.com>
> >> ---
> >> doc/filters.texi               |   15 ++
> >> libavfilter/Makefile           |    1 +
> >> libavfilter/allfilters.c       |    1 +
> >> libavfilter/vf_superfastblur.c |  275
> >> ++++++++++++++++++++++++++++++++++++++++
> >> 4 files changed, 292 insertions(+), 0 deletions(-)
> >> create mode 100644 libavfilter/vf_superfastblur.c
> >>
> >> diff --git a/doc/filters.texi b/doc/filters.texi
> >> index 6800124..c7d1893 100644
> >> --- a/doc/filters.texi
> >> +++ b/doc/filters.texi
> >> @@ -17453,6 +17453,21 @@ Interpolate) pixel art scaling algorithm.
> >>
> >> Useful for enlarging pixel art images without reducing sharpness.
> >>
> >> + at section superfastblur
> >> +
> >> +Blur the input image with super fast blur algorithm, multiple invocations
> >> of this
> >> +filter with a small radius will approximate a gaussian blur quite well.
> >> +
> >> +This filter accepts the following options:
> >> +
> >> + at table @option
> >> + at item radius
> >> + at item r
> >> +Set the blurring box radius. The option value must be a int number in
> >> +the range [1, 10] that specifies the blur box size of the superfast blur
> >> filter
> >> +used to blur the image. Default value is @code{2}..
> >> + at end table
> >> +
> >> @section swaprect
> >>
> >> Swap two rectangular objects in video.
> >> diff --git a/libavfilter/Makefile b/libavfilter/Makefile
> >> index fce9303..db4d5e6 100644
> >> --- a/libavfilter/Makefile
> >> +++ b/libavfilter/Makefile
> >> @@ -396,6 +396,7 @@ OBJS-$(CONFIG_STEREO3D_FILTER)               +=
> >> vf_stereo3d.o
> >> OBJS-$(CONFIG_STREAMSELECT_FILTER)           += f_streamselect.o
> >> framesync.o
> >> OBJS-$(CONFIG_SUBTITLES_FILTER)              += vf_subtitles.o
> >> OBJS-$(CONFIG_SUPER2XSAI_FILTER)             += vf_super2xsai.o
> >> +OBJS-$(CONFIG_SUPEREQUALIZER_FILTER)         += vf_superfastblur.o
> >> OBJS-$(CONFIG_SWAPRECT_FILTER)               += vf_swaprect.o
> >> OBJS-$(CONFIG_SWAPUV_FILTER)                 += vf_swapuv.o
> >> OBJS-$(CONFIG_TBLEND_FILTER)                 += vf_blend.o framesync.o
> >> diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
> >> index 7c1e19e..d507bc5 100644
> >> --- a/libavfilter/allfilters.c
> >> +++ b/libavfilter/allfilters.c
> >> @@ -377,6 +377,7 @@ extern AVFilter ff_vf_stereo3d;
> >> extern AVFilter ff_vf_streamselect;
> >> extern AVFilter ff_vf_subtitles;
> >> extern AVFilter ff_vf_super2xsai;
> >> +extern AVFilter ff_vf_superfastblur;
> >> extern AVFilter ff_vf_swaprect;
> >> extern AVFilter ff_vf_swapuv;
> >> extern AVFilter ff_vf_tblend;
> >> diff --git a/libavfilter/vf_superfastblur.c
> >> b/libavfilter/vf_superfastblur.c
> >> new file mode 100644
> >> index 0000000..a6428cf
> >> --- /dev/null
> >> +++ b/libavfilter/vf_superfastblur.c
> >> @@ -0,0 +1,275 @@
> >> +/*
> >> + * Copyright (c) 2019 Jun Zhao
> >> + *
> >> + * This file is part of FFmpeg.
> >> + *
> >> + * FFmpeg 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.
> >> + *
> >> + * 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
> >> + * Lesser General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU Lesser 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
> >> + * Super fast blur filter
> >> + *
> >> + * @see http://incubator.quasimondo.com/processing/superfast_blur.php
> >> + */
> >> +
> >> +#include "libavutil/avassert.h"
> >> +#include "libavutil/imgutils.h"
> >> +#include "libavutil/opt.h"
> >> +#include "avfilter.h"
> >> +#include "formats.h"
> >> +#include "internal.h"
> >> +#include "video.h"
> >> +
> >> +typedef struct SuperFastBlurContext {
> >> +    const AVClass *class;
> >> +
> >> +    int radius;
> >> +
> >> +    uint32_t *vMIN;
> >> +    uint32_t *vMAX;
> >> +
> >> +    uint8_t *r;
> >> +    uint8_t *g;
> >> +    uint8_t *b;
> >> +
> >> +    uint8_t *dv;
> >> +} SuperFastBlurContext;
> >> +
> >> +#define OFFSET(x) offsetof(SuperFastBlurContext, x)
> >> +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
> >> +static const AVOption superfastblur_options[] = {
> >> +    { "radius", "Radius of the super fast blurring box", OFFSET(radius),
> >> AV_OPT_TYPE_INT, {.i64 = 2}, 1, 10, FLAGS },
> >> +    { "r",      "Radius of the super fast blurring box", OFFSET(radius),
> >> AV_OPT_TYPE_INT, {.i64 = 2}, 1, 10, FLAGS },
> >> +    { NULL }
> >> +};
> >> +
> >> +AVFILTER_DEFINE_CLASS(superfastblur);
> >> +
> >> +static av_cold int init(AVFilterContext *ctx)
> >> +{
> >> +    SuperFastBlurContext *s = ctx->priv;
> >> +
> >> +    // This line precalculates a lookup table for all the possible
> >> +    // mean values that can occur. This is to avoid costly division
> >> +    // in the inner loop. On some systems doing the division directly
> >> +    // instead of a doing an array lookup might actually be faster
> >> +    // nowadays.
> >> +    uint32_t div = 2 * s->radius + 1;
> >> +    s->dv = av_malloc(sizeof(*s->dv) * 256 * div);
> >> +    if (!s->dv)
> >> +        return AVERROR(ENOMEM);
> >> +    for (int i = 0; i < 256 * div; i++)
> >> +        s->dv[i] = (i / div);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +static int query_formats(AVFilterContext *ctx)
> >> +{
> >> +    static const enum AVPixelFormat pix_fmts[] = {
> >> +        AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24,
> >> +
> >> +        AV_PIX_FMT_NONE
> > Empty line?
> >> +    };
> >> +
> >> +    AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
> >> +    if (!fmts_list)
> >> +        return AVERROR(ENOMEM);
> >> +    return ff_set_common_formats(ctx, fmts_list);
> >> +}
> >> +
> >> +static int config_props(AVFilterLink *inlink)
> >> +{
> >> +    AVFilterContext *ctx = inlink->dst;
> >> +    SuperFastBlurContext *s = ctx->priv;
> >> +
> >> +    uint32_t wm = inlink->w - 1;
> >> +    uint32_t wh = inlink->w * inlink->h;
> >> +
> >> +    s->vMIN = av_malloc(sizeof(wm) * FFMAX(inlink->w, inlink->h));
> >> +    s->vMAX = av_malloc(sizeof(wm) * FFMAX(inlink->w, inlink->h));
> >> +    s->r = av_malloc(sizeof(*s->r) * wh);
> >> +    s->g = av_malloc(sizeof(*s->g) * wh);
> >> +    s->b = av_malloc(sizeof(*s->b) * wh);
> >> +
> >> +    if (!s->vMIN || !s->vMAX || !s->r || !s->g || !s->b)
> >> +        return AVERROR(ENOMEM);
> >> +
> >> +    return 0;
> >> +}
> >> +
> >> +/*
> >> + * Super Fast Blur v1.1+
> >> + * by Mario Klingemann <http://incubator.quasimondo.com>
> >> + * Original address:
> >> http://incubator.quasimondo.com/processing/superfastblur.pde
> >> + *
> >> + * Tip: Multiple invocations of this filter with a small
> >> + * radius will approximate a gaussian blur quite well.
> >> + */
> >> +static void superfast_blur(SuperFastBlurContext *s, uint8_t *pix, int w,
> >> int h, int nb_comps)
> >> +{
> >> +    uint32_t wm, hm;
> >> +    uint32_t *vMIN, *vMAX;
> >> +    uint8_t *r, *g, *b, *dv;
> >> +    uint32_t rsum, gsum, bsum;
> >> +    uint32_t p, p1, p2, yi, yw;
> >> +
> >> +    int radius;
> >> +
> >> +    int x, y, i, yp;
> >> +
> >> +    wm = w - 1;
> >> +    hm = h - 1;
> >> +
> >> +    vMIN = s->vMIN;
> >> +    vMAX = s->vMAX;
> >> +    r = s->r;
> >> +    g = s->g;
> >> +    b = s->b;
> >> +
> >> +    dv = s->dv;
> >> +
> >> +    radius = s->radius;
> >> +
> >> +    yw = yi = 0;
> >> +    for (y = 0; y < h; y++) {
> >> +        rsum = gsum = bsum = 0;
> >> +        // The reason why this algorithm is fast is that it uses a
> >> sliding
> >> +        // window and thus reduces the number of required pixel lookups.
> >> +        // The window slides from the left edge to the right (and in the
> >> +        // second pass from top to bottom) and only adds one pixel at the
> >> +        // right and removes one from the left. The code above
> >> initializes
> >> +        // the window by prefilling the window with the leftmost edge
> >> pixel
> >> +        // depending on the kernel size.
> >> +        for (i = -radius; i <= radius; i++) {
> >> +            p = (yi + FFMIN(wm, FFMAX(i, 0))) * nb_comps;
> >> +            rsum += pix[p];
> >> +            gsum += pix[p + 1];
> >> +            bsum += pix[p + 2];
> >> +        }
> >> +
> >> +        for (x = 0; x < w; x++) {
> >> +            r[yi] = dv[rsum];
> >> +            g[yi] = dv[gsum];
> >> +            b[yi] = dv[bsum];
> >> +
> >> +            // adds a new pixel but at the same time handles the border
> >> +            // conditions (when the window tries to read or remove pixels
> >> +            // outside the bitmap).
> >> +            if (y == 0) {
> >> +                vMIN[x] = FFMIN(x + radius + 1, wm);
> >> +                vMAX[x] = FFMAX(x - radius, 0);
> >> +            }
> >> +            p1 = (yw + vMIN[x]) * nb_comps;
> >> +            p2 = (yw + vMAX[x]) * nb_comps;
> >> +            rsum += pix[p1]     - pix[p2];
> >> +            gsum += pix[p1 + 1] - pix[p2 + 1];
> >> +            bsum += pix[p1 + 2] - pix[p2 + 2];
> >> +            yi++;
> >> +        }
> >> +        yw += w;
> >> +    }
> >> +
> >> +    for (x = 0; x < w; x++) {
> >> +        rsum = gsum = bsum = 0;
> >> +        yp = -radius * w;
> >> +        for (i = -radius; i <= radius; i++) {
> >> +            yi = FFMAX(0, yp) + x;
> >> +            rsum += r[yi];
> >> +            gsum += g[yi];
> >> +            bsum += b[yi];
> >> +            yp += w;
> >> +        }
> >> +
> >> +        yi = x;
> >> +        for (y = 0; y < h; y++) {
> >> +            pix[yi * nb_comps]     = dv[bsum];
> >> +            pix[yi * nb_comps + 1] = dv[gsum];
> >> +            pix[yi * nb_comps + 2] = dv[rsum];
> >> +
> >> +            if (x == 0) {
> >> +                vMIN[y] = FFMIN(y + radius + 1, hm) * w;
> >> +                vMAX[y] = FFMAX(y - radius, 0) * w;
> >> +            }
> >> +            p1 = x + vMIN[y];
> >> +            p2 = x + vMAX[y];
> >> +
> >> +            // rsum, gsum and bsum is the accumulated sum of pixels
> >> inside
> >> +            // the sliding window. What you see is the new pixel on the
> >> +            // right side being added to the sum and the leftmost pixel
> >> +            // i nthe window being removed from the sum.
> >> +            rsum += r[p1] - r[p2];
> >> +            gsum += g[p1] - g[p2];
> >> +            bsum += b[p1] - b[p2];
> >> +            yi += w;
> >> +        }
> >> +    }
> >> +}
> >> +
> >> +static int filter_frame(AVFilterLink *inlink, AVFrame *in)
> >> +{
> >> +    AVFilterContext *ctx = inlink->dst;
> >> +    SuperFastBlurContext *s = ctx->priv;
> >> +    AVFilterLink *outlink = ctx->outputs[0];
> >> +    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
> >> +
> >> +    superfast_blur(s, in->data[0], inlink->w, inlink->h,
> >> desc->nb_components);
> >> +
> >> +    return ff_filter_frame(outlink, in);
> >> +}
> >> +
> >> +static av_cold void uninit(AVFilterContext *ctx)
> >> +{
> >> +    SuperFastBlurContext *s = ctx->priv;
> >> +
> >> +    av_freep(&s->r);
> >> +    av_freep(&s->g);
> >> +    av_freep(&s->b);
> >> +    av_freep(&s->vMIN);
> >> +    av_freep(&s->vMAX);
> >> +    av_freep(&s->dv);
> >> +}
> >> +
> >> +static const AVFilterPad superfastblur_inputs[] = {
> >> +    {
> >> +        .name         = "default",
> >> +        .type         = AVMEDIA_TYPE_VIDEO,
> >> +        .config_props = config_props,
> >> +        .filter_frame = filter_frame,
> >> +    },
> >> +    { NULL }
> >> +};
> >> +
> >> +static const AVFilterPad superfastblur_outputs[] = {
> >> +    {
> >> +        .name = "default",
> >> +        .type = AVMEDIA_TYPE_VIDEO,
> >> +    },
> >> +    { NULL }
> >> +};
> >> +
> >> +AVFilter ff_vf_superfastblur = {
> >> +    .name          = "superfastblur",
> >> +    .description   = NULL_IF_CONFIG_SMALL("Blur the input with super fast
> >> blur algorithm."),
> >> +    .priv_size     = sizeof(SuperFastBlurContext),
> >> +    .init          = init,
> >> +    .uninit        = uninit,
> >> +    .query_formats = query_formats,
> >> +    .inputs        = superfastblur_inputs,
> >> +    .outputs       = superfastblur_outputs,
> >> +    .priv_class    = &superfastblur_class,
> >> +    .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC,
> >> +};
> >> --
> >> 1.7.1
> >>
> >> _______________________________________________
> >> ffmpeg-devel mailing list
> >> ffmpeg-devel at ffmpeg.org
> >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >>
> >> To unsubscribe, visit link above, or email
> >> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe”.
> >
> > LGTM
> > BTW, I saw you usually submit multi thread performance optimization for
> > other filter,
> > Why don’y do that in this filter one time complete?
> > I think maybe only one patch complete the whole operation maybe better.
> >
> > Thanks
> > Steven
> >
> >
> >
> >
> >
> > _______________________________________________
> > ffmpeg-devel mailing list
> > ffmpeg-devel at ffmpeg.org
> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> >
> > To unsubscribe, visit link above, or email
> > ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".



-- 
=======================================
Jun zhao/赵军
+++++++++++++++++++++++++++++++++++++++


More information about the ffmpeg-devel mailing list