]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_pseudocolor.c
avfilter: Constify all AVFilters
[ffmpeg] / libavfilter / vf_pseudocolor.c
1 /*
2  * Copyright (c) 2017 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 "libavutil/attributes.h"
22 #include "libavutil/common.h"
23 #include "libavutil/eval.h"
24 #include "libavutil/imgutils.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/pixdesc.h"
27 #include "avfilter.h"
28 #include "formats.h"
29 #include "internal.h"
30 #include "video.h"
31
32 static const char *const var_names[] = {
33     "w",        ///< width of the input video
34     "h",        ///< height of the input video
35     "val",      ///< input value for the pixel
36     "ymin",
37     "umin",
38     "vmin",
39     "amin",
40     "ymax",
41     "umax",
42     "vmax",
43     "amax",
44     NULL
45 };
46
47 enum var_name {
48     VAR_W,
49     VAR_H,
50     VAR_VAL,
51     VAR_YMIN,
52     VAR_UMIN,
53     VAR_VMIN,
54     VAR_AMIN,
55     VAR_YMAX,
56     VAR_UMAX,
57     VAR_VMAX,
58     VAR_AMAX,
59     VAR_VARS_NB
60 };
61
62 enum Curves {
63     MAGMA,
64     INFERNO,
65     PLASMA,
66     VIRIDIS,
67     TURBO,
68     CIVIDIS,
69     NB_CURVES,
70 };
71
72 enum Presets {
73     PRESET_MAGMA,
74     PRESET_INFERNO,
75     PRESET_PLASMA,
76     PRESET_VIRIDIS,
77     PRESET_TURBO,
78     PRESET_CIVIDIS,
79     PRESET_RANGE1,
80     PRESET_RANGE2,
81     PRESET_SHADOWS,
82     PRESET_HIGHLIGHTS,
83     NB_PRESETS,
84 };
85
86 typedef struct Curve {
87     double coef[3][8];
88 } Curve;
89
90 typedef struct Fill {
91     float fill[4];
92 } Fill;
93
94 typedef struct Range {
95     int start, end;
96 } Range;
97
98 typedef struct Preset {
99     int nb_segments;
100     const Range *ranges;
101     const Curve *curves;
102     const Fill  *fills;
103 } Preset;
104
105 static const Range full_range   = {0, 256};
106 static const Range spec1_range[] = {{0, 16}, {16, 236}, {236, 256}};
107 static const Range spec2_range[] = {{0, 16}, {16, 22}, {22, 226}, {226, 236}, {236, 256}};
108 static const Range shadows_range[] = {{0, 32}, {32, 256}};
109 static const Range highlights_range[] = {{0, 214}, {214, 224}, {224, 256}};
110
111 static const Fill spec1_fills[] = {{{0.5f, 0.f, .5f, 1.f}}, {{-1.f, -1.f, -1.f, 1.f}}, {{1.f, 0.f, 0.f, 1.f}}};
112 static const Fill spec2_fills[] = {{{0.5f, 0.f, .5f, 1.f}}, {{0.f, 1.f, 1.f, 1.f}}, {{-1.f, -1.f, -1.f, 1.f}}, {{1.f, 1.f, 0.f, 1.f}}, {{1.f, 0.f, 0.f, 1.f}}};
113 static const Fill shadows_fills[] = {{{0.8f, 0.4f, .8f, 1.f}}, {{-1.f, -1.f, -1.f, 1.f}}};
114 static const Fill highlights_fills[] = {{{-1.f, -1.f, -1.f, 1.f}}, {{1.f, 0.3f, 0.6f, 1.f}}, {{1.f, 0.2f, .5f, 1.f}}};
115
116 static const Curve curves[] =
117 {
118     [MAGMA] = {{
119         {-7.5631093e-16,  7.4289183e-13, -2.8525484e-10,  5.4446085e-08, -5.5596238e-06,  3.0569325e-04, -2.3137421e-03,  1.2152095e-02 },
120         { 1.3217636e-15, -1.2214648e-12,  4.4319712e-10, -8.0197993e-08,  7.6598370e-06, -3.6523704e-04,  8.4836670e-03, -2.5536888e-02 },
121         {-1.1446568e-15,  1.0013446e-12, -3.5651575e-10,  6.6775016e-08, -6.7120346e-06,  2.7346619e-04,  4.7969657e-03,  1.1971441e-02 },
122     }},
123     [INFERNO] = {{
124         {-3.9848859e-18,  9.4821649e-14, -6.7371977e-11,  1.8469937e-08, -2.5359307e-06,  1.7959053e-04,  3.9782564e-04,  2.8845935e-04 },
125         { 6.8408539e-16, -6.5499979e-13,  2.4562526e-10, -4.5989298e-08,  4.5723324e-06, -2.2111913e-04,  5.2023164e-03, -1.1226064e-02 },
126         {-2.9921470e-15,  2.5864165e-12, -8.7403799e-10,  1.4713388e-07, -1.2701505e-05,  4.5159935e-04,  3.1087989e-03,  1.9122831e-02 },
127     }},
128     [PLASMA] = {{
129         { 3.6196089e-16, -3.3623041e-13,  1.2324010e-10, -2.2769060e-08,  2.2297792e-06, -1.2567829e-04,  9.9791629e-03,  5.7247918e-02 },
130         { 5.0262888e-16, -5.3193896e-13,  2.2451715e-10, -4.7529623e-08,  5.1374873e-06, -2.3260136e-04,  3.1502825e-03,  1.5362491e-02 },
131         {-1.7782261e-16,  2.2487839e-13, -1.0610236e-10,  2.4112644e-08, -2.6331623e-06,  8.9499751e-05,  2.1386328e-03,  5.3824268e-01 },
132     }},
133     [VIRIDIS] = {{
134         { 9.4850045e-16, -8.6629383e-13,  3.0310944e-10, -5.1340396e-08,  4.6024275e-06, -2.2744239e-04,  4.5559993e-03,  2.5662350e-01 },
135         { 9.6461041e-17, -6.9209477e-14,  1.7625397e-11, -2.0229773e-09,  1.4900110e-07, -1.9315187e-05,  5.8967339e-03,  3.9544827e-03 },
136         { 5.1785449e-16, -3.6663004e-13,  1.0249990e-10, -1.5431998e-08,  1.5007941e-06, -1.2001502e-04,  7.6951526e-03,  3.2292815e-01 },
137     }},
138     [TURBO] = {{
139         {-4.3683890e-15,  3.7020347e-12, -1.1712592e-09,  1.6401790e-07, -8.6842919e-06, -1.8542465e-06,  8.4485325e-03,  1.6267077e-01 },
140         {-4.0011069e-16,  2.7861423e-13, -6.3388921e-11,  5.8872238e-09, -5.4466522e-07,  1.8037114e-05,  1.0599869e-02,  7.6914696e-02 },
141         {-2.8242609e-15,  2.9234108e-12, -1.1726546e-09,  2.2552115e-07, -2.0059387e-05,  5.0595552e-04,  1.7714932e-02,  2.7271836e-01 },
142     }},
143     [CIVIDIS] = {{
144         {-9.5484131e-16,  9.6988184e-13, -4.0058766e-10,  8.5743924e-08, -9.9644797e-06,  5.9197908e-04, -1.0361579e-02,  3.3164429e-02 },
145         { 1.2731941e-17, -9.4238449e-15,  2.2808841e-12, -1.1548296e-10, -2.3888913e-08,  3.8986680e-06,  2.5879330e-03,  1.2769733e-01 },
146         { 4.6004608e-16, -5.0686849e-13,  2.2753449e-10, -5.3074099e-08,  6.7196096e-06, -4.4120020e-04,  1.3435551e-02,  2.8293355e-01 },
147     }},
148 };
149
150 static const Preset presets[] =
151 {
152     [PRESET_MAGMA]   = { 1, &full_range, &curves[MAGMA],   NULL },
153     [PRESET_INFERNO] = { 1, &full_range, &curves[INFERNO], NULL },
154     [PRESET_PLASMA]  = { 1, &full_range, &curves[PLASMA],  NULL },
155     [PRESET_VIRIDIS] = { 1, &full_range, &curves[VIRIDIS], NULL },
156     [PRESET_TURBO]   = { 1, &full_range, &curves[TURBO],   NULL },
157     [PRESET_CIVIDIS] = { 1, &full_range, &curves[CIVIDIS], NULL },
158     [PRESET_RANGE1]  = { 3, spec1_range, NULL,             spec1_fills },
159     [PRESET_RANGE2]  = { 5, spec2_range, NULL,             spec2_fills },
160     [PRESET_SHADOWS] = { 2, shadows_range, NULL,           shadows_fills },
161     [PRESET_HIGHLIGHTS] = { 3, highlights_range, NULL,     highlights_fills },
162 };
163
164 typedef struct PseudoColorContext {
165     const AVClass *class;
166     int preset;
167     float opacity;
168     int max;
169     int index;
170     int nb_planes;
171     int color;
172     int linesize[4];
173     int width[4], height[4];
174     double var_values[VAR_VARS_NB];
175     char   *comp_expr_str[4];
176     AVExpr *comp_expr[4];
177     float lut[4][256*256];
178
179     void (*filter[4])(int max, int width, int height,
180                       const uint8_t *index, const uint8_t *src,
181                       uint8_t *dst,
182                       ptrdiff_t ilinesize,
183                       ptrdiff_t slinesize,
184                       ptrdiff_t dlinesize,
185                       float *lut,
186                       float opacity);
187 } PseudoColorContext;
188
189 #define OFFSET(x) offsetof(PseudoColorContext, x)
190 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
191
192 static const AVOption pseudocolor_options[] = {
193     { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, {.str="val"},   .flags = FLAGS },
194     { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, {.str="val"},   .flags = FLAGS },
195     { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, {.str="val"},   .flags = FLAGS },
196     { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, {.str="val"},   .flags = FLAGS },
197     { "index", "set component as base",    OFFSET(index),            AV_OPT_TYPE_INT,    {.i64=0}, 0, 3, .flags = FLAGS },
198     { "i",  "set component as base",       OFFSET(index),            AV_OPT_TYPE_INT,    {.i64=0}, 0, 3, .flags = FLAGS },
199     { "preset", "set preset",              OFFSET(preset),           AV_OPT_TYPE_INT,    {.i64=-1},-1, NB_PRESETS-1, .flags = FLAGS, "preset" },
200     { "p",  "set preset",                  OFFSET(preset),           AV_OPT_TYPE_INT,    {.i64=-1},-1, NB_PRESETS-1, .flags = FLAGS, "preset" },
201     { "none",       NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=-1},             .flags = FLAGS, "preset" },
202     { "magma",      NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_MAGMA},   .flags = FLAGS, "preset" },
203     { "inferno",    NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_INFERNO}, .flags = FLAGS, "preset" },
204     { "plasma",     NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_PLASMA},  .flags = FLAGS, "preset" },
205     { "viridis",    NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_VIRIDIS}, .flags = FLAGS, "preset" },
206     { "turbo",      NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_TURBO},   .flags = FLAGS, "preset" },
207     { "cividis",    NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_CIVIDIS}, .flags = FLAGS, "preset" },
208     { "range1",     NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_RANGE1},  .flags = FLAGS, "preset" },
209     { "range2",     NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_RANGE2},  .flags = FLAGS, "preset" },
210     { "shadows",    NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_SHADOWS}, .flags = FLAGS, "preset" },
211     { "highlights", NULL,                  0,                        AV_OPT_TYPE_CONST,  {.i64=PRESET_HIGHLIGHTS},.flags=FLAGS, "preset" },
212     { "opacity", "set pseudocolor opacity",OFFSET(opacity),          AV_OPT_TYPE_FLOAT,  {.dbl=1}, 0, 1, .flags = FLAGS },
213     { NULL }
214 };
215
216 static const enum AVPixelFormat pix_fmts[] = {
217     AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16,
218     AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P,
219     AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P,
220     AV_PIX_FMT_YUV444P, AV_PIX_FMT_GBRP,
221     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GBRAP,
222     AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUVA422P9,
223     AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUVA420P9,
224     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9,
225     AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUVA420P10,
226     AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUVA422P10,
227     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
228     AV_PIX_FMT_YUV420P12,
229     AV_PIX_FMT_YUV422P12,
230     AV_PIX_FMT_YUV444P12,
231     AV_PIX_FMT_YUV420P14,
232     AV_PIX_FMT_YUV422P14,
233     AV_PIX_FMT_YUV444P14,
234     AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUVA420P16,
235     AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUVA422P16,
236     AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16,
237     AV_PIX_FMT_GBRP9,
238     AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
239     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
240     AV_PIX_FMT_GBRP14,
241     AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16,
242     AV_PIX_FMT_NONE
243 };
244
245 static int query_formats(AVFilterContext *ctx)
246 {
247     AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
248     if (!fmts_list)
249         return AVERROR(ENOMEM);
250     return ff_set_common_formats(ctx, fmts_list);
251 }
252
253 static inline float lerpf(float v0, float v1, float f)
254 {
255     return v0 + (v1 - v0) * f;
256 }
257
258 #define PCLIP(v, max, dst, src, x) \
259     if (v >= 0 && v <= max) {      \
260         dst[x] = lerpf(src[x], v, opacity);\
261     } else {                       \
262         dst[x] = src[x];           \
263     }
264
265 static void pseudocolor_filter(int max, int width, int height,
266                                const uint8_t *index,
267                                const uint8_t *src,
268                                uint8_t *dst,
269                                ptrdiff_t ilinesize,
270                                ptrdiff_t slinesize,
271                                ptrdiff_t dlinesize,
272                                float *lut,
273                                float opacity)
274 {
275     int x, y;
276
277     for (y = 0; y < height; y++) {
278         for (x = 0; x < width; x++) {
279             int v = lut[index[x]];
280
281             PCLIP(v, max, dst, src, x);
282         }
283         index += ilinesize;
284         src += slinesize;
285         dst += dlinesize;
286     }
287 }
288
289 static void pseudocolor_filter_11(int max, int width, int height,
290                                   const uint8_t *index,
291                                   const uint8_t *src,
292                                   uint8_t *dst,
293                                   ptrdiff_t ilinesize,
294                                   ptrdiff_t slinesize,
295                                   ptrdiff_t dlinesize,
296                                   float *lut,
297                                   float opacity)
298 {
299     int x, y;
300
301     for (y = 0; y < height; y++) {
302         for (x = 0; x < width; x++) {
303             int v = lut[index[(y << 1) * ilinesize + (x << 1)]];
304
305             PCLIP(v, max, dst, src, x);
306         }
307         src += slinesize;
308         dst += dlinesize;
309     }
310 }
311
312 static void pseudocolor_filter_11d(int max, int width, int height,
313                                    const uint8_t *index,
314                                    const uint8_t *src,
315                                    uint8_t *dst,
316                                    ptrdiff_t ilinesize,
317                                    ptrdiff_t slinesize,
318                                    ptrdiff_t dlinesize,
319                                    float *lut,
320                                    float opacity)
321 {
322     int x, y;
323
324     for (y = 0; y < height; y++) {
325         for (x = 0; x < width; x++) {
326             int v = lut[index[(y >> 1) * ilinesize + (x >> 1)]];
327
328             PCLIP(v, max, dst, src, x);
329         }
330         src += slinesize;
331         dst += dlinesize;
332     }
333 }
334
335 static void pseudocolor_filter_10(int max, int width, int height,
336                                   const uint8_t *index,
337                                   const uint8_t *src,
338                                   uint8_t *dst,
339                                   ptrdiff_t ilinesize,
340                                   ptrdiff_t slinesize,
341                                   ptrdiff_t dlinesize,
342                                   float *lut,
343                                   float opacity)
344 {
345     int x, y;
346
347     for (y = 0; y < height; y++) {
348         for (x = 0; x < width; x++) {
349             int v = lut[index[x << 1]];
350
351             PCLIP(v, max, dst, src, x);
352         }
353         index += ilinesize;
354         src += slinesize;
355         dst += dlinesize;
356     }
357 }
358
359 static void pseudocolor_filter_10d(int max, int width, int height,
360                                    const uint8_t *index,
361                                    const uint8_t *src,
362                                    uint8_t *dst,
363                                    ptrdiff_t ilinesize,
364                                    ptrdiff_t slinesize,
365                                    ptrdiff_t dlinesize,
366                                    float *lut,
367                                    float opacity)
368 {
369     int x, y;
370
371     for (y = 0; y < height; y++) {
372         for (x = 0; x < width; x++) {
373             int v = lut[index[x >> 1]];
374
375             PCLIP(v, max, dst, src, x);
376         }
377         index += ilinesize;
378         src += slinesize;
379         dst += dlinesize;
380     }
381 }
382
383 static void pseudocolor_filter_16(int max, int width, int height,
384                                   const uint8_t *iindex,
385                                   const uint8_t *ssrc,
386                                   uint8_t *ddst,
387                                   ptrdiff_t ilinesize,
388                                   ptrdiff_t slinesize,
389                                   ptrdiff_t dlinesize,
390                                   float *lut,
391                                   float opacity)
392 {
393     const uint16_t *index = (const uint16_t *)iindex;
394     const uint16_t *src = (const uint16_t *)ssrc;
395     uint16_t *dst = (uint16_t *)ddst;
396     int x, y;
397
398     for (y = 0; y < height; y++) {
399         for (x = 0; x < width; x++) {
400             int v = lut[index[x]];
401
402             PCLIP(v, max, dst, src, x);
403         }
404         index += ilinesize / 2;
405         src += slinesize / 2;
406         dst += dlinesize / 2;
407     }
408 }
409
410 static void pseudocolor_filter_16_10(int max, int width, int height,
411                                      const uint8_t *iindex,
412                                      const uint8_t *ssrc,
413                                      uint8_t *ddst,
414                                      ptrdiff_t ilinesize,
415                                      ptrdiff_t slinesize,
416                                      ptrdiff_t dlinesize,
417                                      float *lut,
418                                      float opacity)
419 {
420     const uint16_t *index = (const uint16_t *)iindex;
421     const uint16_t *src = (const uint16_t *)ssrc;
422     uint16_t *dst = (uint16_t *)ddst;
423     int x, y;
424
425     for (y = 0; y < height; y++) {
426         for (x = 0; x < width; x++) {
427             int v = lut[index[x << 1]];
428
429             PCLIP(v, max, dst, src, x);
430         }
431         index += ilinesize / 2;
432         src += slinesize / 2;
433         dst += dlinesize / 2;
434     }
435 }
436
437 static void pseudocolor_filter_16_10d(int max, int width, int height,
438                                       const uint8_t *iindex,
439                                       const uint8_t *ssrc,
440                                       uint8_t *ddst,
441                                       ptrdiff_t ilinesize,
442                                       ptrdiff_t slinesize,
443                                       ptrdiff_t dlinesize,
444                                       float *lut,
445                                       float opacity)
446 {
447     const uint16_t *index = (const uint16_t *)iindex;
448     const uint16_t *src = (const uint16_t *)ssrc;
449     uint16_t *dst = (uint16_t *)ddst;
450     int x, y;
451
452     for (y = 0; y < height; y++) {
453         for (x = 0; x < width; x++) {
454             int v = lut[index[x >> 1]];
455
456             PCLIP(v, max, dst, src, x);
457         }
458         index += ilinesize / 2;
459         src += slinesize / 2;
460         dst += dlinesize / 2;
461     }
462 }
463
464 static void pseudocolor_filter_16_11(int max, int width, int height,
465                                      const uint8_t *iindex,
466                                      const uint8_t *ssrc,
467                                      uint8_t *ddst,
468                                      ptrdiff_t ilinesize,
469                                      ptrdiff_t slinesize,
470                                      ptrdiff_t dlinesize,
471                                      float *lut,
472                                      float opacity)
473 {
474     const uint16_t *index = (const uint16_t *)iindex;
475     const uint16_t *src = (const uint16_t *)ssrc;
476     uint16_t *dst = (uint16_t *)ddst;
477     int x, y;
478
479     ilinesize /= 2;
480     dlinesize /= 2;
481     slinesize /= 2;
482
483     for (y = 0; y < height; y++) {
484         for (x = 0; x < width; x++) {
485             int v = lut[index[(y << 1) * ilinesize + (x << 1)]];
486
487             PCLIP(v, max, dst, src, x);
488         }
489         src += slinesize;
490         dst += dlinesize;
491     }
492 }
493
494 static void pseudocolor_filter_16_11d(int max, int width, int height,
495                                       const uint8_t *iindex,
496                                       const uint8_t *ssrc,
497                                       uint8_t *ddst,
498                                       ptrdiff_t ilinesize,
499                                       ptrdiff_t slinesize,
500                                       ptrdiff_t dlinesize,
501                                       float *lut,
502                                       float opacity)
503 {
504     const uint16_t *index = (const uint16_t *)iindex;
505     const uint16_t *src = (const uint16_t *)ssrc;
506     uint16_t *dst = (uint16_t *)ddst;
507     int x, y;
508
509     ilinesize /= 2;
510     dlinesize /= 2;
511     slinesize /= 2;
512
513     for (y = 0; y < height; y++) {
514         for (x = 0; x < width; x++) {
515             int v = lut[index[(y >> 1) * ilinesize + (x >> 1)]];
516
517             PCLIP(v, max, dst, src, x);
518         }
519         src += slinesize;
520         dst += dlinesize;
521     }
522 }
523
524 #define RGB_TO_Y_BT709(r, g, b) \
525 ((0.21260*219.0/255.0) * (r) + (0.71520*219.0/255.0) * (g) + \
526  (0.07220*219.0/255.0) * (b))
527
528 #define RGB_TO_U_BT709(r1, g1, b1, max) \
529 (-(0.11457*224.0/255.0) * r1 - (0.38543*224.0/255.0) * g1 + \
530     (0.50000*224.0/255.0) * b1 + max * 0.5)
531
532 #define RGB_TO_V_BT709(r1, g1, b1, max) \
533 ((0.50000*224.0/255.0) * r1 - (0.45415*224.0/255.0) * g1 - \
534    (0.04585*224.0/255.0) * b1 + max * 0.5)
535
536 static double poly_eval(const double *const poly, double x)
537 {
538     double res = 0.;
539
540     for (int i = 0; i < 8; i++) {
541         res += pow(x, i) * poly[7-i];
542     }
543
544     return av_clipd(res, 0., 1.);
545 }
546
547 static int config_input(AVFilterLink *inlink)
548 {
549     AVFilterContext *ctx = inlink->dst;
550     PseudoColorContext *s = ctx->priv;
551     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
552     int depth, ret, hsub, vsub, color, factor, rgb;
553
554     rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
555     depth = desc->comp[0].depth;
556     factor = 1 << (depth - 8);
557     s->max = (1 << depth) - 1;
558     s->nb_planes = av_pix_fmt_count_planes(inlink->format);
559
560     if (s->index >= s->nb_planes) {
561         av_log(ctx, AV_LOG_ERROR, "index out of allowed range\n");
562         return AVERROR(EINVAL);
563     }
564
565     if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0)
566         return ret;
567
568     hsub = desc->log2_chroma_w;
569     vsub = desc->log2_chroma_h;
570     s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub);
571     s->height[0] = s->height[3] = inlink->h;
572     s->width[1]  = s->width[2]  = AV_CEIL_RSHIFT(inlink->w, hsub);
573     s->width[0]  = s->width[3]  = inlink->w;
574
575     s->var_values[VAR_W] = inlink->w;
576     s->var_values[VAR_H] = inlink->h;
577
578     s->var_values[VAR_YMIN] = 16 * (1 << (depth - 8));
579     s->var_values[VAR_UMIN] = 16 * (1 << (depth - 8));
580     s->var_values[VAR_VMIN] = 16 * (1 << (depth - 8));
581     s->var_values[VAR_AMIN] = 0;
582     s->var_values[VAR_YMAX] = 235 * (1 << (depth - 8));
583     s->var_values[VAR_UMAX] = 240 * (1 << (depth - 8));
584     s->var_values[VAR_VMAX] = 240 * (1 << (depth - 8));
585     s->var_values[VAR_AMAX] = s->max;
586
587     for (color = 0; color < s->nb_planes && s->preset < 0; color++) {
588         double res;
589         int val;
590
591         /* create the parsed expression */
592         av_expr_free(s->comp_expr[color]);
593         s->comp_expr[color] = NULL;
594         ret = av_expr_parse(&s->comp_expr[color], s->comp_expr_str[color],
595                             var_names, NULL, NULL, NULL, NULL, 0, ctx);
596         if (ret < 0) {
597             av_log(ctx, AV_LOG_ERROR,
598                    "Error when parsing the expression '%s' for the component %d and color %d.\n",
599                    s->comp_expr_str[color], color, color);
600             return AVERROR(EINVAL);
601         }
602
603         /* compute the lut */
604         for (val = 0; val < FF_ARRAY_ELEMS(s->lut[color]); val++) {
605             s->var_values[VAR_VAL] = val;
606
607             res = av_expr_eval(s->comp_expr[color], s->var_values, s);
608             if (isnan(res)) {
609                 av_log(ctx, AV_LOG_ERROR,
610                        "Error when evaluating the expression '%s' for the value %d for the component %d.\n",
611                        s->comp_expr_str[color], val, color);
612                 return AVERROR(EINVAL);
613             }
614             s->lut[color][val] = res;
615         }
616     }
617
618     if (s->preset >= 0) {
619         int nb_segments = presets[s->preset].nb_segments;
620
621         for (int seg = 0; seg < nb_segments; seg++) {
622             int start = presets[s->preset].ranges[seg].start;
623             int end   = presets[s->preset].ranges[seg].end;
624
625             for (int i = start; i < end; i++) {
626                 if (!presets[s->preset].curves) {
627                     const Fill fill = presets[s->preset].fills[seg];
628
629                     for (int j = 0; j < factor; j++) {
630                         double r, g, b, a;
631
632                         g = fill.fill[1];
633                         b = fill.fill[2];
634                         r = fill.fill[0];
635                         a = fill.fill[3];
636
637                         if (g >= 0.f && b >= 0.f && r >= 0.f) {
638                             g *= s->max;
639                             b *= s->max;
640                             r *= s->max;
641
642                             if (!rgb) {
643                                 double y = RGB_TO_Y_BT709(r, g, b);
644                                 double u = RGB_TO_U_BT709(r, g, b, s->max);
645                                 double v = RGB_TO_V_BT709(r, g, b, s->max);
646
647                                 r = v;
648                                 g = y;
649                                 b = u;
650                             }
651                         }
652
653                         s->lut[0][i*factor+j] = g;
654                         s->lut[1][i*factor+j] = b;
655                         s->lut[2][i*factor+j] = r;
656                         s->lut[3][i*factor+j] = a * s->max;
657                     }
658                 } else {
659                     const Curve curve = presets[s->preset].curves[seg];
660
661                     for (int j = 0; j < factor; j++) {
662                         const double lf = j / (double)factor;
663                         double r, g, b;
664
665                         g = poly_eval(curve.coef[1], i + lf) * s->max;
666                         b = poly_eval(curve.coef[2], i + lf) * s->max;
667                         r = poly_eval(curve.coef[0], i + lf) * s->max;
668
669                         if (!rgb) {
670                             double y = RGB_TO_Y_BT709(r, g, b);
671                             double u = RGB_TO_U_BT709(r, g, b, s->max);
672                             double v = RGB_TO_V_BT709(r, g, b, s->max);
673
674                             r = v;
675                             g = y;
676                             b = u;
677                         }
678
679                         s->lut[0][i*factor+j] = g;
680                         s->lut[1][i*factor+j] = b;
681                         s->lut[2][i*factor+j] = r;
682                         s->lut[3][i*factor+j] = 1.f * s->max;
683                     }
684                 }
685             }
686         }
687     }
688
689     switch (inlink->format) {
690     case AV_PIX_FMT_YUV444P:
691     case AV_PIX_FMT_YUVA444P:
692     case AV_PIX_FMT_GBRP:
693     case AV_PIX_FMT_GBRAP:
694     case AV_PIX_FMT_GRAY8:
695         s->filter[0] = s->filter[1] = s->filter[2] = s->filter[3] = pseudocolor_filter;
696         break;
697     case AV_PIX_FMT_YUV420P:
698     case AV_PIX_FMT_YUVA420P:
699         switch (s->index) {
700         case 0:
701         case 3:
702             s->filter[0] = s->filter[3] = pseudocolor_filter;
703             s->filter[1] = s->filter[2] = pseudocolor_filter_11;
704             break;
705         case 1:
706         case 2:
707             s->filter[0] = s->filter[3] = pseudocolor_filter_11d;
708             s->filter[1] = s->filter[2] = pseudocolor_filter;
709             break;
710         }
711         break;
712     case AV_PIX_FMT_YUV422P:
713     case AV_PIX_FMT_YUVA422P:
714         switch (s->index) {
715         case 0:
716         case 3:
717             s->filter[0] = s->filter[3] = pseudocolor_filter;
718             s->filter[1] = s->filter[2] = pseudocolor_filter_10;
719             break;
720         case 1:
721         case 2:
722             s->filter[0] = s->filter[3] = pseudocolor_filter_10d;
723             s->filter[1] = s->filter[2] = pseudocolor_filter;
724             break;
725         }
726         break;
727     case AV_PIX_FMT_YUV444P9:
728     case AV_PIX_FMT_YUVA444P9:
729     case AV_PIX_FMT_YUV444P10:
730     case AV_PIX_FMT_YUVA444P10:
731     case AV_PIX_FMT_YUV444P12:
732     case AV_PIX_FMT_YUV444P14:
733     case AV_PIX_FMT_YUV444P16:
734     case AV_PIX_FMT_YUVA444P16:
735     case AV_PIX_FMT_GBRP9:
736     case AV_PIX_FMT_GBRP10:
737     case AV_PIX_FMT_GBRP12:
738     case AV_PIX_FMT_GBRP14:
739     case AV_PIX_FMT_GBRP16:
740     case AV_PIX_FMT_GBRAP10:
741     case AV_PIX_FMT_GBRAP12:
742     case AV_PIX_FMT_GBRAP16:
743     case AV_PIX_FMT_GRAY9:
744     case AV_PIX_FMT_GRAY10:
745     case AV_PIX_FMT_GRAY12:
746     case AV_PIX_FMT_GRAY14:
747     case AV_PIX_FMT_GRAY16:
748         s->filter[0] = s->filter[1] = s->filter[2] = s->filter[3] = pseudocolor_filter_16;
749         break;
750     case AV_PIX_FMT_YUV422P9:
751     case AV_PIX_FMT_YUVA422P9:
752     case AV_PIX_FMT_YUV422P10:
753     case AV_PIX_FMT_YUVA422P10:
754     case AV_PIX_FMT_YUV422P12:
755     case AV_PIX_FMT_YUV422P14:
756     case AV_PIX_FMT_YUV422P16:
757     case AV_PIX_FMT_YUVA422P16:
758         switch (s->index) {
759         case 0:
760         case 3:
761             s->filter[0] = s->filter[3] = pseudocolor_filter_16;
762             s->filter[1] = s->filter[2] = pseudocolor_filter_16_10;
763             break;
764         case 1:
765         case 2:
766             s->filter[0] = s->filter[3] = pseudocolor_filter_16_10d;
767             s->filter[1] = s->filter[2] = pseudocolor_filter_16;
768             break;
769         }
770         break;
771     case AV_PIX_FMT_YUV420P9:
772     case AV_PIX_FMT_YUVA420P9:
773     case AV_PIX_FMT_YUV420P10:
774     case AV_PIX_FMT_YUVA420P10:
775     case AV_PIX_FMT_YUV420P12:
776     case AV_PIX_FMT_YUV420P14:
777     case AV_PIX_FMT_YUV420P16:
778     case AV_PIX_FMT_YUVA420P16:
779         switch (s->index) {
780         case 0:
781         case 3:
782             s->filter[0] = s->filter[3] = pseudocolor_filter_16;
783             s->filter[1] = s->filter[2] = pseudocolor_filter_16_11;
784             break;
785         case 1:
786         case 2:
787             s->filter[0] = s->filter[3] = pseudocolor_filter_16_11d;
788             s->filter[1] = s->filter[2] = pseudocolor_filter_16;
789             break;
790         }
791         break;
792     }
793
794     return 0;
795 }
796
797 typedef struct ThreadData {
798     AVFrame *in, *out;
799 } ThreadData;
800
801 static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
802 {
803     PseudoColorContext *s = ctx->priv;
804     ThreadData *td = arg;
805     AVFrame *in = td->in;
806     AVFrame *out = td->out;
807
808     for (int plane = 0; plane < s->nb_planes; plane++) {
809         const int slice_start = (s->height[plane] * jobnr) / nb_jobs;
810         const int slice_end = (s->height[plane] * (jobnr+1)) / nb_jobs;
811         const int islice_start = (s->height[s->index] * jobnr) / nb_jobs;
812         ptrdiff_t ilinesize = in->linesize[s->index];
813         ptrdiff_t slinesize = in->linesize[plane];
814         ptrdiff_t dlinesize = out->linesize[plane];
815         const uint8_t *index = in->data[s->index] + islice_start * ilinesize;
816         const uint8_t *src = in->data[plane] + slice_start * slinesize;
817         uint8_t *dst = out->data[plane] + slice_start * dlinesize;
818
819         s->filter[plane](s->max, s->width[plane], slice_end - slice_start,
820                          index, src, dst, ilinesize, slinesize,
821                          dlinesize, s->lut[plane], s->opacity);
822     }
823
824     return 0;
825 }
826
827 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
828 {
829     AVFilterContext *ctx = inlink->dst;
830     PseudoColorContext *s = ctx->priv;
831     AVFilterLink *outlink = ctx->outputs[0];
832     ThreadData td;
833     AVFrame *out;
834
835     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
836     if (!out) {
837         av_frame_free(&in);
838         return AVERROR(ENOMEM);
839     }
840     av_frame_copy_props(out, in);
841
842     td.out = out, td.in = in;
843     ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(s->height[1], ff_filter_get_nb_threads(ctx)));
844
845     av_frame_free(&in);
846     return ff_filter_frame(outlink, out);
847 }
848
849 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
850                            char *res, int res_len, int flags)
851 {
852     int ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
853
854     if (ret < 0)
855         return ret;
856
857     return config_input(ctx->inputs[0]);
858 }
859
860 static const AVFilterPad inputs[] = {
861     {
862         .name         = "default",
863         .type         = AVMEDIA_TYPE_VIDEO,
864         .filter_frame = filter_frame,
865         .config_props = config_input,
866     },
867     { NULL }
868 };
869
870 static const AVFilterPad outputs[] = {
871     {
872         .name = "default",
873         .type = AVMEDIA_TYPE_VIDEO,
874     },
875     { NULL }
876 };
877
878 static av_cold void uninit(AVFilterContext *ctx)
879 {
880     PseudoColorContext *s = ctx->priv;
881     int i;
882
883     for (i = 0; i < 4; i++) {
884         av_expr_free(s->comp_expr[i]);
885         s->comp_expr[i] = NULL;
886     }
887 }
888
889 AVFILTER_DEFINE_CLASS(pseudocolor);
890
891 const AVFilter ff_vf_pseudocolor = {
892     .name          = "pseudocolor",
893     .description   = NULL_IF_CONFIG_SMALL("Make pseudocolored video frames."),
894     .priv_size     = sizeof(PseudoColorContext),
895     .priv_class    = &pseudocolor_class,
896     .uninit        = uninit,
897     .query_formats = query_formats,
898     .inputs        = inputs,
899     .outputs       = outputs,
900     .flags         = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS,
901     .process_command = process_command,
902 };