blob: d005afae874252c5c466ffbd796c95bb30dcd103
1 | /* |
2 | * Copyright (c) 2011 Stefano Sabatini |
3 | * |
4 | * This file is part of FFmpeg. |
5 | * |
6 | * FFmpeg 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. |
10 | * |
11 | * FFmpeg 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. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with FFmpeg; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | */ |
20 | |
21 | /** |
22 | * @file |
23 | * Compute a look-up table for binding the input value to the output |
24 | * value, and apply it to input video. |
25 | */ |
26 | |
27 | #include "libavutil/attributes.h" |
28 | #include "libavutil/bswap.h" |
29 | #include "libavutil/common.h" |
30 | #include "libavutil/eval.h" |
31 | #include "libavutil/opt.h" |
32 | #include "libavutil/pixdesc.h" |
33 | #include "avfilter.h" |
34 | #include "drawutils.h" |
35 | #include "formats.h" |
36 | #include "internal.h" |
37 | #include "video.h" |
38 | |
39 | static const char *const var_names[] = { |
40 | "w", ///< width of the input video |
41 | "h", ///< height of the input video |
42 | "val", ///< input value for the pixel |
43 | "maxval", ///< max value for the pixel |
44 | "minval", ///< min value for the pixel |
45 | "negval", ///< negated value |
46 | "clipval", |
47 | NULL |
48 | }; |
49 | |
50 | enum var_name { |
51 | VAR_W, |
52 | VAR_H, |
53 | VAR_VAL, |
54 | VAR_MAXVAL, |
55 | VAR_MINVAL, |
56 | VAR_NEGVAL, |
57 | VAR_CLIPVAL, |
58 | VAR_VARS_NB |
59 | }; |
60 | |
61 | typedef struct LutContext { |
62 | const AVClass *class; |
63 | uint16_t lut[4][256 * 256]; ///< lookup table for each component |
64 | char *comp_expr_str[4]; |
65 | AVExpr *comp_expr[4]; |
66 | int hsub, vsub; |
67 | double var_values[VAR_VARS_NB]; |
68 | int is_rgb, is_yuv; |
69 | int is_planar; |
70 | int is_16bit; |
71 | int step; |
72 | int negate_alpha; /* only used by negate */ |
73 | } LutContext; |
74 | |
75 | #define Y 0 |
76 | #define U 1 |
77 | #define V 2 |
78 | #define R 0 |
79 | #define G 1 |
80 | #define B 2 |
81 | #define A 3 |
82 | |
83 | #define OFFSET(x) offsetof(LutContext, x) |
84 | #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM |
85 | |
86 | static const AVOption options[] = { |
87 | { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
88 | { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
89 | { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
90 | { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
91 | { "y", "set Y expression", OFFSET(comp_expr_str[Y]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
92 | { "u", "set U expression", OFFSET(comp_expr_str[U]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
93 | { "v", "set V expression", OFFSET(comp_expr_str[V]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
94 | { "r", "set R expression", OFFSET(comp_expr_str[R]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
95 | { "g", "set G expression", OFFSET(comp_expr_str[G]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
96 | { "b", "set B expression", OFFSET(comp_expr_str[B]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
97 | { "a", "set A expression", OFFSET(comp_expr_str[A]), AV_OPT_TYPE_STRING, { .str = "clipval" }, .flags = FLAGS }, |
98 | { NULL } |
99 | }; |
100 | |
101 | static av_cold void uninit(AVFilterContext *ctx) |
102 | { |
103 | LutContext *s = ctx->priv; |
104 | int i; |
105 | |
106 | for (i = 0; i < 4; i++) { |
107 | av_expr_free(s->comp_expr[i]); |
108 | s->comp_expr[i] = NULL; |
109 | av_freep(&s->comp_expr_str[i]); |
110 | } |
111 | } |
112 | |
113 | #define YUV_FORMATS \ |
114 | AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, \ |
115 | AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, \ |
116 | AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, \ |
117 | AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \ |
118 | AV_PIX_FMT_YUVJ440P, \ |
119 | AV_PIX_FMT_YUV444P9LE, AV_PIX_FMT_YUV422P9LE, AV_PIX_FMT_YUV420P9LE, \ |
120 | AV_PIX_FMT_YUV444P10LE, AV_PIX_FMT_YUV422P10LE, AV_PIX_FMT_YUV420P10LE, AV_PIX_FMT_YUV440P10LE, \ |
121 | AV_PIX_FMT_YUV444P12LE, AV_PIX_FMT_YUV422P12LE, AV_PIX_FMT_YUV420P12LE, AV_PIX_FMT_YUV440P12LE, \ |
122 | AV_PIX_FMT_YUV444P14LE, AV_PIX_FMT_YUV422P14LE, AV_PIX_FMT_YUV420P14LE, \ |
123 | AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUV420P16LE, \ |
124 | AV_PIX_FMT_YUVA444P16LE, AV_PIX_FMT_YUVA422P16LE, AV_PIX_FMT_YUVA420P16LE |
125 | |
126 | #define RGB_FORMATS \ |
127 | AV_PIX_FMT_ARGB, AV_PIX_FMT_RGBA, \ |
128 | AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, \ |
129 | AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, \ |
130 | AV_PIX_FMT_RGB48LE, AV_PIX_FMT_RGBA64LE, \ |
131 | AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, \ |
132 | AV_PIX_FMT_GBRP9LE, AV_PIX_FMT_GBRP10LE, \ |
133 | AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRP14LE, \ |
134 | AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRAP12LE, \ |
135 | AV_PIX_FMT_GBRAP16LE |
136 | |
137 | static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE }; |
138 | static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE }; |
139 | static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE }; |
140 | |
141 | static int query_formats(AVFilterContext *ctx) |
142 | { |
143 | LutContext *s = ctx->priv; |
144 | |
145 | const enum AVPixelFormat *pix_fmts = s->is_rgb ? rgb_pix_fmts : |
146 | s->is_yuv ? yuv_pix_fmts : |
147 | all_pix_fmts; |
148 | AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); |
149 | if (!fmts_list) |
150 | return AVERROR(ENOMEM); |
151 | return ff_set_common_formats(ctx, fmts_list); |
152 | } |
153 | |
154 | /** |
155 | * Clip value val in the minval - maxval range. |
156 | */ |
157 | static double clip(void *opaque, double val) |
158 | { |
159 | LutContext *s = opaque; |
160 | double minval = s->var_values[VAR_MINVAL]; |
161 | double maxval = s->var_values[VAR_MAXVAL]; |
162 | |
163 | return av_clip(val, minval, maxval); |
164 | } |
165 | |
166 | /** |
167 | * Compute gamma correction for value val, assuming the minval-maxval |
168 | * range, val is clipped to a value contained in the same interval. |
169 | */ |
170 | static double compute_gammaval(void *opaque, double gamma) |
171 | { |
172 | LutContext *s = opaque; |
173 | double val = s->var_values[VAR_CLIPVAL]; |
174 | double minval = s->var_values[VAR_MINVAL]; |
175 | double maxval = s->var_values[VAR_MAXVAL]; |
176 | |
177 | return pow((val-minval)/(maxval-minval), gamma) * (maxval-minval)+minval; |
178 | } |
179 | |
180 | /** |
181 | * Compute ITU Rec.709 gamma correction of value val. |
182 | */ |
183 | static double compute_gammaval709(void *opaque, double gamma) |
184 | { |
185 | LutContext *s = opaque; |
186 | double val = s->var_values[VAR_CLIPVAL]; |
187 | double minval = s->var_values[VAR_MINVAL]; |
188 | double maxval = s->var_values[VAR_MAXVAL]; |
189 | double level = (val - minval) / (maxval - minval); |
190 | level = level < 0.018 ? 4.5 * level |
191 | : 1.099 * pow(level, 1.0 / gamma) - 0.099; |
192 | return level * (maxval - minval) + minval; |
193 | } |
194 | |
195 | static double (* const funcs1[])(void *, double) = { |
196 | clip, |
197 | compute_gammaval, |
198 | compute_gammaval709, |
199 | NULL |
200 | }; |
201 | |
202 | static const char * const funcs1_names[] = { |
203 | "clip", |
204 | "gammaval", |
205 | "gammaval709", |
206 | NULL |
207 | }; |
208 | |
209 | static int config_props(AVFilterLink *inlink) |
210 | { |
211 | AVFilterContext *ctx = inlink->dst; |
212 | LutContext *s = ctx->priv; |
213 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); |
214 | uint8_t rgba_map[4]; /* component index -> RGBA color index map */ |
215 | int min[4], max[4]; |
216 | int val, color, ret; |
217 | |
218 | s->hsub = desc->log2_chroma_w; |
219 | s->vsub = desc->log2_chroma_h; |
220 | |
221 | s->var_values[VAR_W] = inlink->w; |
222 | s->var_values[VAR_H] = inlink->h; |
223 | s->is_16bit = desc->comp[0].depth > 8; |
224 | |
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 | case AV_PIX_FMT_YUVA422P: |
234 | case AV_PIX_FMT_YUVA444P: |
235 | case AV_PIX_FMT_YUV420P9LE: |
236 | case AV_PIX_FMT_YUV422P9LE: |
237 | case AV_PIX_FMT_YUV444P9LE: |
238 | case AV_PIX_FMT_YUVA420P9LE: |
239 | case AV_PIX_FMT_YUVA422P9LE: |
240 | case AV_PIX_FMT_YUVA444P9LE: |
241 | case AV_PIX_FMT_YUV420P10LE: |
242 | case AV_PIX_FMT_YUV422P10LE: |
243 | case AV_PIX_FMT_YUV440P10LE: |
244 | case AV_PIX_FMT_YUV444P10LE: |
245 | case AV_PIX_FMT_YUVA420P10LE: |
246 | case AV_PIX_FMT_YUVA422P10LE: |
247 | case AV_PIX_FMT_YUVA444P10LE: |
248 | case AV_PIX_FMT_YUV420P12LE: |
249 | case AV_PIX_FMT_YUV422P12LE: |
250 | case AV_PIX_FMT_YUV440P12LE: |
251 | case AV_PIX_FMT_YUV444P12LE: |
252 | case AV_PIX_FMT_YUV420P14LE: |
253 | case AV_PIX_FMT_YUV422P14LE: |
254 | case AV_PIX_FMT_YUV444P14LE: |
255 | case AV_PIX_FMT_YUV420P16LE: |
256 | case AV_PIX_FMT_YUV422P16LE: |
257 | case AV_PIX_FMT_YUV444P16LE: |
258 | case AV_PIX_FMT_YUVA420P16LE: |
259 | case AV_PIX_FMT_YUVA422P16LE: |
260 | case AV_PIX_FMT_YUVA444P16LE: |
261 | min[Y] = 16 * (1 << (desc->comp[0].depth - 8)); |
262 | min[U] = 16 * (1 << (desc->comp[1].depth - 8)); |
263 | min[V] = 16 * (1 << (desc->comp[2].depth - 8)); |
264 | min[A] = 0; |
265 | max[Y] = 235 * (1 << (desc->comp[0].depth - 8)); |
266 | max[U] = 240 * (1 << (desc->comp[1].depth - 8)); |
267 | max[V] = 240 * (1 << (desc->comp[2].depth - 8)); |
268 | max[A] = (1 << desc->comp[0].depth) - 1; |
269 | break; |
270 | case AV_PIX_FMT_RGB48LE: |
271 | case AV_PIX_FMT_RGBA64LE: |
272 | min[0] = min[1] = min[2] = min[3] = 0; |
273 | max[0] = max[1] = max[2] = max[3] = 65535; |
274 | break; |
275 | default: |
276 | min[0] = min[1] = min[2] = min[3] = 0; |
277 | max[0] = max[1] = max[2] = max[3] = 255 * (1 << (desc->comp[0].depth - 8)); |
278 | } |
279 | |
280 | s->is_yuv = s->is_rgb = 0; |
281 | s->is_planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR; |
282 | if (ff_fmt_is_in(inlink->format, yuv_pix_fmts)) s->is_yuv = 1; |
283 | else if (ff_fmt_is_in(inlink->format, rgb_pix_fmts)) s->is_rgb = 1; |
284 | |
285 | if (s->is_rgb) { |
286 | ff_fill_rgba_map(rgba_map, inlink->format); |
287 | s->step = av_get_bits_per_pixel(desc) >> 3; |
288 | if (s->is_16bit) { |
289 | s->step = s->step >> 1; |
290 | } |
291 | } |
292 | |
293 | for (color = 0; color < desc->nb_components; color++) { |
294 | double res; |
295 | int comp = s->is_rgb ? rgba_map[color] : color; |
296 | |
297 | /* create the parsed expression */ |
298 | av_expr_free(s->comp_expr[color]); |
299 | s->comp_expr[color] = NULL; |
300 | ret = av_expr_parse(&s->comp_expr[color], s->comp_expr_str[color], |
301 | var_names, funcs1_names, funcs1, NULL, NULL, 0, ctx); |
302 | if (ret < 0) { |
303 | av_log(ctx, AV_LOG_ERROR, |
304 | "Error when parsing the expression '%s' for the component %d and color %d.\n", |
305 | s->comp_expr_str[comp], comp, color); |
306 | return AVERROR(EINVAL); |
307 | } |
308 | |
309 | /* compute the lut */ |
310 | s->var_values[VAR_MAXVAL] = max[color]; |
311 | s->var_values[VAR_MINVAL] = min[color]; |
312 | |
313 | for (val = 0; val < FF_ARRAY_ELEMS(s->lut[comp]); val++) { |
314 | s->var_values[VAR_VAL] = val; |
315 | s->var_values[VAR_CLIPVAL] = av_clip(val, min[color], max[color]); |
316 | s->var_values[VAR_NEGVAL] = |
317 | av_clip(min[color] + max[color] - s->var_values[VAR_VAL], |
318 | min[color], max[color]); |
319 | |
320 | res = av_expr_eval(s->comp_expr[color], s->var_values, s); |
321 | if (isnan(res)) { |
322 | av_log(ctx, AV_LOG_ERROR, |
323 | "Error when evaluating the expression '%s' for the value %d for the component %d.\n", |
324 | s->comp_expr_str[color], val, comp); |
325 | return AVERROR(EINVAL); |
326 | } |
327 | s->lut[comp][val] = av_clip((int)res, 0, max[A]); |
328 | av_log(ctx, AV_LOG_DEBUG, "val[%d][%d] = %d\n", comp, val, s->lut[comp][val]); |
329 | } |
330 | } |
331 | |
332 | return 0; |
333 | } |
334 | |
335 | static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
336 | { |
337 | AVFilterContext *ctx = inlink->dst; |
338 | LutContext *s = ctx->priv; |
339 | AVFilterLink *outlink = ctx->outputs[0]; |
340 | AVFrame *out; |
341 | int i, j, plane, direct = 0; |
342 | |
343 | if (av_frame_is_writable(in)) { |
344 | direct = 1; |
345 | out = in; |
346 | } else { |
347 | out = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
348 | if (!out) { |
349 | av_frame_free(&in); |
350 | return AVERROR(ENOMEM); |
351 | } |
352 | av_frame_copy_props(out, in); |
353 | } |
354 | |
355 | if (s->is_rgb && s->is_16bit && !s->is_planar) { |
356 | /* packed, 16-bit */ |
357 | uint16_t *inrow, *outrow, *inrow0, *outrow0; |
358 | const int w = inlink->w; |
359 | const int h = in->height; |
360 | const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; |
361 | const int in_linesize = in->linesize[0] / 2; |
362 | const int out_linesize = out->linesize[0] / 2; |
363 | const int step = s->step; |
364 | |
365 | inrow0 = (uint16_t*) in ->data[0]; |
366 | outrow0 = (uint16_t*) out->data[0]; |
367 | |
368 | for (i = 0; i < h; i ++) { |
369 | inrow = inrow0; |
370 | outrow = outrow0; |
371 | for (j = 0; j < w; j++) { |
372 | |
373 | switch (step) { |
374 | #if HAVE_BIGENDIAN |
375 | case 4: outrow[3] = av_bswap16(tab[3][av_bswap16(inrow[3])]); // Fall-through |
376 | case 3: outrow[2] = av_bswap16(tab[2][av_bswap16(inrow[2])]); // Fall-through |
377 | case 2: outrow[1] = av_bswap16(tab[1][av_bswap16(inrow[1])]); // Fall-through |
378 | default: outrow[0] = av_bswap16(tab[0][av_bswap16(inrow[0])]); |
379 | #else |
380 | case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through |
381 | case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through |
382 | case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through |
383 | default: outrow[0] = tab[0][inrow[0]]; |
384 | #endif |
385 | } |
386 | outrow += step; |
387 | inrow += step; |
388 | } |
389 | inrow0 += in_linesize; |
390 | outrow0 += out_linesize; |
391 | } |
392 | } else if (s->is_rgb && !s->is_planar) { |
393 | /* packed */ |
394 | uint8_t *inrow, *outrow, *inrow0, *outrow0; |
395 | const int w = inlink->w; |
396 | const int h = in->height; |
397 | const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; |
398 | const int in_linesize = in->linesize[0]; |
399 | const int out_linesize = out->linesize[0]; |
400 | const int step = s->step; |
401 | |
402 | inrow0 = in ->data[0]; |
403 | outrow0 = out->data[0]; |
404 | |
405 | for (i = 0; i < h; i ++) { |
406 | inrow = inrow0; |
407 | outrow = outrow0; |
408 | for (j = 0; j < w; j++) { |
409 | switch (step) { |
410 | case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through |
411 | case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through |
412 | case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through |
413 | default: outrow[0] = tab[0][inrow[0]]; |
414 | } |
415 | outrow += step; |
416 | inrow += step; |
417 | } |
418 | inrow0 += in_linesize; |
419 | outrow0 += out_linesize; |
420 | } |
421 | } else if (s->is_16bit) { |
422 | // planar >8 bit depth |
423 | uint16_t *inrow, *outrow; |
424 | |
425 | for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { |
426 | int vsub = plane == 1 || plane == 2 ? s->vsub : 0; |
427 | int hsub = plane == 1 || plane == 2 ? s->hsub : 0; |
428 | int h = AV_CEIL_RSHIFT(inlink->h, vsub); |
429 | int w = AV_CEIL_RSHIFT(inlink->w, hsub); |
430 | const uint16_t *tab = s->lut[plane]; |
431 | const int in_linesize = in->linesize[plane] / 2; |
432 | const int out_linesize = out->linesize[plane] / 2; |
433 | |
434 | inrow = (uint16_t *)in ->data[plane]; |
435 | outrow = (uint16_t *)out->data[plane]; |
436 | |
437 | for (i = 0; i < h; i++) { |
438 | for (j = 0; j < w; j++) { |
439 | #if HAVE_BIGENDIAN |
440 | outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]); |
441 | #else |
442 | outrow[j] = tab[inrow[j]]; |
443 | #endif |
444 | } |
445 | inrow += in_linesize; |
446 | outrow += out_linesize; |
447 | } |
448 | } |
449 | } else { |
450 | /* planar 8bit depth */ |
451 | uint8_t *inrow, *outrow; |
452 | |
453 | for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { |
454 | int vsub = plane == 1 || plane == 2 ? s->vsub : 0; |
455 | int hsub = plane == 1 || plane == 2 ? s->hsub : 0; |
456 | int h = AV_CEIL_RSHIFT(inlink->h, vsub); |
457 | int w = AV_CEIL_RSHIFT(inlink->w, hsub); |
458 | const uint16_t *tab = s->lut[plane]; |
459 | const int in_linesize = in->linesize[plane]; |
460 | const int out_linesize = out->linesize[plane]; |
461 | |
462 | inrow = in ->data[plane]; |
463 | outrow = out->data[plane]; |
464 | |
465 | for (i = 0; i < h; i++) { |
466 | for (j = 0; j < w; j++) |
467 | outrow[j] = tab[inrow[j]]; |
468 | inrow += in_linesize; |
469 | outrow += out_linesize; |
470 | } |
471 | } |
472 | } |
473 | |
474 | if (!direct) |
475 | av_frame_free(&in); |
476 | |
477 | return ff_filter_frame(outlink, out); |
478 | } |
479 | |
480 | static const AVFilterPad inputs[] = { |
481 | { .name = "default", |
482 | .type = AVMEDIA_TYPE_VIDEO, |
483 | .filter_frame = filter_frame, |
484 | .config_props = config_props, |
485 | }, |
486 | { NULL } |
487 | }; |
488 | static const AVFilterPad outputs[] = { |
489 | { .name = "default", |
490 | .type = AVMEDIA_TYPE_VIDEO, |
491 | }, |
492 | { NULL } |
493 | }; |
494 | |
495 | #define DEFINE_LUT_FILTER(name_, description_) \ |
496 | AVFilter ff_vf_##name_ = { \ |
497 | .name = #name_, \ |
498 | .description = NULL_IF_CONFIG_SMALL(description_), \ |
499 | .priv_size = sizeof(LutContext), \ |
500 | .priv_class = &name_ ## _class, \ |
501 | .init = name_##_init, \ |
502 | .uninit = uninit, \ |
503 | .query_formats = query_formats, \ |
504 | .inputs = inputs, \ |
505 | .outputs = outputs, \ |
506 | .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \ |
507 | } |
508 | |
509 | #if CONFIG_LUT_FILTER |
510 | |
511 | #define lut_options options |
512 | AVFILTER_DEFINE_CLASS(lut); |
513 | |
514 | static int lut_init(AVFilterContext *ctx) |
515 | { |
516 | return 0; |
517 | } |
518 | |
519 | DEFINE_LUT_FILTER(lut, "Compute and apply a lookup table to the RGB/YUV input video."); |
520 | #endif |
521 | |
522 | #if CONFIG_LUTYUV_FILTER |
523 | |
524 | #define lutyuv_options options |
525 | AVFILTER_DEFINE_CLASS(lutyuv); |
526 | |
527 | static av_cold int lutyuv_init(AVFilterContext *ctx) |
528 | { |
529 | LutContext *s = ctx->priv; |
530 | |
531 | s->is_yuv = 1; |
532 | |
533 | return 0; |
534 | } |
535 | |
536 | DEFINE_LUT_FILTER(lutyuv, "Compute and apply a lookup table to the YUV input video."); |
537 | #endif |
538 | |
539 | #if CONFIG_LUTRGB_FILTER |
540 | |
541 | #define lutrgb_options options |
542 | AVFILTER_DEFINE_CLASS(lutrgb); |
543 | |
544 | static av_cold int lutrgb_init(AVFilterContext *ctx) |
545 | { |
546 | LutContext *s = ctx->priv; |
547 | |
548 | s->is_rgb = 1; |
549 | |
550 | return 0; |
551 | } |
552 | |
553 | DEFINE_LUT_FILTER(lutrgb, "Compute and apply a lookup table to the RGB input video."); |
554 | #endif |
555 | |
556 | #if CONFIG_NEGATE_FILTER |
557 | |
558 | static const AVOption negate_options[] = { |
559 | { "negate_alpha", NULL, OFFSET(negate_alpha), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, |
560 | { NULL } |
561 | }; |
562 | |
563 | AVFILTER_DEFINE_CLASS(negate); |
564 | |
565 | static av_cold int negate_init(AVFilterContext *ctx) |
566 | { |
567 | LutContext *s = ctx->priv; |
568 | int i; |
569 | |
570 | av_log(ctx, AV_LOG_DEBUG, "negate_alpha:%d\n", s->negate_alpha); |
571 | |
572 | for (i = 0; i < 4; i++) { |
573 | s->comp_expr_str[i] = av_strdup((i == 3 && !s->negate_alpha) ? |
574 | "val" : "negval"); |
575 | if (!s->comp_expr_str[i]) { |
576 | uninit(ctx); |
577 | return AVERROR(ENOMEM); |
578 | } |
579 | } |
580 | |
581 | return 0; |
582 | } |
583 | |
584 | DEFINE_LUT_FILTER(negate, "Negate input video."); |
585 | |
586 | #endif |
587 |