Message ID | 1573545091-8319-1-git-send-email-mypopydev@gmail.com |
---|---|
State | Superseded |
Headers | show |
> 在 2019年11月12日,15:51,Jun Zhao <mypopydev@gmail.com> 写道: > > From: Jun Zhao <barryjzhao@tencent.com> > > add superfastblur filter > > Signed-off-by: Jun Zhao <barryjzhao@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 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@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@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
Isn't this same as boxblur? On 11/12/19, Steven Liu <lq@chinaffmpeg.org> wrote: > > >> 在 2019年11月12日,15:51,Jun Zhao <mypopydev@gmail.com> 写道: >> >> From: Jun Zhao <barryjzhao@tencent.com> >> >> add superfastblur filter >> >> Signed-off-by: Jun Zhao <barryjzhao@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 > 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@ffmpeg.org >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> To unsubscribe, visit link above, or email >> ffmpeg-devel-request@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@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
On Tue, Nov 12, 2019 at 4:14 PM Jun Zhao <mypopydev@gmail.com> wrote: > > From: Jun Zhao <barryjzhao@tencent.com> > > add superfastblur filter > > Signed-off-by: Jun Zhao <barryjzhao@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-request@ffmpeg.org with subject "unsubscribe".
On Tue, Nov 12, 2019 at 5:37 PM Paul B Mahol <onemda@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@chinaffmpeg.org> wrote: > > > > > >> 在 2019年11月12日,15:51,Jun Zhao <mypopydev@gmail.com> 写道: > >> > >> From: Jun Zhao <barryjzhao@tencent.com> > >> > >> add superfastblur filter > >> > >> Signed-off-by: Jun Zhao <barryjzhao@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 > > 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@ffmpeg.org > >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > >> > >> To unsubscribe, visit link above, or email > >> ffmpeg-devel-request@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@ffmpeg.org > > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > > > To unsubscribe, visit link above, or email > > ffmpeg-devel-request@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-request@ffmpeg.org with subject "unsubscribe".
If this filter is same speed or better than boxblur, it should replace boxblur filter, as boxblur filter is GPL. On 11/12/19, mypopy@gmail.com <mypopy@gmail.com> wrote: > On Tue, Nov 12, 2019 at 5:37 PM Paul B Mahol <onemda@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@chinaffmpeg.org> wrote: >> > >> > >> >> 在 2019年11月12日,15:51,Jun Zhao <mypopydev@gmail.com> 写道: >> >> >> >> From: Jun Zhao <barryjzhao@tencent.com> >> >> >> >> add superfastblur filter >> >> >> >> Signed-off-by: Jun Zhao <barryjzhao@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 >> > 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@ffmpeg.org >> >> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> >> >> >> To unsubscribe, visit link above, or email >> >> ffmpeg-devel-request@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@ffmpeg.org >> > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel >> > >> > To unsubscribe, visit link above, or email >> > ffmpeg-devel-request@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-request@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-request@ffmpeg.org with subject "unsubscribe".
On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > If this filter is same speed or better than boxblur, it should replace > boxblur filter, as boxblur filter is GPL. relicensing boxblur should not be hard if someone needs the code to be under lgpl [...]
On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: >> If this filter is same speed or better than boxblur, it should replace >> boxblur filter, as boxblur filter is GPL. > > relicensing boxblur should not be hard if someone needs the code to be > under lgpl I do not think so, look at geq, lots of devs no longer contactable, > > [...] > -- > Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB > > The educated differ from the uneducated as much as the living from the > dead. -- Aristotle >
On Wed, Nov 13, 2019 at 7:24 AM Paul B Mahol <onemda@gmail.com> wrote: > > On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > > On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > >> If this filter is same speed or better than boxblur, it should replace > >> boxblur filter, as boxblur filter is GPL. > > > > relicensing boxblur should not be hard if someone needs the code to be > > under lgpl > > I do not think so, look at geq, lots of devs no longer contactable, > Maybe we can keep both based on the license choice
> 在 2019年11月13日,09:02,mypopy@gmail.com 写道: > > On Wed, Nov 13, 2019 at 7:24 AM Paul B Mahol <onemda@gmail.com> wrote: >> >> On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: >>> On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: >>>> If this filter is same speed or better than boxblur, it should replace >>>> boxblur filter, as boxblur filter is GPL. >>> >>> relicensing boxblur should not be hard if someone needs the code to be >>> under lgpl >> >> I do not think so, look at geq, lots of devs no longer contactable, >> > Maybe we can keep both based on the license choice I think your suggestion is better :D > _______________________________________________ > ffmpeg-devel mailing list > ffmpeg-devel@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-devel > > To unsubscribe, visit link above, or email > ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". Thanks Steven
On Wed, Nov 13, 2019 at 12:24:34AM +0100, Paul B Mahol wrote: > On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > > On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > >> If this filter is same speed or better than boxblur, it should replace > >> boxblur filter, as boxblur filter is GPL. > > > > relicensing boxblur should not be hard if someone needs the code to be > > under lgpl > > I do not think so, look at geq, lots of devs no longer contactable, which lines of geq are written by a non contactable developer ? Iam happy to rewrite them same for boxblur btw thx [...]
On Wed, Nov 13, 2019 at 10:25:31AM +0800, Steven Liu wrote: > > > > 在 2019年11月13日,09:02,mypopy@gmail.com 写道: > > > > On Wed, Nov 13, 2019 at 7:24 AM Paul B Mahol <onemda@gmail.com> wrote: > >> > >> On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > >>> On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > >>>> If this filter is same speed or better than boxblur, it should replace > >>>> boxblur filter, as boxblur filter is GPL. > >>> > >>> relicensing boxblur should not be hard if someone needs the code to be > >>> under lgpl > >> > >> I do not think so, look at geq, lots of devs no longer contactable, > >> > > Maybe we can keep both based on the license choice > I think your suggestion is better :D I think the best is to get boxblur relicensed to LGPL and then put any improvments, if there are improvments into it. Avoiding a 2nd filter which does the same thing and using the filter name and syntax users already know Thanks [...]
On Wed, Nov 13, 2019 at 12:24:34AM +0100, Paul B Mahol wrote: > On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > > On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > >> If this filter is same speed or better than boxblur, it should replace > >> boxblur filter, as boxblur filter is GPL. > > > > relicensing boxblur should not be hard if someone needs the code to be > > under lgpl > > I do not think so, look at geq, lots of devs no longer contactable, who did you already contact about boxblur relicensing ? i looked at the log and at the changes and i see noone i think wouldnt reply whos change couldnt be rewritten in less than 5minutes maybe someone could be on vacation and not check their email for a month ... you know, just tell me who is the problem and which lines and ill either contact them, rewrite the code or just revert their change Thanks [...]
On Fri, Nov 15, 2019 at 1:26 AM Michael Niedermayer <michael@niedermayer.cc> wrote: > > On Wed, Nov 13, 2019 at 12:24:34AM +0100, Paul B Mahol wrote: > > On 11/13/19, Michael Niedermayer <michael@niedermayer.cc> wrote: > > > On Tue, Nov 12, 2019 at 12:48:09PM +0100, Paul B Mahol wrote: > > >> If this filter is same speed or better than boxblur, it should replace > > >> boxblur filter, as boxblur filter is GPL. > > > > > > relicensing boxblur should not be hard if someone needs the code to be > > > under lgpl > > > > I do not think so, look at geq, lots of devs no longer contactable, > > who did you already contact about boxblur relicensing ? > i looked at the log and at the changes and i see noone i think wouldnt > reply whos change couldnt be rewritten in less than 5minutes > maybe someone could be on vacation and not check their email for a month ... > > you know, just tell me who is the problem and which lines and ill either > contact them, rewrite the code or just revert their change > > Thanks > I am OK if we can relicese the boxblur and drop this patch. BTW: https://patchwork.ffmpeg.org/patch/16246/ is the other blur :)
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]; + + 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, +};