1 /*
2 * Copyright (c) 2016 Paul B Mahol
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 #include "config_components.h"
22
34
36 "w", ///< width of the input video
37 "h", ///< height of the input video
38 "x", ///< input value for the pixel from input #1
39 "y", ///< input value for the pixel from input #2
40 "bdx", ///< input #1 video bitdepth
41 "bdy", ///< input #2 video bitdepth
43 };
44
53 };
54
58
61
64 uint16_t *
lut[4];
///< lookup table for each component
74
77
81
82 #define OFFSET(x) offsetof(LUT2Context, x)
83 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
84 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
85
93 };
94
96 {
99
102
103 for (
i = 0;
i < 4;
i++) {
108 }
109 }
110
112 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, \
113 AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, \
114 AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, \
115 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \
116 AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, \
117 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
118
120 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GRAY9, \
121 AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, \
122 AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9,
123
125 AV_PIX_FMT_GRAY10, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, \
126 AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, \
127 AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10,
128
130 AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, \
131 AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA444P12, \
132 AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRP12,
133
135 AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, \
136 AV_PIX_FMT_GRAY14, AV_PIX_FMT_GBRP14,
137
139 AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, \
140 AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, \
141 AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16,
142
144 {
152 };
156 };
160 };
164 };
168 };
172 };
176 };
179
180 if (
s->tlut2 || !
s->odepth)
182
186
188 case 8:
pix_fmts = bit8_pix_fmts;
break;
189 case 9:
pix_fmts = bit9_pix_fmts;
break;
190 case 10:
pix_fmts = bit10_pix_fmts;
break;
191 case 12:
pix_fmts = bit12_pix_fmts;
break;
192 case 14:
pix_fmts = bit14_pix_fmts;
break;
193 case 16:
pix_fmts = bit16_pix_fmts;
break;
196 }
197
199 }
200
202 {
207 int vsub =
desc->log2_chroma_h;
208
211 s->heightx[0] =
s->heightx[3] =
inlink->h;
213 s->widthx[0] =
s->widthx[3] =
inlink->w;
214
217 s->depthx =
desc->comp[0].depth;
219
221 s->depthy =
desc->comp[0].depth;
223 }
224
225 return 0;
226 }
227
229 {
234 int vsub =
desc->log2_chroma_h;
235
237 s->depthy =
desc->comp[0].depth;
240 s->heighty[0] =
s->heighty[3] =
inlink->h;
242 s->widthy[0] =
s->widthy[3] =
inlink->w;
243
244 return 0;
245 }
246
247 #define DEFINE_LUT2(zname, xname, yname, ztype, xtype, ytype, zdiv, xdiv, ydiv) \
248 static int lut2_##zname##_##xname##_##yname(AVFilterContext *ctx, \
249 void *arg, \
250 int jobnr, int nb_jobs) \
251 { \
252 LUT2Context *s = ctx->priv; \
253 ThreadData *td = arg; \
254 AVFrame *out = td->out; \
255 AVFrame *srcx = td->srcx; \
256 AVFrame *srcy = td->srcy; \
257 const int odepth = s->odepth; \
258 int p, y, x; \
259 \
260 for (p = 0; p < s->nb_planes; p++) { \
261 const int slice_start = (s->heightx[p] * jobnr) / nb_jobs; \
262 const int slice_end = (s->heightx[p] * (jobnr+1)) / nb_jobs; \
263 const uint16_t *lut = s->lut[p]; \
264 const xtype *srcxx; \
265 const ytype *srcyy; \
266 ztype *dst; \
267 \
268 dst = (ztype *)(out->data[p] + slice_start * out->linesize[p]); \
269 srcxx = (const xtype *)(srcx->data[p] + slice_start * srcx->linesize[p]);\
270 srcyy = (const ytype *)(srcy->data[p] + slice_start * srcy->linesize[p]);\
271 \
272 for (y = slice_start; y < slice_end; y++) { \
273 for (x = 0; x < s->widthx[p]; x++) { \
274 dst[x] = av_clip_uintp2_c(lut[(srcyy[x] << s->depthx) | srcxx[x]], odepth); \
275 } \
276 \
277 dst += out->linesize[p] / zdiv; \
278 srcxx += srcx->linesize[p] / xdiv; \
279 srcyy += srcy->linesize[p] / ydiv; \
280 } \
281 } \
282 return 0; \
283 }
284
285 DEFINE_LUT2(8, 8, 8, uint8_t, uint8_t, uint8_t, 1, 1, 1)
286 DEFINE_LUT2(8, 8, 16, uint8_t, uint8_t, uint16_t, 1, 1, 2)
287 DEFINE_LUT2(8, 16, 8, uint8_t, uint16_t, uint8_t, 1, 2, 1)
288 DEFINE_LUT2(8, 16, 16, uint8_t, uint16_t, uint16_t, 1, 2, 2)
289 DEFINE_LUT2(16, 8, 8, uint16_t, uint8_t, uint8_t, 2, 1, 1)
290 DEFINE_LUT2(16, 8, 16, uint16_t, uint8_t, uint16_t, 2, 1, 2)
291 DEFINE_LUT2(16, 16, 8, uint16_t, uint16_t, uint8_t, 2, 2, 1)
292 DEFINE_LUT2(16, 16, 16, uint16_t, uint16_t, uint16_t, 2, 2, 2)
293
295 {
301
305
306 if (
ctx->is_disabled || !srcy) {
310 } else {
312
317
323 }
324
326
328 }
329
331 {
335
336 s->depth =
s->depthx +
s->depthy;
337 s->nb_planes =
s->nb_planesx;
338
339 s->lut2 =
s->depth > 16 ? lut2_16_16_16 : lut2_8_8_8;
341 if (
s->depthx == 8 &&
s->depthy == 8 &&
s->odepth > 8)
342 s->lut2 = lut2_16_8_8;
343 if (
s->depthx > 8 &&
s->depthy == 8 &&
s->odepth > 8)
344 s->lut2 = lut2_16_16_8;
345 if (
s->depthx == 8 &&
s->depthy > 8 &&
s->odepth > 8)
346 s->lut2 = lut2_16_8_16;
347 if (
s->depthx == 8 &&
s->depthy == 8 &&
s->odepth == 8)
348 s->lut2 = lut2_8_8_8;
349 if (
s->depthx > 8 &&
s->depthy == 8 &&
s->odepth == 8)
350 s->lut2 = lut2_8_16_8;
351 if (
s->depthx == 8 &&
s->depthy > 8 &&
s->odepth == 8)
352 s->lut2 = lut2_8_8_16;
353 if (
s->depthx > 8 &&
s->depthy > 8 &&
s->odepth == 8)
354 s->lut2 = lut2_8_16_16;
355 } else {
356 s->odepth =
s->depthx;
357 }
358
359 for (p = 0; p <
s->nb_planes; p++) {
364 }
365
366 for (p = 0; p <
s->nb_planes; p++) {
367 double res;
368 int x, y;
369
370 /* create the parsed expression */
372 s->comp_expr[p] =
NULL;
377 "Error when parsing the expression '%s' for the component %d.\n",
378 s->comp_expr_str[p], p);
380 }
381
382 /* compute the lut */
383 for (y = 0; y < (1 <<
s->depthy); y++) {
385 for (x = 0; x < (1 <<
s->depthx); x++) {
390 "Error when evaluating the expression '%s' for the values %d and %d for the component %d.\n",
391 s->comp_expr_str[p], x, y, p);
393 }
394
395 s->lut[p][(y <<
s->depthx) + x] = res;
396 }
397 }
398 }
399
400 return 0;
401 }
402
404 {
414 int vsub =
desc->log2_chroma_h;
416
417 outlink->
w = srcx->
w;
418 outlink->
h = srcx->
h;
422
425 s->height[0] =
s->height[3] = outlink->
h;
427 s->width[0] =
s->width[3] = outlink->
w;
428
432 }
433
434 if (srcx->
w != srcy->
w || srcx->
h != srcy->
h) {
436 "(size %dx%d) do not match the corresponding "
437 "second input link %s parameters (size %dx%d)\n",
438 ctx->input_pads[0].name, srcx->
w, srcx->
h,
439 ctx->input_pads[1].name,
442 }
443
444 if (
s->nb_planesx !=
s->nb_planesy) {
446 "(%d) do not match the corresponding "
447 "second input link %s number of planes (%d)\n",
448 ctx->input_pads[0].name,
s->nb_planesx,
449 ctx->input_pads[1].name,
s->nb_planesy);
451 }
452
453 if (
s->nb_planesx !=
s->nb_planes) {
455 "(%d) do not match the corresponding "
456 "output link %s number of planes (%d)\n",
457 ctx->input_pads[0].name,
s->nb_planesx,
458 ctx->output_pads[0].name,
s->nb_planes);
460 }
461
462 if (
s->widthx[1] !=
s->widthy[1] ||
s->heightx[1] !=
s->heighty[1]) {
464 "(size %dx%d) do not match the corresponding "
465 "second input link %s 2nd plane (size %dx%d)\n",
466 ctx->input_pads[0].name,
s->widthx[1],
s->heightx[1],
467 ctx->input_pads[1].name,
468 s->widthy[1],
s->heighty[1]);
470 }
471
472 if (
s->widthx[2] !=
s->widthy[2] ||
s->heightx[2] !=
s->heighty[2]) {
474 "(size %dx%d) do not match the corresponding "
475 "second input link %s 3rd plane (size %dx%d)\n",
476 ctx->input_pads[0].name,
s->widthx[2],
s->heightx[2],
477 ctx->input_pads[1].name,
478 s->widthy[2],
s->heighty[2]);
480 }
481
482 if (
s->widthx[1] !=
s->width[1] ||
s->heightx[1] !=
s->height[1]) {
484 "(size %dx%d) do not match the corresponding "
485 "output link %s 2nd plane (size %dx%d)\n",
486 ctx->input_pads[0].name,
s->widthx[1],
s->heightx[1],
487 ctx->output_pads[0].name,
s->width[1],
s->height[1]);
489 }
490
491 if (
s->widthx[2] !=
s->width[2] ||
s->heightx[2] !=
s->height[2]) {
493 "(size %dx%d) do not match the corresponding "
494 "output link %s 3rd plane (size %dx%d)\n",
495 ctx->input_pads[0].name,
s->widthx[2],
s->heightx[2],
496 ctx->output_pads[0].name,
s->width[2],
s->height[2]);
498 }
499
502
514
517
520
522 }
523
525 {
528 }
529
531 {
535 },
536 {
537 .name = "srcy",
540 },
541 };
542
544 {
548 },
549 };
550
552 char *res,
int res_len,
int flags)
553 {
555
558
560 }
561
562 #define lut2_options options
563
565
569 .preinit = lut2_framesync_preinit,
571 .priv_class = &lut2_class,
580 };
581
582 #if CONFIG_TLUT2_FILTER
583
585 {
587
588 s->tlut2 = !strcmp(
ctx->filter->name,
"tlut2");
589
590 return 0;
591 }
592
594 {
598
601
602 if (
ctx->is_disabled) {
604 } else {
606
612 }
613
615
618 td.
srcy =
s->prev_frame;
621 }
625 }
627 return 0;
628 }
629
630 static const AVOption tlut2_options[] = {
636 };
637
639
641 {
644 .filter_frame = tlut2_filter_frame,
646 },
647 };
648
650 {
654 },
655 };
656
659 .description =
NULL_IF_CONFIG_SMALL(
"Compute and apply a lookup table from two successive frames."),
661 .priv_class = &tlut2_class,
670 };
671
672 #endif