00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include "libavutil/common.h"
00028 #include "libavutil/eval.h"
00029 #include "libavutil/opt.h"
00030 #include "libavutil/pixdesc.h"
00031 #include "avfilter.h"
00032 #include "formats.h"
00033 #include "internal.h"
00034 #include "video.h"
00035
00036 static const char *const var_names[] = {
00037 "w",
00038 "h",
00039 "val",
00040 "maxval",
00041 "minval",
00042 "negval",
00043 "clipval",
00044 NULL
00045 };
00046
00047 enum var_name {
00048 VAR_W,
00049 VAR_H,
00050 VAR_VAL,
00051 VAR_MAXVAL,
00052 VAR_MINVAL,
00053 VAR_NEGVAL,
00054 VAR_CLIPVAL,
00055 VAR_VARS_NB
00056 };
00057
00058 typedef struct {
00059 const AVClass *class;
00060 uint8_t lut[4][256];
00061 char *comp_expr_str[4];
00062 AVExpr *comp_expr[4];
00063 int hsub, vsub;
00064 double var_values[VAR_VARS_NB];
00065 int is_rgb, is_yuv;
00066 int step;
00067 int negate_alpha;
00068 } LutContext;
00069
00070 #define Y 0
00071 #define U 1
00072 #define V 2
00073 #define R 0
00074 #define G 1
00075 #define B 2
00076 #define A 3
00077
00078 #define OFFSET(x) offsetof(LutContext, x)
00079 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
00080
00081 static const AVOption options[] = {
00082 {"c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00083 {"c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00084 {"c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00085 {"c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00086 {"y", "set Y expression", OFFSET(comp_expr_str[Y]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00087 {"u", "set U expression", OFFSET(comp_expr_str[U]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00088 {"v", "set V expression", OFFSET(comp_expr_str[V]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00089 {"r", "set R expression", OFFSET(comp_expr_str[R]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00090 {"g", "set G expression", OFFSET(comp_expr_str[G]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00091 {"b", "set B expression", OFFSET(comp_expr_str[B]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00092 {"a", "set A expression", OFFSET(comp_expr_str[A]), AV_OPT_TYPE_STRING, {.str="val"}, CHAR_MIN, CHAR_MAX, FLAGS},
00093 {NULL},
00094 };
00095
00096 static av_cold void uninit(AVFilterContext *ctx)
00097 {
00098 LutContext *lut = ctx->priv;
00099 int i;
00100
00101 for (i = 0; i < 4; i++) {
00102 av_expr_free(lut->comp_expr[i]);
00103 lut->comp_expr[i] = NULL;
00104 av_freep(&lut->comp_expr_str[i]);
00105 }
00106 }
00107
00108 #define YUV_FORMATS \
00109 PIX_FMT_YUV444P, PIX_FMT_YUV422P, PIX_FMT_YUV420P, \
00110 PIX_FMT_YUV411P, PIX_FMT_YUV410P, PIX_FMT_YUV440P, \
00111 PIX_FMT_YUVA420P, \
00112 PIX_FMT_YUVJ444P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ420P, \
00113 PIX_FMT_YUVJ440P
00114
00115 #define RGB_FORMATS \
00116 PIX_FMT_ARGB, PIX_FMT_RGBA, \
00117 PIX_FMT_ABGR, PIX_FMT_BGRA, \
00118 PIX_FMT_RGB24, PIX_FMT_BGR24
00119
00120 static const enum PixelFormat yuv_pix_fmts[] = { YUV_FORMATS, PIX_FMT_NONE };
00121 static const enum PixelFormat rgb_pix_fmts[] = { RGB_FORMATS, PIX_FMT_NONE };
00122 static const enum PixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, PIX_FMT_NONE };
00123
00124 static int query_formats(AVFilterContext *ctx)
00125 {
00126 LutContext *lut = ctx->priv;
00127
00128 const enum PixelFormat *pix_fmts = lut->is_rgb ? rgb_pix_fmts :
00129 lut->is_yuv ? yuv_pix_fmts : all_pix_fmts;
00130
00131 ff_set_common_formats(ctx, ff_make_format_list(pix_fmts));
00132 return 0;
00133 }
00134
00138 static double clip(void *opaque, double val)
00139 {
00140 LutContext *lut = opaque;
00141 double minval = lut->var_values[VAR_MINVAL];
00142 double maxval = lut->var_values[VAR_MAXVAL];
00143
00144 return av_clip(val, minval, maxval);
00145 }
00146
00151 static double compute_gammaval(void *opaque, double gamma)
00152 {
00153 LutContext *lut = opaque;
00154 double val = lut->var_values[VAR_CLIPVAL];
00155 double minval = lut->var_values[VAR_MINVAL];
00156 double maxval = lut->var_values[VAR_MAXVAL];
00157
00158 return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval;
00159 }
00160
00161 static double (* const funcs1[])(void *, double) = {
00162 (void *)clip,
00163 (void *)compute_gammaval,
00164 NULL
00165 };
00166
00167 static const char * const funcs1_names[] = {
00168 "clip",
00169 "gammaval",
00170 NULL
00171 };
00172
00173 static int config_props(AVFilterLink *inlink)
00174 {
00175 AVFilterContext *ctx = inlink->dst;
00176 LutContext *lut = ctx->priv;
00177 const AVPixFmtDescriptor *desc = &av_pix_fmt_descriptors[inlink->format];
00178 int rgba_map[4];
00179 int min[4], max[4];
00180 int val, comp, ret;
00181
00182 lut->hsub = desc->log2_chroma_w;
00183 lut->vsub = desc->log2_chroma_h;
00184
00185 lut->var_values[VAR_W] = inlink->w;
00186 lut->var_values[VAR_H] = inlink->h;
00187
00188 switch (inlink->format) {
00189 case PIX_FMT_YUV410P:
00190 case PIX_FMT_YUV411P:
00191 case PIX_FMT_YUV420P:
00192 case PIX_FMT_YUV422P:
00193 case PIX_FMT_YUV440P:
00194 case PIX_FMT_YUV444P:
00195 case PIX_FMT_YUVA420P:
00196 min[Y] = min[U] = min[V] = 16;
00197 max[Y] = 235;
00198 max[U] = max[V] = 240;
00199 min[A] = 0; max[A] = 255;
00200 break;
00201 default:
00202 min[0] = min[1] = min[2] = min[3] = 0;
00203 max[0] = max[1] = max[2] = max[3] = 255;
00204 }
00205
00206 lut->is_yuv = lut->is_rgb = 0;
00207 if (ff_fmt_is_in(inlink->format, yuv_pix_fmts)) lut->is_yuv = 1;
00208 else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) lut->is_rgb = 1;
00209
00210 if (lut->is_rgb) {
00211 switch (inlink->format) {
00212 case PIX_FMT_ARGB: rgba_map[0] = A; rgba_map[1] = R; rgba_map[2] = G; rgba_map[3] = B; break;
00213 case PIX_FMT_ABGR: rgba_map[0] = A; rgba_map[1] = B; rgba_map[2] = G; rgba_map[3] = R; break;
00214 case PIX_FMT_RGBA:
00215 case PIX_FMT_RGB24: rgba_map[0] = R; rgba_map[1] = G; rgba_map[2] = B; rgba_map[3] = A; break;
00216 case PIX_FMT_BGRA:
00217 case PIX_FMT_BGR24: rgba_map[0] = B; rgba_map[1] = G; rgba_map[2] = R; rgba_map[3] = A; break;
00218 }
00219 lut->step = av_get_bits_per_pixel(desc) >> 3;
00220 }
00221
00222 for (comp = 0; comp < desc->nb_components; comp++) {
00223 double res;
00224 int color = lut->is_rgb ? rgba_map[comp] : comp;
00225
00226
00227 ret = av_expr_parse(&lut->comp_expr[color], lut->comp_expr_str[color],
00228 var_names, funcs1_names, funcs1, NULL, NULL, 0, ctx);
00229 if (ret < 0) {
00230 av_log(ctx, AV_LOG_ERROR,
00231 "Error when parsing the expression '%s' for the component %d and color %d.\n",
00232 lut->comp_expr_str[comp], comp, color);
00233 return AVERROR(EINVAL);
00234 }
00235
00236
00237 lut->var_values[VAR_MAXVAL] = max[color];
00238 lut->var_values[VAR_MINVAL] = min[color];
00239
00240 for (val = 0; val < 256; val++) {
00241 lut->var_values[VAR_VAL] = val;
00242 lut->var_values[VAR_CLIPVAL] = av_clip(val, min[color], max[color]);
00243 lut->var_values[VAR_NEGVAL] =
00244 av_clip(min[color] + max[color] - lut->var_values[VAR_VAL],
00245 min[color], max[color]);
00246
00247 res = av_expr_eval(lut->comp_expr[color], lut->var_values, lut);
00248 if (isnan(res)) {
00249 av_log(ctx, AV_LOG_ERROR,
00250 "Error when evaluating the expression '%s' for the value %d for the component %d.\n",
00251 lut->comp_expr_str[color], val, comp);
00252 return AVERROR(EINVAL);
00253 }
00254 lut->lut[comp][val] = av_clip((int)res, min[color], max[color]);
00255 av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, lut->lut[comp][val]);
00256 }
00257 }
00258
00259 return 0;
00260 }
00261
00262 static int draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
00263 {
00264 AVFilterContext *ctx = inlink->dst;
00265 LutContext *lut = ctx->priv;
00266 AVFilterLink *outlink = ctx->outputs[0];
00267 AVFilterBufferRef *inpic = inlink ->cur_buf;
00268 AVFilterBufferRef *outpic = outlink->out_buf;
00269 uint8_t *inrow, *outrow, *inrow0, *outrow0;
00270 int i, j, plane;
00271
00272 if (lut->is_rgb) {
00273
00274 inrow0 = inpic ->data[0] + y * inpic ->linesize[0];
00275 outrow0 = outpic->data[0] + y * outpic->linesize[0];
00276
00277 for (i = 0; i < h; i ++) {
00278 int w = inlink->w;
00279 const uint8_t (*tab)[256] = (const uint8_t (*)[256])lut->lut;
00280 inrow = inrow0;
00281 outrow = outrow0;
00282 for (j = 0; j < w; j++) {
00283 outrow[0] = tab[0][inrow[0]];
00284 if (lut->step>1) {
00285 outrow[1] = tab[1][inrow[1]];
00286 if (lut->step>2) {
00287 outrow[2] = tab[2][inrow[2]];
00288 if (lut->step>3) {
00289 outrow[3] = tab[3][inrow[3]];
00290 }
00291 }
00292 }
00293 outrow += lut->step;
00294 inrow += lut->step;
00295 }
00296 inrow0 += inpic ->linesize[0];
00297 outrow0 += outpic->linesize[0];
00298 }
00299 } else {
00300
00301 for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
00302 int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
00303 int hsub = plane == 1 || plane == 2 ? lut->hsub : 0;
00304
00305 inrow = inpic ->data[plane] + (y>>vsub) * inpic ->linesize[plane];
00306 outrow = outpic->data[plane] + (y>>vsub) * outpic->linesize[plane];
00307
00308 for (i = 0; i < (h + (1<<vsub) - 1)>>vsub; i ++) {
00309 const uint8_t *tab = lut->lut[plane];
00310 int w = (inlink->w + (1<<hsub) - 1)>>hsub;
00311 for (j = 0; j < w; j++)
00312 outrow[j] = tab[inrow[j]];
00313 inrow += inpic ->linesize[plane];
00314 outrow += outpic->linesize[plane];
00315 }
00316 }
00317 }
00318
00319 return ff_draw_slice(outlink, y, h, slice_dir);
00320 }
00321
00322 static const AVFilterPad inputs[] = {
00323 { .name = "default",
00324 .type = AVMEDIA_TYPE_VIDEO,
00325 .draw_slice = draw_slice,
00326 .config_props = config_props,
00327 .min_perms = AV_PERM_READ, },
00328 { .name = NULL}
00329 };
00330 static const AVFilterPad outputs[] = {
00331 { .name = "default",
00332 .type = AVMEDIA_TYPE_VIDEO, },
00333 { .name = NULL}
00334 };
00335 #define DEFINE_LUT_FILTER(name_, description_) \
00336 AVFilter avfilter_vf_##name_ = { \
00337 .name = #name_, \
00338 .description = NULL_IF_CONFIG_SMALL(description_), \
00339 .priv_size = sizeof(LutContext), \
00340 \
00341 .init = name_##_init, \
00342 .uninit = uninit, \
00343 .query_formats = query_formats, \
00344 \
00345 .inputs = inputs, \
00346 .outputs = outputs, \
00347 .priv_class = &name_##_class, \
00348 }
00349
00350 #if CONFIG_LUT_FILTER
00351
00352 #define lut_options options
00353 AVFILTER_DEFINE_CLASS(lut);
00354
00355 static int lut_init(AVFilterContext *ctx, const char *args)
00356 {
00357 LutContext *lut = ctx->priv;
00358 int ret;
00359
00360 lut->class = &lut_class;
00361 av_opt_set_defaults(lut);
00362
00363 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00364 return ret;
00365
00366 return 0;
00367 }
00368
00369 DEFINE_LUT_FILTER(lut, "Compute and apply a lookup table to the RGB/YUV input video.");
00370 #endif
00371
00372 #if CONFIG_LUTYUV_FILTER
00373
00374 #define lutyuv_options options
00375 AVFILTER_DEFINE_CLASS(lutyuv);
00376
00377 static int lutyuv_init(AVFilterContext *ctx, const char *args)
00378 {
00379 LutContext *lut = ctx->priv;
00380 int ret;
00381
00382 lut->class = &lutyuv_class;
00383 lut->is_yuv = 1;
00384 av_opt_set_defaults(lut);
00385
00386 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00387 return ret;
00388
00389 return 0;
00390 }
00391
00392 DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.");
00393 #endif
00394
00395 #if CONFIG_LUTRGB_FILTER
00396
00397 #define lutrgb_options options
00398 AVFILTER_DEFINE_CLASS(lutrgb);
00399
00400 static int lutrgb_init(AVFilterContext *ctx, const char *args)
00401 {
00402 LutContext *lut = ctx->priv;
00403 int ret;
00404
00405 lut->class = &lutrgb_class;
00406 lut->is_rgb = 1;
00407 av_opt_set_defaults(lut);
00408
00409 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00410 return ret;
00411
00412 return 0;
00413 }
00414
00415 DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.");
00416 #endif
00417
00418 #if CONFIG_NEGATE_FILTER
00419
00420 #define negate_options options
00421 AVFILTER_DEFINE_CLASS(negate);
00422
00423 static int negate_init(AVFilterContext *ctx, const char *args)
00424 {
00425 LutContext *lut = ctx->priv;
00426 char lut_params[64];
00427
00428 if (args)
00429 sscanf(args, "%d", &lut->negate_alpha);
00430
00431 av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", lut->negate_alpha);
00432
00433 snprintf(lut_params, sizeof(lut_params), "c0=negval:c1=negval:c2=negval:a=%s",
00434 lut->negate_alpha ? "negval" : "val");
00435
00436 lut->class = &negate_class;
00437 av_opt_set_defaults(lut);
00438
00439 return av_set_options_string(lut, lut_params, "=", ":");
00440 }
00441
00442 DEFINE_LUT_FILTER(negate, "Negate input video.");
00443
00444 #endif