2 * Copyright (c) 2011 Stefano Sabatini
4 * This file is part of Libav.
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 * Compute a look-up table for binding the input value to the output
24 * value, and apply it to input video.
27 #include "libavutil/common.h"
28 #include "libavutil/eval.h"
29 #include "libavutil/mathematics.h"
30 #include "libavutil/opt.h"
31 #include "libavutil/pixdesc.h"
37 static const char *const var_names
[] = {
41 "w", ///< width of the input video
42 "h", ///< height of the input video
43 "val", ///< input value for the pixel
44 "maxval", ///< max value for the pixel
45 "minval", ///< min value for the pixel
46 "negval", ///< negated value
67 uint8_t lut
[4][256]; ///< lookup table for each component
68 char *comp_expr_str
[4];
71 double var_values
[VAR_VARS_NB
];
75 int negate_alpha
; /* only used by negate */
86 #define OFFSET(x) offsetof(LutContext, x)
88 static const AVOption lut_options
[] = {
89 {"c0", "set component #0 expression", OFFSET(comp_expr_str
[0]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
90 {"c1", "set component #1 expression", OFFSET(comp_expr_str
[1]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
91 {"c2", "set component #2 expression", OFFSET(comp_expr_str
[2]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
92 {"c3", "set component #3 expression", OFFSET(comp_expr_str
[3]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
93 {"y", "set Y expression", OFFSET(comp_expr_str
[Y
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
94 {"u", "set U expression", OFFSET(comp_expr_str
[U
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
95 {"v", "set V expression", OFFSET(comp_expr_str
[V
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
96 {"r", "set R expression", OFFSET(comp_expr_str
[R
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
97 {"g", "set G expression", OFFSET(comp_expr_str
[G
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
98 {"b", "set B expression", OFFSET(comp_expr_str
[B
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
99 {"a", "set A expression", OFFSET(comp_expr_str
[A
]), AV_OPT_TYPE_STRING
, {.str
="val"}, CHAR_MIN
, CHAR_MAX
},
103 static const char *lut_get_name(void *ctx
)
108 static const AVClass lut_class
= {
114 static int init(AVFilterContext
*ctx
, const char *args
)
116 LutContext
*lut
= ctx
->priv
;
119 lut
->class = &lut_class
;
120 av_opt_set_defaults(lut
);
122 lut
->var_values
[VAR_PHI
] = M_PHI
;
123 lut
->var_values
[VAR_PI
] = M_PI
;
124 lut
->var_values
[VAR_E
] = M_E
;
126 lut
->is_rgb
= !strcmp(ctx
->filter
->name
, "lutrgb");
127 lut
->is_yuv
= !strcmp(ctx
->filter
->name
, "lutyuv");
128 if (args
&& (ret
= av_set_options_string(lut
, args
, "=", ":")) < 0)
134 static av_cold
void uninit(AVFilterContext
*ctx
)
136 LutContext
*lut
= ctx
->priv
;
139 for (i
= 0; i
< 4; i
++) {
140 av_expr_free(lut
->comp_expr
[i
]);
141 lut
->comp_expr
[i
] = NULL
;
142 av_freep(&lut
->comp_expr_str
[i
]);
146 #define YUV_FORMATS \
147 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, \
148 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, \
149 AV_PIX_FMT_YUVA420P, \
150 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \
153 #define RGB_FORMATS \
154 AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, \
155 AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, \
156 AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24
158 static enum AVPixelFormat yuv_pix_fmts
[] = { YUV_FORMATS
, AV_PIX_FMT_NONE
};
159 static enum AVPixelFormat rgb_pix_fmts
[] = { RGB_FORMATS
, AV_PIX_FMT_NONE
};
160 static enum AVPixelFormat all_pix_fmts
[] = { RGB_FORMATS
, YUV_FORMATS
, AV_PIX_FMT_NONE
};
162 static int query_formats(AVFilterContext
*ctx
)
164 LutContext
*lut
= ctx
->priv
;
166 enum AVPixelFormat
*pix_fmts
= lut
->is_rgb
? rgb_pix_fmts
:
167 lut
->is_yuv
? yuv_pix_fmts
: all_pix_fmts
;
169 ff_set_common_formats(ctx
, ff_make_format_list(pix_fmts
));
174 * Clip value val in the minval - maxval range.
176 static double clip(void *opaque
, double val
)
178 LutContext
*lut
= opaque
;
179 double minval
= lut
->var_values
[VAR_MINVAL
];
180 double maxval
= lut
->var_values
[VAR_MAXVAL
];
182 return av_clip(val
, minval
, maxval
);
186 * Compute gamma correction for value val, assuming the minval-maxval
187 * range, val is clipped to a value contained in the same interval.
189 static double compute_gammaval(void *opaque
, double gamma
)
191 LutContext
*lut
= opaque
;
192 double val
= lut
->var_values
[VAR_CLIPVAL
];
193 double minval
= lut
->var_values
[VAR_MINVAL
];
194 double maxval
= lut
->var_values
[VAR_MAXVAL
];
196 return pow((val
-minval
)/(maxval
-minval
), gamma
) * (maxval
-minval
)+minval
;
199 static double (* const funcs1
[])(void *, double) = {
205 static const char * const funcs1_names
[] = {
211 static int config_props(AVFilterLink
*inlink
)
213 AVFilterContext
*ctx
= inlink
->dst
;
214 LutContext
*lut
= ctx
->priv
;
215 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
219 lut
->hsub
= desc
->log2_chroma_w
;
220 lut
->vsub
= desc
->log2_chroma_h
;
222 lut
->var_values
[VAR_W
] = inlink
->w
;
223 lut
->var_values
[VAR_H
] = inlink
->h
;
225 switch (inlink
->format
) {
226 case AV_PIX_FMT_YUV410P
:
227 case AV_PIX_FMT_YUV411P
:
228 case AV_PIX_FMT_YUV420P
:
229 case AV_PIX_FMT_YUV422P
:
230 case AV_PIX_FMT_YUV440P
:
231 case AV_PIX_FMT_YUV444P
:
232 case AV_PIX_FMT_YUVA420P
:
233 min
[Y
] = min
[U
] = min
[V
] = 16;
235 max
[U
] = max
[V
] = 240;
236 min
[A
] = 0; max
[A
] = 255;
239 min
[0] = min
[1] = min
[2] = min
[3] = 0;
240 max
[0] = max
[1] = max
[2] = max
[3] = 255;
243 lut
->is_yuv
= lut
->is_rgb
= 0;
244 if (ff_fmt_is_in(inlink
->format
, yuv_pix_fmts
)) lut
->is_yuv
= 1;
245 else if (ff_fmt_is_in(inlink
->format
, rgb_pix_fmts
)) lut
->is_rgb
= 1;
248 switch (inlink
->format
) {
249 case AV_PIX_FMT_ARGB
: lut
->rgba_map
[A
] = 0; lut
->rgba_map
[R
] = 1; lut
->rgba_map
[G
] = 2; lut
->rgba_map
[B
] = 3; break;
250 case AV_PIX_FMT_ABGR
: lut
->rgba_map
[A
] = 0; lut
->rgba_map
[B
] = 1; lut
->rgba_map
[G
] = 2; lut
->rgba_map
[R
] = 3; break;
251 case AV_PIX_FMT_RGBA
:
252 case AV_PIX_FMT_RGB24
: lut
->rgba_map
[R
] = 0; lut
->rgba_map
[G
] = 1; lut
->rgba_map
[B
] = 2; lut
->rgba_map
[A
] = 3; break;
253 case AV_PIX_FMT_BGRA
:
254 case AV_PIX_FMT_BGR24
: lut
->rgba_map
[B
] = 0; lut
->rgba_map
[G
] = 1; lut
->rgba_map
[R
] = 2; lut
->rgba_map
[A
] = 3; break;
256 lut
->step
= av_get_bits_per_pixel(desc
) >> 3;
259 for (comp
= 0; comp
< desc
->nb_components
; comp
++) {
262 /* create the parsed expression */
263 ret
= av_expr_parse(&lut
->comp_expr
[comp
], lut
->comp_expr_str
[comp
],
264 var_names
, funcs1_names
, funcs1
, NULL
, NULL
, 0, ctx
);
266 av_log(ctx
, AV_LOG_ERROR
,
267 "Error when parsing the expression '%s' for the component %d.\n",
268 lut
->comp_expr_str
[comp
], comp
);
269 return AVERROR(EINVAL
);
272 /* compute the lut */
273 lut
->var_values
[VAR_MAXVAL
] = max
[comp
];
274 lut
->var_values
[VAR_MINVAL
] = min
[comp
];
276 for (val
= 0; val
< 256; val
++) {
277 lut
->var_values
[VAR_VAL
] = val
;
278 lut
->var_values
[VAR_CLIPVAL
] = av_clip(val
, min
[comp
], max
[comp
]);
279 lut
->var_values
[VAR_NEGVAL
] =
280 av_clip(min
[comp
] + max
[comp
] - lut
->var_values
[VAR_VAL
],
281 min
[comp
], max
[comp
]);
283 res
= av_expr_eval(lut
->comp_expr
[comp
], lut
->var_values
, lut
);
285 av_log(ctx
, AV_LOG_ERROR
,
286 "Error when evaluating the expression '%s' for the value %d for the component #%d.\n",
287 lut
->comp_expr_str
[comp
], val
, comp
);
288 return AVERROR(EINVAL
);
290 lut
->lut
[comp
][val
] = av_clip((int)res
, min
[comp
], max
[comp
]);
291 av_log(ctx
, AV_LOG_DEBUG
, "val[%d][%d] = %d\n", comp
, val
, lut
->lut
[comp
][val
]);
298 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*in
)
300 AVFilterContext
*ctx
= inlink
->dst
;
301 LutContext
*lut
= ctx
->priv
;
302 AVFilterLink
*outlink
= ctx
->outputs
[0];
304 uint8_t *inrow
, *outrow
, *inrow0
, *outrow0
;
307 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
310 return AVERROR(ENOMEM
);
312 av_frame_copy_props(out
, in
);
316 inrow0
= in
->data
[0];
317 outrow0
= out
->data
[0];
319 for (i
= 0; i
< in
->height
; i
++) {
322 for (j
= 0; j
< inlink
->w
; j
++) {
323 for (k
= 0; k
< lut
->step
; k
++)
324 outrow
[k
] = lut
->lut
[lut
->rgba_map
[k
]][inrow
[k
]];
328 inrow0
+= in
->linesize
[0];
329 outrow0
+= out
->linesize
[0];
333 for (plane
= 0; plane
< 4 && in
->data
[plane
]; plane
++) {
334 int vsub
= plane
== 1 || plane
== 2 ? lut
->vsub
: 0;
335 int hsub
= plane
== 1 || plane
== 2 ? lut
->hsub
: 0;
337 inrow
= in
->data
[plane
];
338 outrow
= out
->data
[plane
];
340 for (i
= 0; i
< in
->height
>> vsub
; i
++) {
341 for (j
= 0; j
< inlink
->w
>>hsub
; j
++)
342 outrow
[j
] = lut
->lut
[plane
][inrow
[j
]];
343 inrow
+= in
->linesize
[plane
];
344 outrow
+= out
->linesize
[plane
];
350 return ff_filter_frame(outlink
, out
);
353 static const AVFilterPad inputs
[] = {
355 .type
= AVMEDIA_TYPE_VIDEO
,
356 .filter_frame
= filter_frame
,
357 .config_props
= config_props
,
361 static const AVFilterPad outputs
[] = {
363 .type
= AVMEDIA_TYPE_VIDEO
, },
366 #define DEFINE_LUT_FILTER(name_, description_, init_) \
367 AVFilter avfilter_vf_##name_ = { \
369 .description = NULL_IF_CONFIG_SMALL(description_), \
370 .priv_size = sizeof(LutContext), \
374 .query_formats = query_formats, \
377 .outputs = outputs, \
380 #if CONFIG_LUT_FILTER
381 DEFINE_LUT_FILTER(lut
, "Compute and apply a lookup table to the RGB/YUV input video.", init
);
383 #if CONFIG_LUTYUV_FILTER
384 DEFINE_LUT_FILTER(lutyuv
, "Compute and apply a lookup table to the YUV input video.", init
);
386 #if CONFIG_LUTRGB_FILTER
387 DEFINE_LUT_FILTER(lutrgb
, "Compute and apply a lookup table to the RGB input video.", init
);
390 #if CONFIG_NEGATE_FILTER
392 static int negate_init(AVFilterContext
*ctx
, const char *args
)
394 LutContext
*lut
= ctx
->priv
;
398 sscanf(args
, "%d", &lut
->negate_alpha
);
400 av_log(ctx
, AV_LOG_DEBUG
, "negate_alpha:%d\n", lut
->negate_alpha
);
402 snprintf(lut_params
, sizeof(lut_params
), "c0=negval:c1=negval:c2=negval:a=%s",
403 lut
->negate_alpha
? "negval" : "val");
405 return init(ctx
, lut_params
);
408 DEFINE_LUT_FILTER(negate
, "Negate input video.", negate_init
);