diff options
Diffstat (limited to 'libavfilter/vf_boxblur.c')
-rw-r--r-- | libavfilter/vf_boxblur.c | 216 |
1 files changed, 132 insertions, 84 deletions
diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c index 4cbfe2c..bcf0ca5 100644 --- a/libavfilter/vf_boxblur.c +++ b/libavfilter/vf_boxblur.c @@ -2,20 +2,20 @@ * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at> * Copyright (c) 2011 Stefano Sabatini * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or modify + * FFmpeg is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along - * with Libav; if not, write to the Free Software Foundation, Inc., + * with FFmpeg; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ @@ -58,6 +58,7 @@ enum var_name { typedef struct FilterParam { int radius; int power; + char *radius_expr; } FilterParam; typedef struct BoxBlurContext { @@ -65,9 +66,6 @@ typedef struct BoxBlurContext { FilterParam luma_param; FilterParam chroma_param; FilterParam alpha_param; - char *luma_radius_expr; - char *chroma_radius_expr; - char *alpha_radius_expr; int hsub, vsub; int radius[4]; @@ -84,23 +82,27 @@ static av_cold int init(AVFilterContext *ctx) { BoxBlurContext *s = ctx->priv; - if (!s->luma_radius_expr) { + if (!s->luma_param.radius_expr) { av_log(ctx, AV_LOG_ERROR, "Luma radius expression is not set.\n"); return AVERROR(EINVAL); } - if (!s->chroma_radius_expr) { - s->chroma_radius_expr = av_strdup(s->luma_radius_expr); - if (!s->chroma_radius_expr) + /* fill missing params */ + if (!s->chroma_param.radius_expr) { + s->chroma_param.radius_expr = av_strdup(s->luma_param.radius_expr); + if (!s->chroma_param.radius_expr) return AVERROR(ENOMEM); - s->chroma_param.power = s->luma_param.power; } - if (!s->alpha_radius_expr) { - s->alpha_radius_expr = av_strdup(s->luma_radius_expr); - if (!s->alpha_radius_expr) + if (s->chroma_param.power < 0) + s->chroma_param.power = s->luma_param.power; + + if (!s->alpha_param.radius_expr) { + s->alpha_param.radius_expr = av_strdup(s->luma_param.radius_expr); + if (!s->alpha_param.radius_expr) return AVERROR(ENOMEM); - s->alpha_param.power = s->luma_param.power; } + if (s->alpha_param.power < 0) + s->alpha_param.power = s->luma_param.power; return 0; } @@ -115,16 +117,18 @@ static av_cold void uninit(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx) { - enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA420P, - AV_PIX_FMT_YUV440P, AV_PIX_FMT_GRAY8, - AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, - AV_PIX_FMT_YUVJ440P, - AV_PIX_FMT_NONE - }; - - ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); + AVFilterFormats *formats = NULL; + int fmt; + + for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (!(desc->flags & (AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM | AV_PIX_FMT_FLAG_PAL)) && + (desc->flags & AV_PIX_FMT_FLAG_PLANAR || desc->nb_components == 1) && + (!(desc->flags & AV_PIX_FMT_FLAG_BE) == !HAVE_BIGENDIAN || desc->comp[0].depth_minus1 == 7)) + ff_add_format(&formats, fmt); + } + + ff_set_common_formats(ctx, formats); return 0; } @@ -139,14 +143,9 @@ static int config_input(AVFilterLink *inlink) char *expr; int ret; - av_freep(&s->temp[0]); - av_freep(&s->temp[1]); - if (!(s->temp[0] = av_malloc(FFMAX(w, h)))) - return AVERROR(ENOMEM); - if (!(s->temp[1] = av_malloc(FFMAX(w, h)))) { - av_freep(&s->temp[0]); + if (!(s->temp[0] = av_malloc(2*FFMAX(w, h))) || + !(s->temp[1] = av_malloc(2*FFMAX(w, h)))) return AVERROR(ENOMEM); - } s->hsub = desc->log2_chroma_w; s->vsub = desc->log2_chroma_h; @@ -159,7 +158,7 @@ static int config_input(AVFilterLink *inlink) var_values[VAR_VSUB] = 1<<s->vsub; #define EVAL_RADIUS_EXPR(comp) \ - expr = s->comp##_radius_expr; \ + expr = s->comp##_param.radius_expr; \ ret = av_expr_parse_and_eval(&res, expr, var_names, var_values, \ NULL, NULL, NULL, NULL, NULL, 0, ctx); \ s->comp##_param.radius = res; \ @@ -172,7 +171,7 @@ static int config_input(AVFilterLink *inlink) EVAL_RADIUS_EXPR(chroma); EVAL_RADIUS_EXPR(alpha); - av_log(ctx, AV_LOG_DEBUG, + av_log(ctx, AV_LOG_VERBOSE, "luma_radius:%d luma_power:%d " "chroma_radius:%d chroma_power:%d " "alpha_radius:%d alpha_power:%d " @@ -205,7 +204,7 @@ static int config_input(AVFilterLink *inlink) return 0; } -static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_step, +static inline void blur8(uint8_t *dst, int dst_step, const uint8_t *src, int src_step, int len, int radius) { /* Naive boxblur would sum source pixels from x-radius .. x+radius @@ -224,56 +223,100 @@ static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_ */ const int length = radius*2 + 1; const int inv = ((1<<16) + length/2)/length; - int x, sum = 0; + int x, sum = src[radius*src_step]; for (x = 0; x < radius; x++) sum += src[x*src_step]<<1; - sum += src[radius*src_step]; + + sum = sum*inv + (1<<15); for (x = 0; x <= radius; x++) { - sum += src[(radius+x)*src_step] - src[(radius-x)*src_step]; - dst[x*dst_step] = (sum*inv + (1<<15))>>16; + sum += (src[(radius+x)*src_step] - src[(radius-x)*src_step])*inv; + dst[x*dst_step] = sum>>16; } for (; x < len-radius; x++) { - sum += src[(radius+x)*src_step] - src[(x-radius-1)*src_step]; - dst[x*dst_step] = (sum*inv + (1<<15))>>16; + sum += (src[(radius+x)*src_step] - src[(x-radius-1)*src_step])*inv; + dst[x*dst_step] = sum >>16; } for (; x < len; x++) { - sum += src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step]; - dst[x*dst_step] = (sum*inv + (1<<15))>>16; + sum += (src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step])*inv; + dst[x*dst_step] = sum>>16; } } +static inline void blur16(uint16_t *dst, int dst_step, const uint16_t *src, int src_step, + int len, int radius) +{ + const int length = radius*2 + 1; + const int inv = ((1<<16) + length/2)/length; + int x, sum = src[radius*src_step]; + + for (x = 0; x < radius; x++) + sum += src[x*src_step]<<1; + + sum = sum*inv + (1<<15); + + for (x = 0; x <= radius; x++) { + sum += (src[(radius+x)*src_step] - src[(radius-x)*src_step])*inv; + dst[x*dst_step] = sum>>16; + } + + for (; x < len-radius; x++) { + sum += (src[(radius+x)*src_step] - src[(x-radius-1)*src_step])*inv; + dst[x*dst_step] = sum >>16; + } + + for (; x < len; x++) { + sum += (src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step])*inv; + dst[x*dst_step] = sum>>16; + } +} + +static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_step, + int len, int radius, int pixsize) +{ + if (pixsize == 1) blur8 (dst, dst_step , src, src_step , len, radius); + else blur16((uint16_t*)dst, dst_step>>1, (const uint16_t*)src, src_step>>1, len, radius); +} + static inline void blur_power(uint8_t *dst, int dst_step, const uint8_t *src, int src_step, - int len, int radius, int power, uint8_t *temp[2]) + int len, int radius, int power, uint8_t *temp[2], int pixsize) { uint8_t *a = temp[0], *b = temp[1]; if (radius && power) { - blur(a, 1, src, src_step, len, radius); + blur(a, pixsize, src, src_step, len, radius, pixsize); for (; power > 2; power--) { uint8_t *c; - blur(b, 1, a, 1, len, radius); + blur(b, pixsize, a, pixsize, len, radius, pixsize); c = a; a = b; b = c; } if (power > 1) { - blur(dst, dst_step, a, 1, len, radius); + blur(dst, dst_step, a, pixsize, len, radius, pixsize); } else { int i; - for (i = 0; i < len; i++) - dst[i*dst_step] = a[i]; + if (pixsize == 1) { + for (i = 0; i < len; i++) + dst[i*dst_step] = a[i]; + } else + for (i = 0; i < len; i++) + *(uint16_t*)(dst + i*dst_step) = ((uint16_t*)a)[i]; } } else { int i; - for (i = 0; i < len; i++) - dst[i*dst_step] = src[i*src_step]; + if (pixsize == 1) { + for (i = 0; i < len; i++) + dst[i*dst_step] = src[i*src_step]; + } else + for (i = 0; i < len; i++) + *(uint16_t*)(dst + i*dst_step) = *(uint16_t*)(src + i*src_step); } } static void hblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, - int w, int h, int radius, int power, uint8_t *temp[2]) + int w, int h, int radius, int power, uint8_t *temp[2], int pixsize) { int y; @@ -281,12 +324,12 @@ static void hblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li return; for (y = 0; y < h; y++) - blur_power(dst + y*dst_linesize, 1, src + y*src_linesize, 1, - w, radius, power, temp); + blur_power(dst + y*dst_linesize, pixsize, src + y*src_linesize, pixsize, + w, radius, power, temp, pixsize); } static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, - int w, int h, int radius, int power, uint8_t *temp[2]) + int w, int h, int radius, int power, uint8_t *temp[2], int pixsize) { int x; @@ -294,8 +337,8 @@ static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_li return; for (x = 0; x < w; x++) - blur_power(dst + x, dst_linesize, src + x, src_linesize, - h, radius, power, temp); + blur_power(dst + x*pixsize, dst_linesize, src + x*pixsize, src_linesize, + h, radius, power, temp, pixsize); } static int filter_frame(AVFilterLink *inlink, AVFrame *in) @@ -305,9 +348,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = inlink->dst->outputs[0]; AVFrame *out; int plane; - int cw = inlink->w >> s->hsub, ch = in->height >> s->vsub; + int cw = FF_CEIL_RSHIFT(inlink->w, s->hsub), ch = FF_CEIL_RSHIFT(in->height, s->vsub); int w[4] = { inlink->w, cw, cw, inlink->w }; int h[4] = { in->height, ch, ch, in->height }; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + const int depth = desc->comp[0].depth_minus1 + 1; + const int pixsize = (depth+7)/8; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { @@ -316,17 +362,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_copy_props(out, in); - for (plane = 0; in->data[plane] && plane < 4; plane++) + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) hblur(out->data[plane], out->linesize[plane], in ->data[plane], in ->linesize[plane], w[plane], h[plane], s->radius[plane], s->power[plane], - s->temp); + s->temp, pixsize); - for (plane = 0; in->data[plane] && plane < 4; plane++) + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) vblur(out->data[plane], out->linesize[plane], out->data[plane], out->linesize[plane], w[plane], h[plane], s->radius[plane], s->power[plane], - s->temp); + s->temp, pixsize); av_frame_free(&in); @@ -334,27 +380,29 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } #define OFFSET(x) offsetof(BoxBlurContext, x) -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM -static const AVOption options[] = { - { "luma_radius", "Radius of the luma blurring box", OFFSET(luma_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "luma_power", "How many times should the boxblur be applied to luma", - OFFSET(luma_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS }, - { "chroma_radius", "Radius of the chroma blurring box", OFFSET(chroma_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "chroma_power", "How many times should the boxblur be applied to chroma", - OFFSET(chroma_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS }, - { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_radius_expr), AV_OPT_TYPE_STRING, .flags = FLAGS }, - { "alpha_power", "How many times should the boxblur be applied to alpha", - OFFSET(alpha_param.power), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, FLAGS }, - { NULL }, -}; +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption boxblur_options[] = { + { "luma_radius", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS }, + { "lr", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS }, + { "luma_power", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS }, + { "lp", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS }, -static const AVClass boxblur_class = { - .class_name = "boxblur", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, + { "chroma_radius", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "cr", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "chroma_power", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + { "cp", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + + { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "ar", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "alpha_power", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + { "ap", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + + { NULL } }; +AVFILTER_DEFINE_CLASS(boxblur); + static const AVFilterPad avfilter_vf_boxblur_inputs[] = { { .name = "default", @@ -381,7 +429,7 @@ AVFilter ff_vf_boxblur = { .init = init, .uninit = uninit, .query_formats = query_formats, - - .inputs = avfilter_vf_boxblur_inputs, - .outputs = avfilter_vf_boxblur_outputs, + .inputs = avfilter_vf_boxblur_inputs, + .outputs = avfilter_vf_boxblur_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; |