00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/eval.h"
00030 #include "libavutil/pixdesc.h"
00031 #include "avfilter.h"
00032
00033 static const char *const var_names[] = {
00034 "w",
00035 "h",
00036 "cw",
00037 "ch",
00038 "hsub",
00039 "vsub",
00040 NULL
00041 };
00042
00043 enum var_name {
00044 VAR_W,
00045 VAR_H,
00046 VAR_CW,
00047 VAR_CH,
00048 VAR_HSUB,
00049 VAR_VSUB,
00050 VARS_NB
00051 };
00052
00053 typedef struct {
00054 int radius;
00055 int power;
00056 } FilterParam;
00057
00058 typedef struct {
00059 FilterParam luma_param;
00060 FilterParam chroma_param;
00061 FilterParam alpha_param;
00062 char luma_radius_expr [256];
00063 char chroma_radius_expr[256];
00064 char alpha_radius_expr [256];
00065
00066 int hsub, vsub;
00067 int radius[4];
00068 int power[4];
00069 uint8_t *temp[2];
00070 } BoxBlurContext;
00071
00072 #define Y 0
00073 #define U 1
00074 #define V 2
00075 #define A 3
00076
00077 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
00078 {
00079 BoxBlurContext *boxblur = ctx->priv;
00080 int e;
00081
00082 if (!args) {
00083 av_log(ctx, AV_LOG_ERROR,
00084 "Filter expects 2 or 4 or 6 arguments, none provided\n");
00085 return AVERROR(EINVAL);
00086 }
00087
00088 e = sscanf(args, "%255[^:]:%d:%255[^:]:%d:%255[^:]:%d",
00089 boxblur->luma_radius_expr, &boxblur->luma_param .power,
00090 boxblur->chroma_radius_expr, &boxblur->chroma_param.power,
00091 boxblur->alpha_radius_expr, &boxblur->alpha_param .power);
00092
00093 if (e != 2 && e != 4 && e != 6) {
00094 av_log(ctx, AV_LOG_ERROR,
00095 "Filter expects 2 or 4 or 6 params, provided %d\n", e);
00096 return AVERROR(EINVAL);
00097 }
00098
00099 if (e < 4) {
00100 boxblur->chroma_param.power = boxblur->luma_param.power;
00101 av_strlcpy(boxblur->chroma_radius_expr, boxblur->luma_radius_expr,
00102 sizeof(boxblur->chroma_radius_expr));
00103 }
00104 if (e < 6) {
00105 boxblur->alpha_param.power = boxblur->luma_param.power;
00106 av_strlcpy(boxblur->alpha_radius_expr, boxblur->luma_radius_expr,
00107 sizeof(boxblur->alpha_radius_expr));
00108 }
00109
00110 return 0;
00111 }
00112
00113 static av_cold void uninit(AVFilterContext *ctx)
00114 {
00115 BoxBlurContext *boxblur = ctx->priv;
00116
00117 av_freep(&boxblur->temp[0]);
00118 av_freep(&boxblur->temp[1]);
00119 }
00120
00121 static int query_formats(AVFilterContext *ctx)
00122 {
00123 enum PixelFormat pix_fmts[] = {
00124 PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV420P,
00125 PIX_FMT_YUV411P, PIX_FMT_YUV410P, PIX_FMT_YUVA420P,
00126 PIX_FMT_YUV440P, PIX_FMT_GRAY8,
00127 PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P,
00128 PIX_FMT_YUVJ440P,
00129 PIX_FMT_NONE
00130 };
00131
00132 avfilter_set_common_pixel_formats(ctx, avfilter_make_format_list(pix_fmts));
00133 return 0;
00134 }
00135
00136 static int config_input(AVFilterLink *inlink)
00137 {
00138 AVFilterContext *ctx = inlink->dst;
00139 BoxBlurContext *boxblur = ctx->priv;
00140 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[inlink->format];
00141 int w = inlink->w, h = inlink->h;
00142 int cw, ch;
00143 double var_values[VARS_NB], res;
00144 char *expr;
00145 int ret;
00146
00147 if (!(boxblur->temp[0] = av_malloc(FFMAX(w, h))) ||
00148 !(boxblur->temp[1] = av_malloc(FFMAX(w, h))))
00149 return AVERROR(ENOMEM);
00150
00151 boxblur->hsub = desc->log2_chroma_w;
00152 boxblur->vsub = desc->log2_chroma_h;
00153
00154 var_values[VAR_W] = inlink->w;
00155 var_values[VAR_H] = inlink->h;
00156 var_values[VAR_CW] = cw = w>>boxblur->hsub;
00157 var_values[VAR_CH] = ch = h>>boxblur->vsub;
00158 var_values[VAR_HSUB] = 1<<boxblur->hsub;
00159 var_values[VAR_VSUB] = 1<<boxblur->vsub;
00160
00161 #define EVAL_RADIUS_EXPR(comp) \
00162 expr = boxblur->comp##_radius_expr; \
00163 ret = av_expr_parse_and_eval(&res, expr, var_names, var_values, \
00164 NULL, NULL, NULL, NULL, NULL, 0, ctx); \
00165 boxblur->comp##_param.radius = res; \
00166 if (ret < 0) { \
00167 av_log(NULL, AV_LOG_ERROR, \
00168 "Error when evaluating " #comp " radius expression '%s'\n", expr); \
00169 return ret; \
00170 }
00171 EVAL_RADIUS_EXPR(luma);
00172 EVAL_RADIUS_EXPR(chroma);
00173 EVAL_RADIUS_EXPR(alpha);
00174
00175 av_log(ctx, AV_LOG_INFO,
00176 "luma_radius:%d luma_power:%d "
00177 "chroma_radius:%d chroma_power:%d "
00178 "alpha_radius:%d alpha_power:%d "
00179 "w:%d chroma_w:%d h:%d chroma_h:%d\n",
00180 boxblur->luma_param .radius, boxblur->luma_param .power,
00181 boxblur->chroma_param.radius, boxblur->chroma_param.power,
00182 boxblur->alpha_param .radius, boxblur->alpha_param .power,
00183 w, cw, h, ch);
00184
00185 #define CHECK_RADIUS_VAL(w_, h_, comp) \
00186 if (boxblur->comp##_param.radius < 0 || \
00187 2*boxblur->comp##_param.radius > FFMIN(w_, h_)) { \
00188 av_log(ctx, AV_LOG_ERROR, \
00189 "Invalid " #comp " radius value %d, must be >= 0 and <= %d\n", \
00190 boxblur->comp##_param.radius, FFMIN(w_, h_)/2); \
00191 return AVERROR(EINVAL); \
00192 }
00193 CHECK_RADIUS_VAL(w, h, luma);
00194 CHECK_RADIUS_VAL(cw, ch, chroma);
00195 CHECK_RADIUS_VAL(w, h, alpha);
00196
00197 boxblur->radius[Y] = boxblur->luma_param.radius;
00198 boxblur->radius[U] = boxblur->radius[V] = boxblur->chroma_param.radius;
00199 boxblur->radius[A] = boxblur->alpha_param.radius;
00200
00201 boxblur->power[Y] = boxblur->luma_param.power;
00202 boxblur->power[U] = boxblur->power[V] = boxblur->chroma_param.power;
00203 boxblur->power[A] = boxblur->alpha_param.power;
00204
00205 return 0;
00206 }
00207
00208 static inline void blur(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
00209 int len, int radius)
00210 {
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 int x, sum = 0;
00226 const int length = radius*2 + 1;
00227 const int inv = ((1<<16) + length/2)/length;
00228
00229 for (x = 0; x < radius; x++)
00230 sum += src[x*src_step]<<1;
00231 sum += src[radius*src_step];
00232
00233 for (x = 0; x <= radius; x++) {
00234 sum += src[(radius+x)*src_step] - src[(radius-x)*src_step];
00235 dst[x*dst_step] = (sum*inv + (1<<15))>>16;
00236 }
00237
00238 for (; x < len-radius; x++) {
00239 sum += src[(radius+x)*src_step] - src[(x-radius-1)*src_step];
00240 dst[x*dst_step] = (sum*inv + (1<<15))>>16;
00241 }
00242
00243 for (; x < len; x++) {
00244 sum += src[(2*len-radius-x-1)*src_step] - src[(x-radius-1)*src_step];
00245 dst[x*dst_step] = (sum*inv + (1<<15))>>16;
00246 }
00247 }
00248
00249 static inline void blur_power(uint8_t *dst, int dst_step, const uint8_t *src, int src_step,
00250 int len, int radius, int power, uint8_t *temp[2])
00251 {
00252 uint8_t *a = temp[0], *b = temp[1];
00253
00254 if (radius && power) {
00255 blur(a, 1, src, src_step, len, radius);
00256 for (; power > 2; power--) {
00257 uint8_t *c;
00258 blur(b, 1, a, 1, len, radius);
00259 c = a; a = b; b = c;
00260 }
00261 if (power > 1) {
00262 blur(dst, dst_step, a, 1, len, radius);
00263 } else {
00264 int i;
00265 for (i = 0; i < len; i++)
00266 dst[i*dst_step] = a[i];
00267 }
00268 } else {
00269 int i;
00270 for (i = 0; i < len; i++)
00271 dst[i*dst_step] = src[i*src_step];
00272 }
00273 }
00274
00275 static void hblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize,
00276 int w, int h, int radius, int power, uint8_t *temp[2])
00277 {
00278 int y;
00279
00280 if (radius == 0 && dst == src)
00281 return;
00282
00283 for (y = 0; y < h; y++)
00284 blur_power(dst + y*dst_linesize, 1, src + y*src_linesize, 1,
00285 w, radius, power, temp);
00286 }
00287
00288 static void vblur(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize,
00289 int w, int h, int radius, int power, uint8_t *temp[2])
00290 {
00291 int x;
00292
00293 if (radius == 0 && dst == src)
00294 return;
00295
00296 for (x = 0; x < w; x++)
00297 blur_power(dst + x, dst_linesize, src + x, src_linesize,
00298 h, radius, power, temp);
00299 }
00300
00301 static void null_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { }
00302
00303 static void end_frame(AVFilterLink *inlink)
00304 {
00305 AVFilterContext *ctx = inlink->dst;
00306 BoxBlurContext *boxblur = ctx->priv;
00307 AVFilterLink *outlink = inlink->dst->outputs[0];
00308 AVFilterBufferRef *inpicref = inlink ->cur_buf;
00309 AVFilterBufferRef *outpicref = outlink->out_buf;
00310 int plane;
00311 int cw = inlink->w >> boxblur->hsub, ch = inlink->h >> boxblur->vsub;
00312 int w[4] = { inlink->w, cw, cw, inlink->w };
00313 int h[4] = { inlink->h, ch, ch, inlink->h };
00314
00315 for (plane = 0; inpicref->data[plane] && plane < 4; plane++)
00316 hblur(outpicref->data[plane], outpicref->linesize[plane],
00317 inpicref ->data[plane], inpicref ->linesize[plane],
00318 w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane],
00319 boxblur->temp);
00320
00321 for (plane = 0; inpicref->data[plane] && plane < 4; plane++)
00322 vblur(outpicref->data[plane], outpicref->linesize[plane],
00323 outpicref->data[plane], outpicref->linesize[plane],
00324 w[plane], h[plane], boxblur->radius[plane], boxblur->power[plane],
00325 boxblur->temp);
00326
00327 avfilter_draw_slice(outlink, 0, inlink->h, 1);
00328 avfilter_default_end_frame(inlink);
00329 }
00330
00331 AVFilter avfilter_vf_boxblur = {
00332 .name = "boxblur",
00333 .description = NULL_IF_CONFIG_SMALL("Blur the input."),
00334 .priv_size = sizeof(BoxBlurContext),
00335 .init = init,
00336 .uninit = uninit,
00337 .query_formats = query_formats,
00338
00339 .inputs = (const AVFilterPad[]) {{ .name = "default",
00340 .type = AVMEDIA_TYPE_VIDEO,
00341 .config_props = config_input,
00342 .draw_slice = null_draw_slice,
00343 .end_frame = end_frame,
00344 .min_perms = AV_PERM_READ },
00345 { .name = NULL}},
00346 .outputs = (const AVFilterPad[]) {{ .name = "default",
00347 .type = AVMEDIA_TYPE_VIDEO, },
00348 { .name = NULL}},
00349 };