On Tue, Nov 12, 2019 at 4:14 PM Jun Zhao <mypopy...@gmail.com> wrote: > > From: Jun Zhao <barryjz...@tencent.com> > > add superfastblur filter > > Signed-off-by: Jun Zhao <barryjz...@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. > > +@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: > + > +@table @option > +@item radius > +@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}.. > +@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 > + }; > + > + 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]; > + need to swap bsum and rsum, will fix in next version > + 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@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
-- ======================================= Jun zhao/赵军 +++++++++++++++++++++++++++++++++++++++ _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".