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 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, \
00110 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, \
00111 AV_PIX_FMT_YUVA420P, \
00112 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \
00113 AV_PIX_FMT_YUVJ440P
00114
00115 #define RGB_FORMATS \
00116 AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, \
00117 AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, \
00118 AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24
00119
00120 static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE };
00121 static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE };
00122 static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE };
00123
00124 static int query_formats(AVFilterContext *ctx)
00125 {
00126 LutContext *lut = ctx->priv;
00127
00128 const enum AVPixelFormat *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_desc_get(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 AV_PIX_FMT_YUV410P:
00190 case AV_PIX_FMT_YUV411P:
00191 case AV_PIX_FMT_YUV420P:
00192 case AV_PIX_FMT_YUV422P:
00193 case AV_PIX_FMT_YUV440P:
00194 case AV_PIX_FMT_YUV444P:
00195 case AV_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 AV_PIX_FMT_ARGB: rgba_map[0] = A; rgba_map[1] = R; rgba_map[2] = G; rgba_map[3] = B; break;
00213 case AV_PIX_FMT_ABGR: rgba_map[0] = A; rgba_map[1] = B; rgba_map[2] = G; rgba_map[3] = R; break;
00214 case AV_PIX_FMT_RGBA:
00215 case AV_PIX_FMT_RGB24: rgba_map[0] = R; rgba_map[1] = G; rgba_map[2] = B; rgba_map[3] = A; break;
00216 case AV_PIX_FMT_BGRA:
00217 case AV_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 filter_frame(AVFilterLink *inlink, AVFilterBufferRef *in)
00263 {
00264 AVFilterContext *ctx = inlink->dst;
00265 LutContext *lut = ctx->priv;
00266 AVFilterLink *outlink = ctx->outputs[0];
00267 AVFilterBufferRef *out;
00268 uint8_t *inrow, *outrow, *inrow0, *outrow0;
00269 int i, j, plane;
00270
00271 out = ff_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
00272 if (!out) {
00273 avfilter_unref_bufferp(&in);
00274 return AVERROR(ENOMEM);
00275 }
00276 avfilter_copy_buffer_ref_props(out, in);
00277
00278 if (lut->is_rgb) {
00279
00280 inrow0 = in ->data[0];
00281 outrow0 = out->data[0];
00282
00283 for (i = 0; i < in->video->h; i ++) {
00284 int w = inlink->w;
00285 const uint8_t (*tab)[256] = (const uint8_t (*)[256])lut->lut;
00286 inrow = inrow0;
00287 outrow = outrow0;
00288 for (j = 0; j < w; j++) {
00289 outrow[0] = tab[0][inrow[0]];
00290 if (lut->step>1) {
00291 outrow[1] = tab[1][inrow[1]];
00292 if (lut->step>2) {
00293 outrow[2] = tab[2][inrow[2]];
00294 if (lut->step>3) {
00295 outrow[3] = tab[3][inrow[3]];
00296 }
00297 }
00298 }
00299 outrow += lut->step;
00300 inrow += lut->step;
00301 }
00302 inrow0 += in ->linesize[0];
00303 outrow0 += out->linesize[0];
00304 }
00305 } else {
00306
00307 for (plane = 0; plane < 4 && in->data[plane]; plane++) {
00308 int vsub = plane == 1 || plane == 2 ? lut->vsub : 0;
00309 int hsub = plane == 1 || plane == 2 ? lut->hsub : 0;
00310
00311 inrow = in ->data[plane];
00312 outrow = out->data[plane];
00313
00314 for (i = 0; i < (in->video->h + (1<<vsub) - 1)>>vsub; i ++) {
00315 const uint8_t *tab = lut->lut[plane];
00316 int w = (inlink->w + (1<<hsub) - 1)>>hsub;
00317 for (j = 0; j < w; j++)
00318 outrow[j] = tab[inrow[j]];
00319 inrow += in ->linesize[plane];
00320 outrow += out->linesize[plane];
00321 }
00322 }
00323 }
00324
00325 avfilter_unref_bufferp(&in);
00326 return ff_filter_frame(outlink, out);
00327 }
00328
00329 static const AVFilterPad inputs[] = {
00330 { .name = "default",
00331 .type = AVMEDIA_TYPE_VIDEO,
00332 .filter_frame = filter_frame,
00333 .config_props = config_props,
00334 .min_perms = AV_PERM_READ, },
00335 { .name = NULL}
00336 };
00337 static const AVFilterPad outputs[] = {
00338 { .name = "default",
00339 .type = AVMEDIA_TYPE_VIDEO, },
00340 { .name = NULL}
00341 };
00342 #define DEFINE_LUT_FILTER(name_, description_) \
00343 AVFilter avfilter_vf_##name_ = { \
00344 .name = #name_, \
00345 .description = NULL_IF_CONFIG_SMALL(description_), \
00346 .priv_size = sizeof(LutContext), \
00347 \
00348 .init = name_##_init, \
00349 .uninit = uninit, \
00350 .query_formats = query_formats, \
00351 \
00352 .inputs = inputs, \
00353 .outputs = outputs, \
00354 .priv_class = &name_##_class, \
00355 }
00356
00357 #if CONFIG_LUT_FILTER
00358
00359 #define lut_options options
00360 AVFILTER_DEFINE_CLASS(lut);
00361
00362 static int lut_init(AVFilterContext *ctx, const char *args)
00363 {
00364 LutContext *lut = ctx->priv;
00365 int ret;
00366
00367 lut->class = &lut_class;
00368 av_opt_set_defaults(lut);
00369
00370 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00371 return ret;
00372
00373 return 0;
00374 }
00375
00376 DEFINE_LUT_FILTER(lut, "Compute and apply a lookup table to the RGB/YUV input video.");
00377 #endif
00378
00379 #if CONFIG_LUTYUV_FILTER
00380
00381 #define lutyuv_options options
00382 AVFILTER_DEFINE_CLASS(lutyuv);
00383
00384 static int lutyuv_init(AVFilterContext *ctx, const char *args)
00385 {
00386 LutContext *lut = ctx->priv;
00387 int ret;
00388
00389 lut->class = &lutyuv_class;
00390 lut->is_yuv = 1;
00391 av_opt_set_defaults(lut);
00392
00393 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00394 return ret;
00395
00396 return 0;
00397 }
00398
00399 DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video.");
00400 #endif
00401
00402 #if CONFIG_LUTRGB_FILTER
00403
00404 #define lutrgb_options options
00405 AVFILTER_DEFINE_CLASS(lutrgb);
00406
00407 static int lutrgb_init(AVFilterContext *ctx, const char *args)
00408 {
00409 LutContext *lut = ctx->priv;
00410 int ret;
00411
00412 lut->class = &lutrgb_class;
00413 lut->is_rgb = 1;
00414 av_opt_set_defaults(lut);
00415
00416 if (args && (ret = av_set_options_string(lut, args, "=", ":")) < 0)
00417 return ret;
00418
00419 return 0;
00420 }
00421
00422 DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video.");
00423 #endif
00424
00425 #if CONFIG_NEGATE_FILTER
00426
00427 #define negate_options options
00428 AVFILTER_DEFINE_CLASS(negate);
00429
00430 static int negate_init(AVFilterContext *ctx, const char *args)
00431 {
00432 LutContext *lut = ctx->priv;
00433 char lut_params[64];
00434
00435 if (args)
00436 sscanf(args, "%d", &lut->negate_alpha);
00437
00438 av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", lut->negate_alpha);
00439
00440 snprintf(lut_params, sizeof(lut_params), "c0=negval:c1=negval:c2=negval:a=%s",
00441 lut->negate_alpha ? "negval" : "val");
00442
00443 lut->class = &negate_class;
00444 av_opt_set_defaults(lut);
00445
00446 return av_set_options_string(lut, lut_params, "=", ":");
00447 }
00448
00449 DEFINE_LUT_FILTER(negate, "Negate input video.");
00450
00451 #endif