On Wed, Nov 20, 2019 at 8:38 PM Paul B Mahol <one...@gmail.com> wrote: > > How can this be fast at all? > It does not use slice threading and also supports only packed rgb formats. > Have you actually benchmarked with and without lookup table? > Will support other format like RGBA and YUV420P with slice threading enabling in next version > On 11/13/19, Jun Zhao <mypopy...@gmail.com> wrote: > > From: Jun Zhao <barryjz...@tencent.com> > > > > add stackblur filter > > > > Signed-off-by: Jun Zhao <barryjz...@tencent.com> > > --- > > doc/filters.texi | 22 +++ > > libavfilter/Makefile | 1 + > > libavfilter/allfilters.c | 1 + > > libavfilter/vf_stackblur.c | 362 > > ++++++++++++++++++++++++++++++++++++++++++++ > > 4 files changed, 386 insertions(+), 0 deletions(-) > > create mode 100644 libavfilter/vf_stackblur.c > > > > diff --git a/doc/filters.texi b/doc/filters.texi > > index 23a3ded..0c450ff 100644 > > --- a/doc/filters.texi > > +++ b/doc/filters.texi > > @@ -17132,6 +17132,28 @@ ffmpeg -i main.mpg -i ref.mkv -lavfi > > "[0:v]settb=1/AVTB,setpts=PTS-STARTPTS[mai > > @end example > > @end itemize > > > > +@section stackblur > > + > > +Blur the input image with stack blur algorithm, this is a compromise > > between Gaussian Blur > > +and Box blur, It creates much better looking blurs than Box Blur, but is > > faster > > +than the Gaussian Blur. > > + > > +Called it stack blur because this describes best how this filter works > > internally: it creates > > +a kind of moving stack of colors whilst scanning through the image. Thereby > > it > > +just has to add one new block of color to the right side of the stack and > > remove the > > +leftmost color. The remaining colors on the topmost layer of the stack are > > either added on > > +or reduced by one, depending on if they are on the right or on the left > > side of the stack. > > + > > +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, 179] that specifies the blur box size of the stack blur > > filter > > +used to blur the image. Default value is @code{2}. > > +@end table > > + > > @section stereo3d > > > > Convert between different stereoscopic image formats. > > diff --git a/libavfilter/Makefile b/libavfilter/Makefile > > index db4d5e6..b9a4ad0 100644 > > --- a/libavfilter/Makefile > > +++ b/libavfilter/Makefile > > @@ -392,6 +392,7 @@ OBJS-$(CONFIG_SPLIT_FILTER) += split.o > > OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o > > OBJS-$(CONFIG_SR_FILTER) += vf_sr.o > > OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o framesync.o > > +OBJS-$(CONFIG_STACKBLUR_FILTER) += vf_stackblur.o > > OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o > > OBJS-$(CONFIG_STREAMSELECT_FILTER) += f_streamselect.o > > framesync.o > > OBJS-$(CONFIG_SUBTITLES_FILTER) += vf_subtitles.o > > diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c > > index d507bc5..4064ba0 100644 > > --- a/libavfilter/allfilters.c > > +++ b/libavfilter/allfilters.c > > @@ -373,6 +373,7 @@ extern AVFilter ff_vf_split; > > extern AVFilter ff_vf_spp; > > extern AVFilter ff_vf_sr; > > extern AVFilter ff_vf_ssim; > > +extern AVFilter ff_vf_stackblur; > > extern AVFilter ff_vf_stereo3d; > > extern AVFilter ff_vf_streamselect; > > extern AVFilter ff_vf_subtitles; > > diff --git a/libavfilter/vf_stackblur.c b/libavfilter/vf_stackblur.c > > new file mode 100644 > > index 0000000..f1a6f20 > > --- /dev/null > > +++ b/libavfilter/vf_stackblur.c > > @@ -0,0 +1,362 @@ > > +/* > > + * 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 > > + * Stack blur filter > > + * > > + * Stack Blur Algorithm by Mario Klingemann <ma...@quasimondo.com> > > + * > > + * @see http://incubator.quasimondo.com/processing/stackblur.pde > > + */ > > + > > +#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; > > + uint8_t *rgb; > > + uint8_t *dv; > > + > > + int *stack; > > +} StackBlurContext; > > + > > +#define OFFSET(x) offsetof(StackBlurContext, x) > > +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM > > +static const AVOption stackblur_options[] = { > > + { "radius", "Radius of the stack blurring box", OFFSET(radius), > > AV_OPT_TYPE_INT, {.i64 = 2}, 1, 179, FLAGS }, > > + { "r", "Radius of the stack blurring box", OFFSET(radius), > > AV_OPT_TYPE_INT, {.i64 = 2}, 1, 179, FLAGS }, > > + { NULL } > > +}; > > + > > +AVFILTER_DEFINE_CLASS(stackblur); > > + > > +static av_cold int init(AVFilterContext *ctx) > > +{ > > + StackBlurContext *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; > > + int divsum = (div + 1) >> 1; > > + divsum *= divsum; > > + s->dv = av_malloc(256 * divsum * sizeof(*s->dv)); > > + if (!s->dv) > > + return AVERROR(ENOMEM); > > + for (int i = 0; i < 256 * divsum; i++) > > + s->dv[i] = i / divsum; > > + > > + 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; > > + StackBlurContext *s = ctx->priv; > > + > > + uint32_t div = 2 * s->radius + 1; > > + uint32_t wh = inlink->w * inlink->h; > > + > > + s->rgb = av_malloc(sizeof(*s->rgb) * wh * 3); > > + s->vMIN = av_malloc(FFMAX(inlink->w, inlink->h) * sizeof(*s->vMIN)); > > + s->stack = av_malloc(div * 3 * sizeof(*s->stack)); > > + if (!s->vMIN || !s->rgb || !s->stack) > > + return AVERROR(ENOMEM); > > + > > + return 0; > > +} > > + > > +// Stack Blur v1.0 > > +// > > +// Author: Mario Klingemann <ma...@quasimondo.com> > > +// http://incubator.quasimondo.com > > +// created Feburary 29, 2004 > > +// > > +// This is a compromise between Gaussian Blur and Box blur > > +// It creates much better looking blurs than Box Blur, but is faster > > +// than the Gaussian Blur implementation. > > +// > > +// Called it Stack Blur because this describes best how this > > +// filter works internally: it creates a kind of moving stack > > +// of colors whilst scanning through the image. Thereby it > > +// just has to add one new block of color to the right side > > +// of the stack and remove the leftmost color. The remaining > > +// colors on the topmost layer of the stack are either added on > > +// or reduced by one, depending on if they are on the right or > > +// on the left side of the stack. > > +// > > +static void stack_blur(StackBlurContext *s, uint8_t *pix, int w, int h, int > > nb_comps) > > +{ > > + uint32_t wm = w - 1; > > + uint32_t hm = h - 1; > > + uint32_t wh = w * h; > > + > > + int radius = s->radius; > > + > > + uint8_t *rgb = s->rgb; > > + uint8_t *r = rgb; > > + uint8_t *g = rgb + wh; > > + uint8_t *b = rgb + wh * 2; > > + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; > > + > > + uint32_t stackpointer; > > + uint32_t stackstart; > > + int *sir; > > + int rbs; > > + int r1 = radius + 1; > > + int routsum, goutsum, boutsum; > > + int rinsum, ginsum, binsum; > > + > > + uint32_t div = 2 * radius + 1; > > + > > + int(*stack)[3] = (int(*)[3])(s->stack); > > + uint32_t *vMIN = s->vMIN; > > + uint8_t *dv = s->dv; > > + > > + yw = yi = 0; > > + > > + for (y = 0; y < h; y++) { > > + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = > > gsum = bsum = 0; > > + for (i = -radius; i <= radius; i++) { > > + p = yi + (FFMIN(wm, FFMAX(i, 0))); > > + sir = stack[i + radius]; > > + sir[0] = pix[(p*nb_comps)]; > > + sir[1] = pix[(p*nb_comps) + 1]; > > + sir[2] = pix[(p*nb_comps) + 2]; > > + > > + rbs = r1 - FFABS(i); > > + rsum += sir[0] * rbs; > > + gsum += sir[1] * rbs; > > + bsum += sir[2] * rbs; > > + if (i > 0) { > > + rinsum += sir[0]; > > + ginsum += sir[1]; > > + binsum += sir[2]; > > + } else { > > + routsum += sir[0]; > > + goutsum += sir[1]; > > + boutsum += sir[2]; > > + } > > + } > > + stackpointer = radius; > > + > > + for (x = 0; x < w; x++) { > > + r[yi] = dv[rsum]; > > + g[yi] = dv[gsum]; > > + b[yi] = dv[bsum]; > > + > > + rsum -= routsum; > > + gsum -= goutsum; > > + bsum -= boutsum; > > + > > + stackstart = stackpointer - radius + div; > > + sir = stack[stackstart % div]; > > + > > + routsum -= sir[0]; > > + goutsum -= sir[1]; > > + boutsum -= sir[2]; > > + > > + if (y == 0) > > + vMIN[x] = FFMIN(x + radius + 1, wm); > > + p = yw + vMIN[x]; > > + > > + sir[0] = pix[(p*nb_comps)]; > > + sir[1] = pix[(p*nb_comps) + 1]; > > + sir[2] = pix[(p*nb_comps) + 2]; > > + rinsum += sir[0]; > > + ginsum += sir[1]; > > + binsum += sir[2]; > > + > > + rsum += rinsum; > > + gsum += ginsum; > > + bsum += binsum; > > + > > + stackpointer = (stackpointer + 1) % div; > > + sir = stack[(stackpointer) % div]; > > + > > + routsum += sir[0]; > > + goutsum += sir[1]; > > + boutsum += sir[2]; > > + > > + rinsum -= sir[0]; > > + ginsum -= sir[1]; > > + binsum -= sir[2]; > > + > > + yi++; > > + } > > + yw += w; > > + } > > + for (x = 0; x < w; x++) { > > + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = > > gsum = bsum = 0; > > + yp = -radius * w; > > + for (i = -radius; i <= radius; i++) { > > + yi = FFMAX(0, yp) + x; > > + > > + sir = stack[i + radius]; > > + > > + sir[0] = r[yi]; > > + sir[1] = g[yi]; > > + sir[2] = b[yi]; > > + > > + rbs = r1 - FFABS(i); > > + > > + rsum += r[yi] * rbs; > > + gsum += g[yi] * rbs; > > + bsum += b[yi] * rbs; > > + > > + if (i > 0) { > > + rinsum += sir[0]; > > + ginsum += sir[1]; > > + binsum += sir[2]; > > + } else { > > + routsum += sir[0]; > > + goutsum += sir[1]; > > + boutsum += sir[2]; > > + } > > + > > + if (i < hm) > > + yp += w; > > + } > > + yi = x; > > + stackpointer = radius; > > + for (y = 0; y < h; y++) { > > + pix[(yi*nb_comps)] = dv[rsum]; > > + pix[(yi*nb_comps) + 1] = dv[gsum]; > > + pix[(yi*nb_comps) + 2] = dv[bsum]; > > + rsum -= routsum; > > + gsum -= goutsum; > > + bsum -= boutsum; > > + > > + stackstart = stackpointer - radius + div; > > + sir = stack[stackstart % div]; > > + > > + routsum -= sir[0]; > > + goutsum -= sir[1]; > > + boutsum -= sir[2]; > > + > > + if (x == 0) > > + vMIN[y] = FFMIN(y + r1, hm) * w; > > + p = x + vMIN[y]; > > + > > + sir[0] = r[p]; > > + sir[1] = g[p]; > > + sir[2] = b[p]; > > + > > + rinsum += sir[0]; > > + ginsum += sir[1]; > > + binsum += sir[2]; > > + > > + rsum += rinsum; > > + gsum += ginsum; > > + bsum += binsum; > > + > > + stackpointer = (stackpointer + 1) % div; > > + sir = stack[stackpointer]; > > + > > + routsum += sir[0]; > > + goutsum += sir[1]; > > + boutsum += sir[2]; > > + > > + rinsum -= sir[0]; > > + ginsum -= sir[1]; > > + binsum -= sir[2]; > > + > > + yi += w; > > + } > > + } > > +} > > + > > +static int filter_frame(AVFilterLink *inlink, AVFrame *in) > > +{ > > + AVFilterContext *ctx = inlink->dst; > > + StackBlurContext *s = ctx->priv; > > + AVFilterLink *outlink = ctx->outputs[0]; > > + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); > > + > > + stack_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) > > +{ > > + StackBlurContext *s = ctx->priv; > > + > > + av_freep(&s->rgb); > > + av_freep(&s->vMIN); > > + av_freep(&s->dv); > > + av_freep(&s->stack); > > +} > > + > > +static const AVFilterPad stackblur_inputs[] = { > > + { > > + .name = "default", > > + .type = AVMEDIA_TYPE_VIDEO, > > + .config_props = config_props, > > + .filter_frame = filter_frame, > > + }, > > + { NULL } > > +}; > > + > > +static const AVFilterPad stackblur_outputs[] = { > > + { > > + .name = "default", > > + .type = AVMEDIA_TYPE_VIDEO, > > + }, > > + { NULL } > > +}; > > + > > +AVFilter ff_vf_stackblur = { > > + .name = "stackblur", > > + .description = NULL_IF_CONFIG_SMALL("Blur the input with stack > > algorithm."), > > + .priv_size = sizeof(StackBlurContext), > > + .init = init, > > + .uninit = uninit, > > + .query_formats = query_formats, > > + .inputs = stackblur_inputs, > > + .outputs = stackblur_outputs, > > + .priv_class = &stackblur_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". > _______________________________________________ > 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".