]> git.sesse.net Git - ffmpeg/blob - libavfilter/vf_waveform.c
lavc/qsvenc: add Tiles encode support for HEVC
[ffmpeg] / libavfilter / vf_waveform.c
1 /*
2  * Copyright (c) 2012-2016 Paul B Mahol
3  * Copyright (c) 2013 Marton Balint
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "libavutil/avassert.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/parseutils.h"
25 #include "libavutil/pixdesc.h"
26 #include "libavutil/xga_font_data.h"
27 #include "avfilter.h"
28 #include "formats.h"
29 #include "internal.h"
30 #include "video.h"
31
32 typedef struct ThreadData {
33     AVFrame *in;
34     AVFrame *out;
35     int component;
36     int offset_y;
37     int offset_x;
38 } ThreadData;
39
40 enum FilterType {
41     LOWPASS,
42     FLAT,
43     AFLAT,
44     CHROMA,
45     COLOR,
46     ACOLOR,
47     XFLAT,
48     YFLAT,
49     NB_FILTERS
50 };
51
52 enum DisplayType {
53     OVERLAY,
54     STACK,
55     PARADE,
56     NB_DISPLAYS
57 };
58
59 enum ScaleType {
60     DIGITAL,
61     MILLIVOLTS,
62     IRE,
63     NB_SCALES
64 };
65
66 enum GraticuleType {
67     GRAT_NONE,
68     GRAT_GREEN,
69     GRAT_ORANGE,
70     GRAT_INVERT,
71     NB_GRATICULES
72 };
73
74 typedef struct GraticuleLine {
75     const char *name;
76     uint16_t pos;
77 } GraticuleLine;
78
79 typedef struct GraticuleLines {
80     struct GraticuleLine line[4];
81 } GraticuleLines;
82
83 typedef struct WaveformContext {
84     const AVClass *class;
85     int            mode;
86     int            acomp;
87     int            dcomp;
88     int            ncomp;
89     int            pcomp;
90     uint8_t        bg_color[4];
91     float          fintensity;
92     int            intensity;
93     int            mirror;
94     int            display;
95     int            envelope;
96     int            graticule;
97     float          opacity;
98     float          bgopacity;
99     int            estart[4];
100     int            eend[4];
101     int            *emax[4][4];
102     int            *emin[4][4];
103     int            *peak;
104     int            filter;
105     int            flags;
106     int            bits;
107     int            max;
108     int            size;
109     int            scale;
110     uint8_t        grat_yuva_color[4];
111     int            shift_w[4], shift_h[4];
112     GraticuleLines *glines;
113     int            nb_glines;
114     int            rgb;
115
116     int (*waveform_slice)(AVFilterContext *ctx, void *arg,
117                           int jobnr, int nb_jobs);
118     void (*graticulef)(struct WaveformContext *s, AVFrame *out);
119     void (*blend_line)(uint8_t *dst, int size, int linesize, float o1, float o2,
120                        int v, int step);
121     void (*draw_text)(AVFrame *out, int x, int y, int mult,
122                       float o1, float o2, const char *txt,
123                       const uint8_t color[4]);
124     const AVPixFmtDescriptor *desc;
125     const AVPixFmtDescriptor *odesc;
126 } WaveformContext;
127
128 #define OFFSET(x) offsetof(WaveformContext, x)
129 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
130
131 static const AVOption waveform_options[] = {
132     { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
133     { "m",    "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
134         { "row",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
135         { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
136     { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
137     { "i",         "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
138     { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
139     { "r",      "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
140     { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
141     { "d",       "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
142         { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY}, 0, 0, FLAGS, "display" },
143         { "stack",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=STACK},   0, 0, FLAGS, "display" },
144         { "parade",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=PARADE},  0, 0, FLAGS, "display" },
145     { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
146     { "c",          "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
147     { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
148     { "e",        "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
149         { "none",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
150         { "instant",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
151         { "peak",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
152         { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
153     { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
154     { "f",      "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
155         { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, "filter" },
156         { "flat"   , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT},    0, 0, FLAGS, "filter" },
157         { "aflat"  , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT},   0, 0, FLAGS, "filter" },
158         { "chroma",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA},  0, 0, FLAGS, "filter" },
159         { "color",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR},   0, 0, FLAGS, "filter" },
160         { "acolor",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACOLOR},  0, 0, FLAGS, "filter" },
161         { "xflat",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=XFLAT},   0, 0, FLAGS, "filter" },
162         { "yflat",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=YFLAT},   0, 0, FLAGS, "filter" },
163     { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, "graticule" },
164     { "g",         "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, "graticule" },
165         { "none",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_NONE},   0, 0, FLAGS, "graticule" },
166         { "green",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_GREEN},  0, 0, FLAGS, "graticule" },
167         { "orange", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_ORANGE}, 0, 0, FLAGS, "graticule" },
168         { "invert", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_INVERT}, 0, 0, FLAGS, "graticule" },
169     { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
170     { "o",       "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
171     { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
172     { "fl",    "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
173         { "numbers",  "draw numbers", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "flags" },
174         { "dots",     "draw dots instead of lines", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
175     { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
176     { "s",     "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
177         { "digital",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=DIGITAL},    0, 0, FLAGS, "scale" },
178         { "millivolts", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MILLIVOLTS}, 0, 0, FLAGS, "scale" },
179         { "ire",        NULL, 0, AV_OPT_TYPE_CONST, {.i64=IRE},        0, 0, FLAGS, "scale" },
180     { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
181     { "b",         "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
182     { NULL }
183 };
184
185 AVFILTER_DEFINE_CLASS(waveform);
186
187 static const enum AVPixelFormat in_lowpass_pix_fmts[] = {
188     AV_PIX_FMT_GBRP,     AV_PIX_FMT_GBRAP,
189     AV_PIX_FMT_GBRP9,    AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
190     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
191     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
192     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
193     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
194     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
195     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
196     AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
197     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
198     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
199     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
200     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
201     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
202     AV_PIX_FMT_NONE
203 };
204
205 static const enum AVPixelFormat in_color_pix_fmts[] = {
206     AV_PIX_FMT_GBRP,     AV_PIX_FMT_GBRAP,
207     AV_PIX_FMT_GBRP9,    AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
208     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
209     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
210     AV_PIX_FMT_YUV411P,
211     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
212     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
213     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
214     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
215     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
216     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
217     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
218     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
219     AV_PIX_FMT_NONE
220 };
221
222 static const enum AVPixelFormat in_flat_pix_fmts[] = {
223     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
224     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
225     AV_PIX_FMT_YUV411P,
226     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
227     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
228     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
229     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
230     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
231     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
232     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
233     AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
234     AV_PIX_FMT_NONE
235 };
236
237 static const enum AVPixelFormat out_rgb8_lowpass_pix_fmts[] = {
238     AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
239     AV_PIX_FMT_NONE
240 };
241
242 static const enum AVPixelFormat out_rgb9_lowpass_pix_fmts[] = {
243     AV_PIX_FMT_GBRP9,
244     AV_PIX_FMT_NONE
245 };
246
247 static const enum AVPixelFormat out_rgb10_lowpass_pix_fmts[] = {
248     AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
249     AV_PIX_FMT_NONE
250 };
251
252 static const enum AVPixelFormat out_rgb12_lowpass_pix_fmts[] = {
253     AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
254     AV_PIX_FMT_NONE
255 };
256
257 static const enum AVPixelFormat out_yuv8_lowpass_pix_fmts[] = {
258     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P,
259     AV_PIX_FMT_NONE
260 };
261
262 static const enum AVPixelFormat out_yuv9_lowpass_pix_fmts[] = {
263     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9,
264     AV_PIX_FMT_NONE
265 };
266
267 static const enum AVPixelFormat out_yuv10_lowpass_pix_fmts[] = {
268     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
269     AV_PIX_FMT_NONE
270 };
271
272 static const enum AVPixelFormat out_yuv12_lowpass_pix_fmts[] = {
273     AV_PIX_FMT_YUV444P12,
274     AV_PIX_FMT_NONE
275 };
276
277 static const enum AVPixelFormat out_gray8_lowpass_pix_fmts[] = {
278     AV_PIX_FMT_GRAY8,
279     AV_PIX_FMT_NONE
280 };
281
282 static const enum AVPixelFormat out_gray9_lowpass_pix_fmts[] = {
283     AV_PIX_FMT_GRAY9,
284     AV_PIX_FMT_NONE
285 };
286
287 static const enum AVPixelFormat out_gray10_lowpass_pix_fmts[] = {
288     AV_PIX_FMT_GRAY10,
289     AV_PIX_FMT_NONE
290 };
291
292 static const enum AVPixelFormat out_gray12_lowpass_pix_fmts[] = {
293     AV_PIX_FMT_GRAY12,
294     AV_PIX_FMT_NONE
295 };
296
297 static const enum AVPixelFormat flat_pix_fmts[] = {
298     AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
299     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
300     AV_PIX_FMT_YUV444P12,
301     AV_PIX_FMT_NONE
302 };
303
304 static int query_formats(AVFilterContext *ctx)
305 {
306     WaveformContext *s = ctx->priv;
307     const enum AVPixelFormat *out_pix_fmts;
308     const enum AVPixelFormat *in_pix_fmts;
309     const AVPixFmtDescriptor *desc, *desc2;
310     AVFilterFormats *avff, *avff2;
311     int depth, depth2, rgb, i, ret, ncomp, ncomp2;
312
313     if (!ctx->inputs[0]->in_formats ||
314         !ctx->inputs[0]->in_formats->nb_formats) {
315         return AVERROR(EAGAIN);
316     }
317
318     switch (s->filter) {
319     case LOWPASS: in_pix_fmts = in_lowpass_pix_fmts; break;
320     case CHROMA:
321     case XFLAT:
322     case YFLAT:
323     case AFLAT:
324     case FLAT:    in_pix_fmts = in_flat_pix_fmts;    break;
325     case ACOLOR:
326     case COLOR:   in_pix_fmts = in_color_pix_fmts;   break;
327     default: return AVERROR_BUG;
328     }
329
330     if (!ctx->inputs[0]->out_formats) {
331         if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->out_formats)) < 0)
332             return ret;
333     }
334
335     avff = ctx->inputs[0]->in_formats;
336     avff2 = ctx->inputs[0]->out_formats;
337     desc = av_pix_fmt_desc_get(avff->formats[0]);
338     desc2 = av_pix_fmt_desc_get(avff2->formats[0]);
339     ncomp = desc->nb_components;
340     ncomp2 = desc2->nb_components;
341     rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
342     depth = desc->comp[0].depth;
343     depth2 = desc2->comp[0].depth;
344     if (ncomp != ncomp2 || depth != depth2)
345         return AVERROR(EAGAIN);
346     for (i = 1; i < avff->nb_formats; i++) {
347         desc = av_pix_fmt_desc_get(avff->formats[i]);
348         if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
349             depth != desc->comp[0].depth)
350             return AVERROR(EAGAIN);
351     }
352
353     if (s->filter == LOWPASS && ncomp == 1 && depth == 8)
354         out_pix_fmts = out_gray8_lowpass_pix_fmts;
355     else if (s->filter == LOWPASS && ncomp == 1 && depth == 9)
356         out_pix_fmts = out_gray9_lowpass_pix_fmts;
357     else if (s->filter == LOWPASS && ncomp == 1 && depth == 10)
358         out_pix_fmts = out_gray10_lowpass_pix_fmts;
359     else if (s->filter == LOWPASS && ncomp == 1 && depth == 12)
360         out_pix_fmts = out_gray12_lowpass_pix_fmts;
361     else if (rgb && depth == 8 && ncomp > 2)
362         out_pix_fmts = out_rgb8_lowpass_pix_fmts;
363     else if (rgb && depth == 9 && ncomp > 2)
364         out_pix_fmts = out_rgb9_lowpass_pix_fmts;
365     else if (rgb && depth == 10 && ncomp > 2)
366         out_pix_fmts = out_rgb10_lowpass_pix_fmts;
367     else if (rgb && depth == 12 && ncomp > 2)
368         out_pix_fmts = out_rgb12_lowpass_pix_fmts;
369     else if (depth == 8 && ncomp > 2)
370         out_pix_fmts = out_yuv8_lowpass_pix_fmts;
371     else if (depth == 9 && ncomp > 2)
372         out_pix_fmts = out_yuv9_lowpass_pix_fmts;
373     else if (depth == 10 && ncomp > 2)
374         out_pix_fmts = out_yuv10_lowpass_pix_fmts;
375     else if (depth == 12 && ncomp > 2)
376         out_pix_fmts = out_yuv12_lowpass_pix_fmts;
377     else
378         return AVERROR(EAGAIN);
379     if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats)) < 0)
380         return ret;
381
382     return 0;
383 }
384
385 static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
386 {
387     const int dst_linesize = out->linesize[component] / 2;
388     const int bg = s->bg_color[component] * (s->max / 256);
389     const int limit = s->max - 1;
390     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
391     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
392     const int start = s->estart[plane];
393     const int end = s->eend[plane];
394     uint16_t *dst;
395     int x, y;
396
397     if (s->mode) {
398         for (x = offset; x < offset + dst_w; x++) {
399             for (y = start; y < end; y++) {
400                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
401                 if (dst[0] != bg) {
402                     dst[0] = limit;
403                     break;
404                 }
405             }
406             for (y = end - 1; y >= start; y--) {
407                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
408                 if (dst[0] != bg) {
409                     dst[0] = limit;
410                     break;
411                 }
412             }
413         }
414     } else {
415         for (y = offset; y < offset + dst_h; y++) {
416             dst = (uint16_t *)out->data[component] + y * dst_linesize;
417             for (x = start; x < end; x++) {
418                 if (dst[x] != bg) {
419                     dst[x] = limit;
420                     break;
421                 }
422             }
423             for (x = end - 1; x >= start; x--) {
424                 if (dst[x] != bg) {
425                     dst[x] = limit;
426                     break;
427                 }
428             }
429         }
430     }
431 }
432
433 static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
434 {
435     const int dst_linesize = out->linesize[component];
436     const uint8_t bg = s->bg_color[component];
437     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
438     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
439     const int start = s->estart[plane];
440     const int end = s->eend[plane];
441     uint8_t *dst;
442     int x, y;
443
444     if (s->mode) {
445         for (x = offset; x < offset + dst_w; x++) {
446             for (y = start; y < end; y++) {
447                 dst = out->data[component] + y * dst_linesize + x;
448                 if (dst[0] != bg) {
449                     dst[0] = 255;
450                     break;
451                 }
452             }
453             for (y = end - 1; y >= start; y--) {
454                 dst = out->data[component] + y * dst_linesize + x;
455                 if (dst[0] != bg) {
456                     dst[0] = 255;
457                     break;
458                 }
459             }
460         }
461     } else {
462         for (y = offset; y < offset + dst_h; y++) {
463             dst = out->data[component] + y * dst_linesize;
464             for (x = start; x < end; x++) {
465                 if (dst[x] != bg) {
466                     dst[x] = 255;
467                     break;
468                 }
469             }
470             for (x = end - 1; x >= start; x--) {
471                 if (dst[x] != bg) {
472                     dst[x] = 255;
473                     break;
474                 }
475             }
476         }
477     }
478 }
479
480 static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
481 {
482     const int dst_linesize = out->linesize[component] / 2;
483     const int bg = s->bg_color[component] * (s->max / 256);
484     const int limit = s->max - 1;
485     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
486     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
487     const int start = s->estart[plane];
488     const int end = s->eend[plane];
489     int *emax = s->emax[plane][component];
490     int *emin = s->emin[plane][component];
491     uint16_t *dst;
492     int x, y;
493
494     if (s->mode) {
495         for (x = offset; x < offset + dst_w; x++) {
496             for (y = start; y < end && y < emin[x - offset]; y++) {
497                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
498                 if (dst[0] != bg) {
499                     emin[x - offset] = y;
500                     break;
501                 }
502             }
503             for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
504                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
505                 if (dst[0] != bg) {
506                     emax[x - offset] = y;
507                     break;
508                 }
509             }
510         }
511
512         if (s->envelope == 3)
513             envelope_instant16(s, out, plane, component, offset);
514
515         for (x = offset; x < offset + dst_w; x++) {
516             dst = (uint16_t *)out->data[component] + emin[x - offset] * dst_linesize + x;
517             dst[0] = limit;
518             dst = (uint16_t *)out->data[component] + emax[x - offset] * dst_linesize + x;
519             dst[0] = limit;
520         }
521     } else {
522         for (y = offset; y < offset + dst_h; y++) {
523             dst = (uint16_t *)out->data[component] + y * dst_linesize;
524             for (x = start; x < end && x < emin[y - offset]; x++) {
525                 if (dst[x] != bg) {
526                     emin[y - offset] = x;
527                     break;
528                 }
529             }
530             for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
531                 if (dst[x] != bg) {
532                     emax[y - offset] = x;
533                     break;
534                 }
535             }
536         }
537
538         if (s->envelope == 3)
539             envelope_instant16(s, out, plane, component, offset);
540
541         for (y = offset; y < offset + dst_h; y++) {
542             dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y - offset];
543             dst[0] = limit;
544             dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y - offset];
545             dst[0] = limit;
546         }
547     }
548 }
549
550 static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
551 {
552     const int dst_linesize = out->linesize[component];
553     const int bg = s->bg_color[component];
554     const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
555     const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
556     const int start = s->estart[plane];
557     const int end = s->eend[plane];
558     int *emax = s->emax[plane][component];
559     int *emin = s->emin[plane][component];
560     uint8_t *dst;
561     int x, y;
562
563     if (s->mode) {
564         for (x = offset; x < offset + dst_w; x++) {
565             for (y = start; y < end && y < emin[x - offset]; y++) {
566                 dst = out->data[component] + y * dst_linesize + x;
567                 if (dst[0] != bg) {
568                     emin[x - offset] = y;
569                     break;
570                 }
571             }
572             for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
573                 dst = out->data[component] + y * dst_linesize + x;
574                 if (dst[0] != bg) {
575                     emax[x - offset] = y;
576                     break;
577                 }
578             }
579         }
580
581         if (s->envelope == 3)
582             envelope_instant(s, out, plane, component, offset);
583
584         for (x = offset; x < offset + dst_w; x++) {
585             dst = out->data[component] + emin[x - offset] * dst_linesize + x;
586             dst[0] = 255;
587             dst = out->data[component] + emax[x - offset] * dst_linesize + x;
588             dst[0] = 255;
589         }
590     } else {
591         for (y = offset; y < offset + dst_h; y++) {
592             dst = out->data[component] + y * dst_linesize;
593             for (x = start; x < end && x < emin[y - offset]; x++) {
594                 if (dst[x] != bg) {
595                     emin[y - offset] = x;
596                     break;
597                 }
598             }
599             for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
600                 if (dst[x] != bg) {
601                     emax[y - offset] = x;
602                     break;
603                 }
604             }
605         }
606
607         if (s->envelope == 3)
608             envelope_instant(s, out, plane, component, offset);
609
610         for (y = offset; y < offset + dst_h; y++) {
611             dst = out->data[component] + y * dst_linesize + emin[y - offset];
612             dst[0] = 255;
613             dst = out->data[component] + y * dst_linesize + emax[y - offset];
614             dst[0] = 255;
615         }
616     }
617 }
618
619 static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
620 {
621     if (s->envelope == 0) {
622         return;
623     } else if (s->envelope == 1) {
624         envelope_instant16(s, out, plane, component, offset);
625     } else {
626         envelope_peak16(s, out, plane, component, offset);
627     }
628 }
629
630 static void envelope(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
631 {
632     if (s->envelope == 0) {
633         return;
634     } else if (s->envelope == 1) {
635         envelope_instant(s, out, plane, component, offset);
636     } else {
637         envelope_peak(s, out, plane, component, offset);
638     }
639 }
640
641 static void update16(uint16_t *target, int max, int intensity, int limit)
642 {
643     if (*target <= max)
644         *target += intensity;
645     else
646         *target = limit;
647 }
648
649 static void update(uint8_t *target, int max, int intensity)
650 {
651     if (*target <= max)
652         *target += intensity;
653     else
654         *target = 255;
655 }
656
657 static void update_cr(uint8_t *target, int unused, int intensity)
658 {
659     if (*target - intensity > 0)
660         *target -= intensity;
661     else
662         *target = 0;
663 }
664
665 static void update16_cr(uint16_t *target, int unused, int intensity, int limit)
666 {
667     if (*target - intensity > 0)
668         *target -= intensity;
669     else
670         *target = 0;
671 }
672
673 static av_always_inline void lowpass16(WaveformContext *s,
674                                        AVFrame *in, AVFrame *out,
675                                        int component, int intensity,
676                                        int offset_y, int offset_x,
677                                        int column, int mirror,
678                                        int jobnr, int nb_jobs)
679 {
680     const int plane = s->desc->comp[component].plane;
681     const int shift_w = s->shift_w[component];
682     const int shift_h = s->shift_h[component];
683     const int src_linesize = in->linesize[plane] / 2;
684     const int dst_linesize = out->linesize[plane] / 2;
685     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
686     const int limit = s->max - 1;
687     const int max = limit - intensity;
688     const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
689     const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
690     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
691     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
692     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
693     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
694     const int step = column ? 1 << shift_w : 1 << shift_h;
695     const uint16_t *src_data = (const uint16_t *)in->data[plane] + sliceh_start * src_linesize;
696     uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
697     uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
698     uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
699     const uint16_t *p;
700     int y;
701
702     if (!column && mirror)
703         dst_data += s->size;
704
705     for (y = sliceh_start; y < sliceh_end; y++) {
706         const uint16_t *src_data_end = src_data + slicew_end;
707         uint16_t *dst = dst_line + slicew_start * step;
708
709         for (p = src_data + slicew_start; p < src_data_end; p++) {
710             uint16_t *target;
711             int i = 0, v = FFMIN(*p, limit);
712
713             if (column) {
714                 do {
715                     target = dst++ + dst_signed_linesize * v;
716                     update16(target, max, intensity, limit);
717                 } while (++i < step);
718             } else {
719                 uint16_t *row = dst_data;
720                 do {
721                     if (mirror)
722                         target = row - v - 1;
723                     else
724                         target = row + v;
725                     update16(target, max, intensity, limit);
726                     row += dst_linesize;
727                 } while (++i < step);
728             }
729         }
730         src_data += src_linesize;
731         dst_data += dst_linesize * step;
732     }
733 }
734
735 #define LOWPASS16_FUNC(name, column, mirror)        \
736 static int lowpass16_##name(AVFilterContext *ctx,   \
737                              void *arg, int jobnr,  \
738                              int nb_jobs)           \
739 {                                                   \
740     WaveformContext *s = ctx->priv;                 \
741     ThreadData *td = arg;                           \
742     AVFrame *in = td->in;                           \
743     AVFrame *out = td->out;                         \
744     int component = td->component;                  \
745     int offset_y = td->offset_y;                    \
746     int offset_x = td->offset_x;                    \
747                                                     \
748     lowpass16(s, in, out, component, s->intensity,  \
749               offset_y, offset_x, column, mirror,   \
750               jobnr, nb_jobs);                      \
751                                                     \
752     return 0;                                       \
753 }
754
755 LOWPASS16_FUNC(column_mirror, 1, 1)
756 LOWPASS16_FUNC(column,        1, 0)
757 LOWPASS16_FUNC(row_mirror,    0, 1)
758 LOWPASS16_FUNC(row,           0, 0)
759
760 static av_always_inline void lowpass(WaveformContext *s,
761                                      AVFrame *in, AVFrame *out,
762                                      int component, int intensity,
763                                      int offset_y, int offset_x,
764                                      int column, int mirror,
765                                      int jobnr, int nb_jobs)
766 {
767     const int plane = s->desc->comp[component].plane;
768     const int shift_w = s->shift_w[component];
769     const int shift_h = s->shift_h[component];
770     const int src_linesize = in->linesize[plane];
771     const int dst_linesize = out->linesize[plane];
772     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
773     const int max = 255 - intensity;
774     const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
775     const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
776     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
777     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
778     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
779     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
780     const int step = column ? 1 << shift_w : 1 << shift_h;
781     const uint8_t *src_data = in->data[plane] + sliceh_start * src_linesize;
782     uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
783     uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
784     uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
785     const uint8_t *p;
786     int y;
787
788     if (!column && mirror)
789         dst_data += s->size;
790
791     for (y = sliceh_start; y < sliceh_end; y++) {
792         const uint8_t *src_data_end = src_data + slicew_end;
793         uint8_t *dst = dst_line + slicew_start * step;
794
795         for (p = src_data + slicew_start; p < src_data_end; p++) {
796             uint8_t *target;
797             if (column) {
798                 target = dst + dst_signed_linesize * *p;
799                 dst += step;
800                 update(target, max, intensity);
801             } else {
802                 uint8_t *row = dst_data;
803                 if (mirror)
804                     target = row - *p - 1;
805                 else
806                     target = row + *p;
807                 update(target, max, intensity);
808                 row += dst_linesize;
809             }
810         }
811         src_data += src_linesize;
812         dst_data += dst_linesize * step;
813     }
814
815     if (column && step > 1) {
816         const int dst_h = 256;
817         uint8_t *dst;
818         int x, z;
819
820         dst = out->data[plane] + offset_y * dst_linesize + offset_x;
821         for (y = 0; y < dst_h; y++) {
822             for (x = slicew_start * step; x < slicew_end * step; x+=step) {
823                 for (z = 1; z < step; z++) {
824                     dst[x + z] = dst[x];
825                 }
826             }
827             dst += dst_linesize;
828         }
829     } else if (step > 1) {
830         const int dst_w = 256;
831         uint8_t *dst;
832         int z;
833
834         dst = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
835         for (y = sliceh_start * step; y < sliceh_end * step; y+=step) {
836             for (z = 1; z < step; z++)
837                 memcpy(dst + dst_linesize * z, dst, dst_w);
838             dst += dst_linesize * step;
839         }
840     }
841 }
842
843 #define LOWPASS_FUNC(name, column, mirror)        \
844 static int lowpass_##name(AVFilterContext *ctx,   \
845                           void *arg, int jobnr,   \
846                           int nb_jobs)            \
847 {                                                 \
848     WaveformContext *s = ctx->priv;               \
849     ThreadData *td = arg;                         \
850     AVFrame *in = td->in;                         \
851     AVFrame *out = td->out;                       \
852     int component = td->component;                \
853     int offset_y = td->offset_y;                  \
854     int offset_x = td->offset_x;                  \
855                                                   \
856     lowpass(s, in, out, component, s->intensity,  \
857             offset_y, offset_x, column, mirror,   \
858             jobnr, nb_jobs);                      \
859                                                   \
860     return 0;                                     \
861 }
862
863 LOWPASS_FUNC(column_mirror, 1, 1)
864 LOWPASS_FUNC(column,        1, 0)
865 LOWPASS_FUNC(row_mirror,    0, 1)
866 LOWPASS_FUNC(row,           0, 0)
867
868 static av_always_inline void flat16(WaveformContext *s,
869                                     AVFrame *in, AVFrame *out,
870                                     int component, int intensity,
871                                     int offset_y, int offset_x,
872                                     int column, int mirror,
873                                     int jobnr, int nb_jobs)
874 {
875     const int plane = s->desc->comp[component].plane;
876     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
877     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
878     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
879     const int c0_shift_w = s->shift_w[ component + 0 ];
880     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
881     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
882     const int c0_shift_h = s->shift_h[ component + 0 ];
883     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
884     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
885     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
886     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
887     const int limit = s->max - 1;
888     const int max = limit - intensity;
889     const int mid = s->max / 2;
890     const int src_h = in->height;
891     const int src_w = in->width;
892     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
893     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
894     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
895     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
896     int x, y;
897
898     if (column) {
899         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
900         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
901
902         for (x = slicew_start; x < slicew_end; x++) {
903             const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];
904             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
905             const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
906             uint16_t *d0_data = (uint16_t *)(out->data[plane]) + offset_y * d0_linesize + offset_x;
907             uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + offset_y * d1_linesize + offset_x;
908             uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
909             uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
910             uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
911             uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
912
913             for (y = 0; y < src_h; y++) {
914                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
915                 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
916                 uint16_t *target;
917
918                 target = d0 + x + d0_signed_linesize * c0;
919                 update16(target, max, intensity, limit);
920                 target = d1 + x + d1_signed_linesize * (c0 - c1);
921                 update16(target, max, intensity, limit);
922                 target = d1 + x + d1_signed_linesize * (c0 + c1);
923                 update16(target, max, intensity, limit);
924
925                 if (!c0_shift_h || (y & c0_shift_h))
926                     c0_data += c0_linesize;
927                 if (!c1_shift_h || (y & c1_shift_h))
928                     c1_data += c1_linesize;
929                 if (!c2_shift_h || (y & c2_shift_h))
930                     c2_data += c2_linesize;
931                 d0_data += d0_linesize;
932                 d1_data += d1_linesize;
933             }
934         }
935     } else {
936         const uint16_t *c0_data = (uint16_t *)(in->data[plane]) +                  (sliceh_start >> c0_shift_h) * c0_linesize;
937         const uint16_t *c1_data = (uint16_t *)(in->data[(plane + 1) % s->ncomp]) + (sliceh_start >> c1_shift_h) * c1_linesize;
938         const uint16_t *c2_data = (uint16_t *)(in->data[(plane + 2) % s->ncomp]) + (sliceh_start >> c2_shift_h) * c2_linesize;
939         uint16_t *d0_data = (uint16_t *)(out->data[plane]) + (offset_y + sliceh_start) * d0_linesize + offset_x;
940         uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + (offset_y + sliceh_start) * d1_linesize + offset_x;
941
942         if (mirror) {
943             d0_data += s->size - 1;
944             d1_data += s->size - 1;
945         }
946
947         for (y = sliceh_start; y < sliceh_end; y++) {
948             for (x = 0; x < src_w; x++) {
949                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
950                 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
951                 uint16_t *target;
952
953                 if (mirror) {
954                     target = d0_data - c0;
955                     update16(target, max, intensity, limit);
956                     target = d1_data - (c0 - c1);
957                     update16(target, max, intensity, limit);
958                     target = d1_data - (c0 + c1);
959                     update16(target, max, intensity, limit);
960                 } else {
961                     target = d0_data + c0;
962                     update16(target, max, intensity, limit);
963                     target = d1_data + (c0 - c1);
964                     update16(target, max, intensity, limit);
965                     target = d1_data + (c0 + c1);
966                     update16(target, max, intensity, limit);
967                 }
968             }
969
970             if (!c0_shift_h || (y & c0_shift_h))
971                 c0_data += c0_linesize;
972             if (!c1_shift_h || (y & c1_shift_h))
973                 c1_data += c1_linesize;
974             if (!c2_shift_h || (y & c2_shift_h))
975                 c2_data += c2_linesize;
976             d0_data += d0_linesize;
977             d1_data += d1_linesize;
978         }
979     }
980 }
981
982 #define FLAT16_FUNC(name, column, mirror)        \
983 static int flat16_##name(AVFilterContext *ctx,   \
984                          void *arg, int jobnr,   \
985                          int nb_jobs)            \
986 {                                                \
987     WaveformContext *s = ctx->priv;              \
988     ThreadData *td = arg;                        \
989     AVFrame *in = td->in;                        \
990     AVFrame *out = td->out;                      \
991     int component = td->component;               \
992     int offset_y = td->offset_y;                 \
993     int offset_x = td->offset_x;                 \
994                                                  \
995     flat16(s, in, out, component, s->intensity,  \
996            offset_y, offset_x, column, mirror,   \
997            jobnr, nb_jobs);                      \
998                                                  \
999     return 0;                                    \
1000 }
1001
1002 FLAT16_FUNC(column_mirror, 1, 1)
1003 FLAT16_FUNC(column,        1, 0)
1004 FLAT16_FUNC(row_mirror,    0, 1)
1005 FLAT16_FUNC(row,           0, 0)
1006
1007 static av_always_inline void flat(WaveformContext *s,
1008                                   AVFrame *in, AVFrame *out,
1009                                   int component, int intensity,
1010                                   int offset_y, int offset_x,
1011                                   int column, int mirror,
1012                                   int jobnr, int nb_jobs)
1013 {
1014     const int plane = s->desc->comp[component].plane;
1015     const int c0_linesize = in->linesize[ plane + 0 ];
1016     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1017     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1018     const int c0_shift_w = s->shift_w[ component + 0 ];
1019     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1020     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1021     const int c0_shift_h = s->shift_h[ component + 0 ];
1022     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1023     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1024     const int d0_linesize = out->linesize[ plane + 0 ];
1025     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1026     const int max = 255 - intensity;
1027     const int src_h = in->height;
1028     const int src_w = in->width;
1029     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1030     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1031     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1032     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1033     int x, y;
1034
1035     if (column) {
1036         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1037         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1038
1039         for (x = slicew_start; x < slicew_end; x++) {
1040             const uint8_t *c0_data = in->data[plane + 0];
1041             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
1042             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
1043             uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1044             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1045             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1046             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1047             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1048             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1049
1050             for (y = 0; y < src_h; y++) {
1051                 const int c0 = c0_data[x >> c0_shift_w] + 256;
1052                 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1053                 uint8_t *target;
1054
1055                 target = d0 + x + d0_signed_linesize * c0;
1056                 update(target, max, intensity);
1057                 target = d1 + x + d1_signed_linesize * (c0 - c1);
1058                 update(target, max, intensity);
1059                 target = d1 + x + d1_signed_linesize * (c0 + c1);
1060                 update(target, max, intensity);
1061
1062                 if (!c0_shift_h || (y & c0_shift_h))
1063                     c0_data += c0_linesize;
1064                 if (!c1_shift_h || (y & c1_shift_h))
1065                     c1_data += c1_linesize;
1066                 if (!c2_shift_h || (y & c2_shift_h))
1067                     c2_data += c2_linesize;
1068                 d0_data += d0_linesize;
1069                 d1_data += d1_linesize;
1070             }
1071         }
1072     } else {
1073         const uint8_t *c0_data = in->data[plane] +                  (sliceh_start >> c0_shift_h) * c0_linesize;
1074         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1075         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1076         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1077         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1078
1079         if (mirror) {
1080             d0_data += s->size - 1;
1081             d1_data += s->size - 1;
1082         }
1083
1084         for (y = sliceh_start; y < sliceh_end; y++) {
1085             for (x = 0; x < src_w; x++) {
1086                 const int c0 = c0_data[x >> c0_shift_w] + 256;
1087                 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1088                 uint8_t *target;
1089
1090                 if (mirror) {
1091                     target = d0_data - c0;
1092                     update(target, max, intensity);
1093                     target = d1_data - (c0 - c1);
1094                     update(target, max, intensity);
1095                     target = d1_data - (c0 + c1);
1096                     update(target, max, intensity);
1097                 } else {
1098                     target = d0_data + c0;
1099                     update(target, max, intensity);
1100                     target = d1_data + (c0 - c1);
1101                     update(target, max, intensity);
1102                     target = d1_data + (c0 + c1);
1103                     update(target, max, intensity);
1104                 }
1105             }
1106
1107             if (!c0_shift_h || (y & c0_shift_h))
1108                 c0_data += c0_linesize;
1109             if (!c1_shift_h || (y & c1_shift_h))
1110                 c1_data += c1_linesize;
1111             if (!c2_shift_h || (y & c2_shift_h))
1112                 c2_data += c2_linesize;
1113             d0_data += d0_linesize;
1114             d1_data += d1_linesize;
1115         }
1116     }
1117 }
1118
1119 #define FLAT_FUNC(name, column, mirror)        \
1120 static int flat_##name(AVFilterContext *ctx,   \
1121                        void *arg, int jobnr,   \
1122                        int nb_jobs)            \
1123 {                                              \
1124     WaveformContext *s = ctx->priv;            \
1125     ThreadData *td = arg;                      \
1126     AVFrame *in = td->in;                      \
1127     AVFrame *out = td->out;                    \
1128     int component = td->component;             \
1129     int offset_y = td->offset_y;               \
1130     int offset_x = td->offset_x;               \
1131                                                \
1132     flat(s, in, out, component, s->intensity,  \
1133          offset_y, offset_x, column, mirror,   \
1134          jobnr, nb_jobs);                      \
1135                                                \
1136     return 0;                                  \
1137 }
1138
1139 FLAT_FUNC(column_mirror, 1, 1)
1140 FLAT_FUNC(column,        1, 0)
1141 FLAT_FUNC(row_mirror,    0, 1)
1142 FLAT_FUNC(row,           0, 0)
1143
1144 #define AFLAT16(name, update_cb, update_cr, column, mirror)                                                        \
1145 static int name(AVFilterContext *ctx,                                                                              \
1146                 void *arg, int jobnr,                                                                              \
1147                 int nb_jobs)                                                                                       \
1148 {                                                                                                                  \
1149     WaveformContext *s = ctx->priv;                                                                                \
1150     ThreadData *td = arg;                                                                                          \
1151     AVFrame *in = td->in;                                                                                          \
1152     AVFrame *out = td->out;                                                                                        \
1153     int component = td->component;                                                                                 \
1154     int offset_y = td->offset_y;                                                                                   \
1155     int offset_x = td->offset_x;                                                                                   \
1156     const int intensity = s->intensity;                                                                            \
1157     const int plane = s->desc->comp[component].plane;                                                              \
1158     const int c0_linesize = in->linesize[ plane + 0 ] / 2;                                                         \
1159     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;                                              \
1160     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;                                              \
1161     const int c0_shift_w = s->shift_w[ component + 0 ];                                                            \
1162     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];                                                 \
1163     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];                                                 \
1164     const int c0_shift_h = s->shift_h[ component + 0 ];                                                            \
1165     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];                                                 \
1166     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];                                                 \
1167     const int d0_linesize = out->linesize[ plane + 0 ] / 2;                                                        \
1168     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;                                             \
1169     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;                                             \
1170     const int limit = s->max - 1;                                                                                  \
1171     const int max = limit - intensity;                                                                             \
1172     const int mid = s->max / 2;                                                                                    \
1173     const int src_h = in->height;                                                                                  \
1174     const int src_w = in->width;                                                                                   \
1175     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;                                              \
1176     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;                                        \
1177     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;                                               \
1178     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;                                         \
1179     int x, y;                                                                                                      \
1180                                                                                                                    \
1181     if (column) {                                                                                                  \
1182         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);                                       \
1183         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);                                       \
1184         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);                                       \
1185                                                                                                                    \
1186         for (x = slicew_start; x < slicew_end; x++) {                                                              \
1187             const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];                                             \
1188             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];                                \
1189             const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];                                \
1190             uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;                  \
1191             uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1192             uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1193             uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);                               \
1194             uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);                                             \
1195             uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);                               \
1196             uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);                                             \
1197             uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);                               \
1198             uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);                                             \
1199                                                                                                                    \
1200             for (y = 0; y < src_h; y++) {                                                                          \
1201                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid;                                       \
1202                 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid;                                       \
1203                 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid;                                       \
1204                 uint16_t *target;                                                                                  \
1205                                                                                                                    \
1206                 target = d0 + x + d0_signed_linesize * c0;                                                         \
1207                 update16(target, max, intensity, limit);                                                           \
1208                                                                                                                    \
1209                 target = d1 + x + d1_signed_linesize * (c0 + c1);                                                  \
1210                 update_cb(target, max, intensity, limit);                                                          \
1211                                                                                                                    \
1212                 target = d2 + x + d2_signed_linesize * (c0 + c2);                                                  \
1213                 update_cr(target, max, intensity, limit);                                                          \
1214                                                                                                                    \
1215                 if (!c0_shift_h || (y & c0_shift_h))                                                               \
1216                     c0_data += c0_linesize;                                                                        \
1217                 if (!c1_shift_h || (y & c1_shift_h))                                                               \
1218                     c1_data += c1_linesize;                                                                        \
1219                 if (!c2_shift_h || (y & c2_shift_h))                                                               \
1220                     c2_data += c2_linesize;                                                                        \
1221                 d0_data += d0_linesize;                                                                            \
1222                 d1_data += d1_linesize;                                                                            \
1223                 d2_data += d2_linesize;                                                                            \
1224             }                                                                                                      \
1225         }                                                                                                          \
1226     } else {                                                                                                       \
1227         const uint16_t *c0_data = (uint16_t *)in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;        \
1228         const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1229         const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1230         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;                      \
1231         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;     \
1232         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;     \
1233                                                                                                                    \
1234         if (mirror) {                                                                                              \
1235             d0_data += s->size - 1;                                                                                \
1236             d1_data += s->size - 1;                                                                                \
1237             d2_data += s->size - 1;                                                                                \
1238         }                                                                                                          \
1239                                                                                                                    \
1240         for (y = sliceh_start; y < sliceh_end; y++) {                                                              \
1241             for (x = 0; x < src_w; x++) {                                                                          \
1242                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid;                                       \
1243                 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid;                                       \
1244                 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid;                                       \
1245                 uint16_t *target;                                                                                  \
1246                                                                                                                    \
1247                 if (mirror) {                                                                                      \
1248                     target = d0_data - c0;                                                                         \
1249                     update16(target, max, intensity, limit);                                                       \
1250                     target = d1_data - (c0 + c1);                                                                  \
1251                     update_cb(target, max, intensity, limit);                                                      \
1252                     target = d2_data - (c0 + c2);                                                                  \
1253                     update_cr(target, max, intensity, limit);                                                      \
1254                 } else {                                                                                           \
1255                     target = d0_data + c0;                                                                         \
1256                     update16(target, max, intensity, limit);                                                       \
1257                     target = d1_data + (c0 + c1);                                                                  \
1258                     update_cb(target, max, intensity, limit);                                                      \
1259                     target = d2_data + (c0 + c2);                                                                  \
1260                     update_cr(target, max, intensity, limit);                                                      \
1261                 }                                                                                                  \
1262             }                                                                                                      \
1263                                                                                                                    \
1264             if (!c0_shift_h || (y & c0_shift_h))                                                                   \
1265                 c0_data += c0_linesize;                                                                            \
1266             if (!c1_shift_h || (y & c1_shift_h))                                                                   \
1267                 c1_data += c1_linesize;                                                                            \
1268             if (!c2_shift_h || (y & c2_shift_h))                                                                   \
1269                 c2_data += c2_linesize;                                                                            \
1270             d0_data += d0_linesize;                                                                                \
1271             d1_data += d1_linesize;                                                                                \
1272             d2_data += d2_linesize;                                                                                \
1273         }                                                                                                          \
1274     }                                                                                                              \
1275     return 0;                                                                                                      \
1276 }
1277
1278 #define AFLAT(name, update_cb, update_cr, column, mirror)                                             \
1279 static int name(AVFilterContext *ctx,                                                                 \
1280                 void *arg, int jobnr,                                                                 \
1281                 int nb_jobs)                                                                          \
1282 {                                                                                                     \
1283     WaveformContext *s = ctx->priv;                                                                   \
1284     ThreadData *td = arg;                                                                             \
1285     AVFrame *in = td->in;                                                                             \
1286     AVFrame *out = td->out;                                                                           \
1287     int component = td->component;                                                                    \
1288     int offset_y = td->offset_y;                                                                      \
1289     int offset_x = td->offset_x;                                                                      \
1290     const int src_h = in->height;                                                                     \
1291     const int src_w = in->width;                                                                      \
1292     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;                                 \
1293     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;                           \
1294     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;                                  \
1295     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;                            \
1296     const int intensity = s->intensity;                                                               \
1297     const int plane = s->desc->comp[component].plane;                                                 \
1298     const int c0_linesize = in->linesize[ plane + 0 ];                                                \
1299     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];                                     \
1300     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];                                     \
1301     const int c0_shift_w = s->shift_w[ component + 0 ];                                               \
1302     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];                                    \
1303     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];                                    \
1304     const int c0_shift_h = s->shift_h[ component + 0 ];                                               \
1305     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];                                    \
1306     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];                                    \
1307     const int d0_linesize = out->linesize[ plane + 0 ];                                               \
1308     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];                                    \
1309     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];                                    \
1310     const int max = 255 - intensity;                                                                  \
1311     int x, y;                                                                                         \
1312                                                                                                       \
1313     if (column) {                                                                                     \
1314         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);                          \
1315         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);                          \
1316         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);                          \
1317                                                                                                       \
1318         for (x = slicew_start; x < slicew_end; x++) {                                                 \
1319             const uint8_t *c0_data = in->data[plane + 0];                                             \
1320             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];                                \
1321             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];                                \
1322             uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;                  \
1323             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1324             uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1325             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);                   \
1326             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);                                 \
1327             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);                   \
1328             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);                                 \
1329             uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);                   \
1330             uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);                                 \
1331                                                                                                       \
1332             for (y = 0; y < src_h; y++) {                                                             \
1333                 const int c0 = c0_data[x >> c0_shift_w] + 128;                                        \
1334                 const int c1 = c1_data[x >> c1_shift_w] - 128;                                        \
1335                 const int c2 = c2_data[x >> c2_shift_w] - 128;                                        \
1336                 uint8_t *target;                                                                      \
1337                                                                                                       \
1338                 target = d0 + x + d0_signed_linesize * c0;                                            \
1339                 update(target, max, intensity);                                                       \
1340                                                                                                       \
1341                 target = d1 + x + d1_signed_linesize * (c0 + c1);                                     \
1342                 update_cb(target, max, intensity);                                                    \
1343                                                                                                       \
1344                 target = d2 + x + d2_signed_linesize * (c0 + c2);                                     \
1345                 update_cr(target, max, intensity);                                                    \
1346                                                                                                       \
1347                 if (!c0_shift_h || (y & c0_shift_h))                                                  \
1348                     c0_data += c0_linesize;                                                           \
1349                 if (!c1_shift_h || (y & c1_shift_h))                                                  \
1350                     c1_data += c1_linesize;                                                           \
1351                 if (!c2_shift_h || (y & c2_shift_h))                                                  \
1352                     c2_data += c2_linesize;                                                           \
1353                 d0_data += d0_linesize;                                                               \
1354                 d1_data += d1_linesize;                                                               \
1355                 d2_data += d2_linesize;                                                               \
1356             }                                                                                         \
1357         }                                                                                             \
1358     } else {                                                                                          \
1359         const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;        \
1360         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1361         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1362         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;     \
1363         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
1364         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
1365                                                                                                       \
1366         if (mirror) {                                                                                 \
1367             d0_data += s->size - 1;                                                                   \
1368             d1_data += s->size - 1;                                                                   \
1369             d2_data += s->size - 1;                                                                   \
1370         }                                                                                             \
1371                                                                                                       \
1372         for (y = sliceh_start; y < sliceh_end; y++) {                                                 \
1373             for (x = 0; x < src_w; x++) {                                                             \
1374                 const int c0 = c0_data[x >> c0_shift_w] + 128;                                        \
1375                 const int c1 = c1_data[x >> c1_shift_w] - 128;                                        \
1376                 const int c2 = c2_data[x >> c2_shift_w] - 128;                                        \
1377                 uint8_t *target;                                                                      \
1378                                                                                                       \
1379                 if (mirror) {                                                                         \
1380                     target = d0_data - c0;                                                            \
1381                     update(target, max, intensity);                                                   \
1382                     target = d1_data - (c0 + c1);                                                     \
1383                     update_cb(target, max, intensity);                                                \
1384                     target = d2_data - (c0 + c2);                                                     \
1385                     update_cr(target, max, intensity);                                                \
1386                 } else {                                                                              \
1387                     target = d0_data + c0;                                                            \
1388                     update(target, max, intensity);                                                   \
1389                     target = d1_data + (c0 + c1);                                                     \
1390                     update_cb(target, max, intensity);                                                \
1391                     target = d2_data + (c0 + c2);                                                     \
1392                     update_cr(target, max, intensity);                                                \
1393                 }                                                                                     \
1394             }                                                                                         \
1395                                                                                                       \
1396             if (!c0_shift_h || (y & c0_shift_h))                                                      \
1397                 c0_data += c0_linesize;                                                               \
1398             if (!c1_shift_h || (y & c1_shift_h))                                                      \
1399                 c1_data += c1_linesize;                                                               \
1400             if (!c2_shift_h || (y & c2_shift_h))                                                      \
1401                 c2_data += c2_linesize;                                                               \
1402             d0_data += d0_linesize;                                                                   \
1403             d1_data += d1_linesize;                                                                   \
1404             d2_data += d2_linesize;                                                                   \
1405         }                                                                                             \
1406     }                                                                                                 \
1407     return 0;                                                                                         \
1408 }
1409
1410 AFLAT16(aflat16_row,           update16, update16,    0, 0)
1411 AFLAT16(aflat16_row_mirror,    update16, update16,    0, 1)
1412 AFLAT16(aflat16_column,        update16, update16,    1, 0)
1413 AFLAT16(aflat16_column_mirror, update16, update16,    1, 1)
1414 AFLAT16(xflat16_row,           update16, update16_cr, 0, 0)
1415 AFLAT16(xflat16_row_mirror,    update16, update16_cr, 0, 1)
1416 AFLAT16(xflat16_column,        update16, update16_cr, 1, 0)
1417 AFLAT16(xflat16_column_mirror, update16, update16_cr, 1, 1)
1418 AFLAT16(yflat16_row,           update16_cr, update16_cr, 0, 0)
1419 AFLAT16(yflat16_row_mirror,    update16_cr, update16_cr, 0, 1)
1420 AFLAT16(yflat16_column,        update16_cr, update16_cr, 1, 0)
1421 AFLAT16(yflat16_column_mirror, update16_cr, update16_cr, 1, 1)
1422
1423 AFLAT(aflat_row,           update, update,    0, 0)
1424 AFLAT(aflat_row_mirror,    update, update,    0, 1)
1425 AFLAT(aflat_column,        update, update,    1, 0)
1426 AFLAT(aflat_column_mirror, update, update,    1, 1)
1427 AFLAT(xflat_row,           update, update_cr, 0, 0)
1428 AFLAT(xflat_row_mirror,    update, update_cr, 0, 1)
1429 AFLAT(xflat_column,        update, update_cr, 1, 0)
1430 AFLAT(xflat_column_mirror, update, update_cr, 1, 1)
1431 AFLAT(yflat_row,           update_cr, update_cr, 0, 0)
1432 AFLAT(yflat_row_mirror,    update_cr, update_cr, 0, 1)
1433 AFLAT(yflat_column,        update_cr, update_cr, 1, 0)
1434 AFLAT(yflat_column_mirror, update_cr, update_cr, 1, 1)
1435
1436 static av_always_inline void chroma16(WaveformContext *s,
1437                                       AVFrame *in, AVFrame *out,
1438                                       int component, int intensity,
1439                                       int offset_y, int offset_x,
1440                                       int column, int mirror,
1441                                       int jobnr, int nb_jobs)
1442 {
1443     const int plane = s->desc->comp[component].plane;
1444     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1445     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1446     const int dst_linesize = out->linesize[plane] / 2;
1447     const int limit = s->max - 1;
1448     const int max = limit - intensity;
1449     const int mid = s->max / 2;
1450     const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1451     const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1452     const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1453     const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1454     const int src_h = in->height;
1455     const int src_w = in->width;
1456     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1457     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1458     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1459     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1460     int x, y;
1461
1462     if (column) {
1463         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1464
1465         for (x = slicew_start; x < slicew_end; x++) {
1466             const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
1467             const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
1468             uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x;
1469             uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1470             uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1471             uint16_t *dst = dst_line;
1472
1473             for (y = 0; y < src_h; y++) {
1474                 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1475                 uint16_t *target;
1476
1477                 target = dst + x + dst_signed_linesize * sum;
1478                 update16(target, max, intensity, limit);
1479
1480                 if (!c0_shift_h || (y & c0_shift_h))
1481                     c0_data += c0_linesize;
1482                 if (!c1_shift_h || (y & c1_shift_h))
1483                     c1_data += c1_linesize;
1484                 dst_data += dst_linesize;
1485             }
1486         }
1487     } else {
1488         const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1489         const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1490         uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1491
1492         if (mirror)
1493             dst_data += s->size - 1;
1494         for (y = sliceh_start; y < sliceh_end; y++) {
1495             for (x = 0; x < src_w; x++) {
1496                 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1497                 uint16_t *target;
1498
1499                 if (mirror) {
1500                     target = dst_data - sum;
1501                     update16(target, max, intensity, limit);
1502                 } else {
1503                     target = dst_data + sum;
1504                     update16(target, max, intensity, limit);
1505                 }
1506             }
1507
1508             if (!c0_shift_h || (y & c0_shift_h))
1509                 c0_data += c0_linesize;
1510             if (!c1_shift_h || (y & c1_shift_h))
1511                 c1_data += c1_linesize;
1512             dst_data += dst_linesize;
1513         }
1514     }
1515 }
1516
1517 #define CHROMA16_FUNC(name, column, mirror)      \
1518 static int chroma16_##name(AVFilterContext *ctx, \
1519                            void *arg, int jobnr, \
1520                            int nb_jobs)          \
1521 {                                                \
1522     WaveformContext *s = ctx->priv;              \
1523     ThreadData *td = arg;                        \
1524     AVFrame *in = td->in;                        \
1525     AVFrame *out = td->out;                      \
1526     int component = td->component;               \
1527     int offset_y = td->offset_y;                 \
1528     int offset_x = td->offset_x;                 \
1529                                                  \
1530     chroma16(s, in, out, component, s->intensity,\
1531            offset_y, offset_x, column, mirror,   \
1532            jobnr, nb_jobs);                      \
1533                                                  \
1534     return 0;                                    \
1535 }
1536
1537 CHROMA16_FUNC(column_mirror, 1, 1)
1538 CHROMA16_FUNC(column,        1, 0)
1539 CHROMA16_FUNC(row_mirror,    0, 1)
1540 CHROMA16_FUNC(row,           0, 0)
1541
1542 static av_always_inline void chroma(WaveformContext *s,
1543                                     AVFrame *in, AVFrame *out,
1544                                     int component, int intensity,
1545                                     int offset_y, int offset_x,
1546                                     int column, int mirror,
1547                                     int jobnr, int nb_jobs)
1548 {
1549     const int plane = s->desc->comp[component].plane;
1550     const int src_h = in->height;
1551     const int src_w = in->width;
1552     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1553     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1554     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1555     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1556     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
1557     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
1558     const int dst_linesize = out->linesize[plane];
1559     const int max = 255 - intensity;
1560     const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1561     const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1562     const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1563     const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1564     int x, y;
1565
1566     if (column) {
1567         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1568
1569         for (x = slicew_start; x < slicew_end; x++) {
1570             const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
1571             const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
1572             uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x;
1573             uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1574             uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1575             uint8_t *dst = dst_line;
1576
1577             for (y = 0; y < src_h; y++) {
1578                 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1579                 uint8_t *target;
1580
1581                 target = dst + x + dst_signed_linesize * sum;
1582                 update(target, max, intensity);
1583
1584                 if (!c0_shift_h || (y & c0_shift_h))
1585                     c0_data += c0_linesize;
1586                 if (!c1_shift_h || (y & c1_shift_h))
1587                     c1_data += c1_linesize;
1588                 dst_data += dst_linesize;
1589             }
1590         }
1591     } else {
1592         const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1593         const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1594         uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1595
1596         if (mirror)
1597             dst_data += s->size - 1;
1598         for (y = sliceh_start; y < sliceh_end; y++) {
1599             for (x = 0; x < src_w; x++) {
1600                 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1601                 uint8_t *target;
1602
1603                 if (mirror) {
1604                     target = dst_data - sum;
1605                     update(target, max, intensity);
1606                 } else {
1607                     target = dst_data + sum;
1608                     update(target, max, intensity);
1609                 }
1610             }
1611
1612             if (!c0_shift_h || (y & c0_shift_h))
1613                 c0_data += c0_linesize;
1614             if (!c1_shift_h || (y & c1_shift_h))
1615                 c1_data += c1_linesize;
1616             dst_data += dst_linesize;
1617         }
1618     }
1619 }
1620
1621 #define CHROMA_FUNC(name, column, mirror)        \
1622 static int chroma_##name(AVFilterContext *ctx,   \
1623                          void *arg, int jobnr,   \
1624                          int nb_jobs)            \
1625 {                                                \
1626     WaveformContext *s = ctx->priv;              \
1627     ThreadData *td = arg;                        \
1628     AVFrame *in = td->in;                        \
1629     AVFrame *out = td->out;                      \
1630     int component = td->component;               \
1631     int offset_y = td->offset_y;                 \
1632     int offset_x = td->offset_x;                 \
1633                                                  \
1634     chroma(s, in, out, component, s->intensity,  \
1635            offset_y, offset_x, column, mirror,   \
1636            jobnr, nb_jobs);                      \
1637                                                  \
1638     return 0;                                    \
1639 }
1640
1641 CHROMA_FUNC(column_mirror, 1, 1)
1642 CHROMA_FUNC(column,        1, 0)
1643 CHROMA_FUNC(row_mirror,    0, 1)
1644 CHROMA_FUNC(row,           0, 0)
1645
1646 static av_always_inline void color16(WaveformContext *s,
1647                                      AVFrame *in, AVFrame *out,
1648                                      int component, int intensity,
1649                                      int offset_y, int offset_x,
1650                                      int column, int mirror,
1651                                      int jobnr, int nb_jobs)
1652 {
1653     const int plane = s->desc->comp[component].plane;
1654     const int limit = s->max - 1;
1655     const int src_h = in->height;
1656     const int src_w = in->width;
1657     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1658     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1659     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1660     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1661     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
1662     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1663     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1664     const int c0_shift_h = s->shift_h[ component + 0 ];
1665     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1666     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1667     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
1668     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1669     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1670     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
1671     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
1672     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
1673     const int c0_shift_w = s->shift_w[ component + 0 ];
1674     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1675     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1676     int x, y;
1677
1678     if (column) {
1679         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1680         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1681         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1682         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
1683         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1684         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1685         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1686         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1687         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1688         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1689         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1690         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1691
1692         for (y = 0; y < src_h; y++) {
1693             for (x = slicew_start; x < slicew_end; x++) {
1694                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1695                 const int c1 = c1_data[x >> c1_shift_w];
1696                 const int c2 = c2_data[x >> c2_shift_w];
1697
1698                 *(d0 + d0_signed_linesize * c0 + x) = c0;
1699                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1700                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1701             }
1702
1703             if (!c0_shift_h || (y & c0_shift_h))
1704                 c0_data += c0_linesize;
1705             if (!c1_shift_h || (y & c1_shift_h))
1706                 c1_data += c1_linesize;
1707             if (!c2_shift_h || (y & c2_shift_h))
1708                 c2_data += c2_linesize;
1709             d0_data += d0_linesize;
1710             d1_data += d1_linesize;
1711             d2_data += d2_linesize;
1712         }
1713     } else {
1714         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1715         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1716         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1717
1718         if (mirror) {
1719             d0_data += s->size - 1;
1720             d1_data += s->size - 1;
1721             d2_data += s->size - 1;
1722         }
1723
1724         for (y = sliceh_start; y < sliceh_end; y++) {
1725             for (x = 0; x < src_w; x++) {
1726                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1727                 const int c1 = c1_data[x >> c1_shift_w];
1728                 const int c2 = c2_data[x >> c2_shift_w];
1729
1730                 if (mirror) {
1731                     *(d0_data - c0) = c0;
1732                     *(d1_data - c0) = c1;
1733                     *(d2_data - c0) = c2;
1734                 } else {
1735                     *(d0_data + c0) = c0;
1736                     *(d1_data + c0) = c1;
1737                     *(d2_data + c0) = c2;
1738                 }
1739             }
1740
1741             if (!c0_shift_h || (y & c0_shift_h))
1742                 c0_data += c0_linesize;
1743             if (!c1_shift_h || (y & c1_shift_h))
1744                 c1_data += c1_linesize;
1745             if (!c2_shift_h || (y & c2_shift_h))
1746                 c2_data += c2_linesize;
1747             d0_data += d0_linesize;
1748             d1_data += d1_linesize;
1749             d2_data += d2_linesize;
1750         }
1751     }
1752 }
1753
1754 #define COLOR16_FUNC(name, column, mirror)       \
1755 static int color16_##name(AVFilterContext *ctx,  \
1756                           void *arg, int jobnr,  \
1757                           int nb_jobs)           \
1758 {                                                \
1759     WaveformContext *s = ctx->priv;              \
1760     ThreadData *td = arg;                        \
1761     AVFrame *in = td->in;                        \
1762     AVFrame *out = td->out;                      \
1763     int component = td->component;               \
1764     int offset_y = td->offset_y;                 \
1765     int offset_x = td->offset_x;                 \
1766                                                  \
1767     color16(s, in, out, component, s->intensity, \
1768             offset_y, offset_x, column, mirror,  \
1769             jobnr, nb_jobs);                     \
1770                                                  \
1771     return 0;                                    \
1772 }
1773
1774 COLOR16_FUNC(column_mirror, 1, 1)
1775 COLOR16_FUNC(column,        1, 0)
1776 COLOR16_FUNC(row_mirror,    0, 1)
1777 COLOR16_FUNC(row,           0, 0)
1778
1779 static av_always_inline void color(WaveformContext *s,
1780                                    AVFrame *in, AVFrame *out,
1781                                    int component, int intensity,
1782                                    int offset_y, int offset_x,
1783                                    int column, int mirror,
1784                                    int jobnr, int nb_jobs)
1785 {
1786     const int plane = s->desc->comp[component].plane;
1787     const int src_h = in->height;
1788     const int src_w = in->width;
1789     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1790     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1791     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1792     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1793     const int c0_linesize = in->linesize[ plane + 0 ];
1794     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1795     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1796     const int c0_shift_h = s->shift_h[ component + 0 ];
1797     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1798     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1799     const uint8_t *c0_data = in->data[plane] +                  (sliceh_start >> c0_shift_h) * c0_linesize;
1800     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1801     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1802     const int d0_linesize = out->linesize[ plane + 0 ];
1803     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1804     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1805     const int c0_shift_w = s->shift_w[ component + 0 ];
1806     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1807     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1808     int x, y;
1809
1810     if (column) {
1811         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1812         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1813         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1814         uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1815         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1816         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1817         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1818         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1819         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1820         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1821         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1822         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1823
1824         for (y = 0; y < src_h; y++) {
1825             for (x = slicew_start; x < slicew_end; x++) {
1826                 const int c0 = c0_data[x >> c0_shift_w];
1827                 const int c1 = c1_data[x >> c1_shift_w];
1828                 const int c2 = c2_data[x >> c2_shift_w];
1829
1830                 *(d0 + d0_signed_linesize * c0 + x) = c0;
1831                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1832                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1833             }
1834
1835             if (!c0_shift_h || (y & c0_shift_h))
1836                 c0_data += c0_linesize;
1837             if (!c1_shift_h || (y & c1_shift_h))
1838                 c1_data += c1_linesize;
1839             if (!c2_shift_h || (y & c2_shift_h))
1840                 c2_data += c2_linesize;
1841             d0_data += d0_linesize;
1842             d1_data += d1_linesize;
1843             d2_data += d2_linesize;
1844         }
1845     } else {
1846         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1847         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1848         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1849
1850         if (mirror) {
1851             d0_data += s->size - 1;
1852             d1_data += s->size - 1;
1853             d2_data += s->size - 1;
1854         }
1855
1856         for (y = sliceh_start; y < sliceh_end; y++) {
1857             for (x = 0; x < src_w; x++) {
1858                 const int c0 = c0_data[x >> c0_shift_w];
1859                 const int c1 = c1_data[x >> c1_shift_w];
1860                 const int c2 = c2_data[x >> c2_shift_w];
1861
1862                 if (mirror) {
1863                     *(d0_data - c0) = c0;
1864                     *(d1_data - c0) = c1;
1865                     *(d2_data - c0) = c2;
1866                 } else {
1867                     *(d0_data + c0) = c0;
1868                     *(d1_data + c0) = c1;
1869                     *(d2_data + c0) = c2;
1870                 }
1871             }
1872
1873             if (!c0_shift_h || (y & c0_shift_h))
1874                 c0_data += c0_linesize;
1875             if (!c1_shift_h || (y & c1_shift_h))
1876                 c1_data += c1_linesize;
1877             if (!c2_shift_h || (y & c2_shift_h))
1878                 c2_data += c2_linesize;
1879             d0_data += d0_linesize;
1880             d1_data += d1_linesize;
1881             d2_data += d2_linesize;
1882         }
1883     }
1884 }
1885
1886 #define COLOR_FUNC(name, column, mirror)       \
1887 static int color_##name(AVFilterContext *ctx,  \
1888                         void *arg, int jobnr,  \
1889                         int nb_jobs)           \
1890 {                                              \
1891     WaveformContext *s = ctx->priv;            \
1892     ThreadData *td = arg;                      \
1893     AVFrame *in = td->in;                      \
1894     AVFrame *out = td->out;                    \
1895     int component = td->component;             \
1896     int offset_y = td->offset_y;               \
1897     int offset_x = td->offset_x;               \
1898                                                \
1899     color(s, in, out, component, s->intensity, \
1900           offset_y, offset_x, column, mirror,  \
1901           jobnr, nb_jobs);                     \
1902                                                \
1903     return 0;                                  \
1904 }
1905
1906 COLOR_FUNC(column_mirror, 1, 1)
1907 COLOR_FUNC(column,        1, 0)
1908 COLOR_FUNC(row_mirror,    0, 1)
1909 COLOR_FUNC(row,           0, 0)
1910
1911 static av_always_inline void acolor16(WaveformContext *s,
1912                                       AVFrame *in, AVFrame *out,
1913                                       int component, int intensity,
1914                                       int offset_y, int offset_x,
1915                                       int column, int mirror,
1916                                       int jobnr, int nb_jobs)
1917 {
1918     const int plane = s->desc->comp[component].plane;
1919     const int limit = s->max - 1;
1920     const int max = limit - intensity;
1921     const int src_h = in->height;
1922     const int src_w = in->width;
1923     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1924     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1925     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1926     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1927     const int c0_shift_h = s->shift_h[ component + 0 ];
1928     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1929     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1930     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
1931     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1932     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1933     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
1934     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1935     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1936     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
1937     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
1938     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
1939     const int c0_shift_w = s->shift_w[ component + 0 ];
1940     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1941     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1942     int x, y;
1943
1944     if (column) {
1945         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1946         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1947         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1948         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
1949         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1950         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1951         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1952         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1953         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1954         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1955         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1956         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1957
1958         for (y = 0; y < src_h; y++) {
1959             for (x = slicew_start; x < slicew_end; x++) {
1960                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1961                 const int c1 = c1_data[x >> c1_shift_w];
1962                 const int c2 = c2_data[x >> c2_shift_w];
1963
1964                 update16(d0 + d0_signed_linesize * c0 + x, max, intensity, limit);
1965                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1966                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1967             }
1968
1969             if (!c0_shift_h || (y & c0_shift_h))
1970                 c0_data += c0_linesize;
1971             if (!c1_shift_h || (y & c1_shift_h))
1972                 c1_data += c1_linesize;
1973             if (!c2_shift_h || (y & c2_shift_h))
1974                 c2_data += c2_linesize;
1975             d0_data += d0_linesize;
1976             d1_data += d1_linesize;
1977             d2_data += d2_linesize;
1978         }
1979     } else {
1980         uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1981         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1982         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1983
1984         if (mirror) {
1985             d0_data += s->size - 1;
1986             d1_data += s->size - 1;
1987             d2_data += s->size - 1;
1988         }
1989
1990         for (y = sliceh_start; y < sliceh_end; y++) {
1991             for (x = 0; x < src_w; x++) {
1992                 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1993                 const int c1 = c1_data[x >> c1_shift_w];
1994                 const int c2 = c2_data[x >> c2_shift_w];
1995
1996                 if (mirror) {
1997                     update16(d0_data - c0, max, intensity, limit);
1998                     *(d1_data - c0) = c1;
1999                     *(d2_data - c0) = c2;
2000                 } else {
2001                     update16(d0_data + c0, max, intensity, limit);
2002                     *(d1_data + c0) = c1;
2003                     *(d2_data + c0) = c2;
2004                 }
2005             }
2006
2007             if (!c0_shift_h || (y & c0_shift_h))
2008                 c0_data += c0_linesize;
2009             if (!c1_shift_h || (y & c1_shift_h))
2010                 c1_data += c1_linesize;
2011             if (!c2_shift_h || (y & c2_shift_h))
2012                 c2_data += c2_linesize;
2013             d0_data += d0_linesize;
2014             d1_data += d1_linesize;
2015             d2_data += d2_linesize;
2016         }
2017     }
2018 }
2019
2020 #define ACOLOR16_FUNC(name, column, mirror)      \
2021 static int acolor16_##name(AVFilterContext *ctx, \
2022                            void *arg, int jobnr, \
2023                            int nb_jobs)          \
2024 {                                                \
2025     WaveformContext *s = ctx->priv;              \
2026     ThreadData *td = arg;                        \
2027     AVFrame *in = td->in;                        \
2028     AVFrame *out = td->out;                      \
2029     int component = td->component;               \
2030     int offset_y = td->offset_y;                 \
2031     int offset_x = td->offset_x;                 \
2032                                                  \
2033     acolor16(s, in, out, component, s->intensity,\
2034              offset_y, offset_x, column, mirror, \
2035              jobnr, nb_jobs);                    \
2036                                                  \
2037     return 0;                                    \
2038 }
2039
2040 ACOLOR16_FUNC(column_mirror, 1, 1)
2041 ACOLOR16_FUNC(column,        1, 0)
2042 ACOLOR16_FUNC(row_mirror,    0, 1)
2043 ACOLOR16_FUNC(row,           0, 0)
2044
2045 static av_always_inline void acolor(WaveformContext *s,
2046                                     AVFrame *in, AVFrame *out,
2047                                     int component, int intensity,
2048                                     int offset_y, int offset_x,
2049                                     int column, int mirror,
2050                                     int jobnr, int nb_jobs)
2051 {
2052     const int plane = s->desc->comp[component].plane;
2053     const int src_h = in->height;
2054     const int src_w = in->width;
2055     const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
2056     const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
2057     const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
2058     const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
2059     const int c0_shift_w = s->shift_w[ component + 0 ];
2060     const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
2061     const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
2062     const int c0_shift_h = s->shift_h[ component + 0 ];
2063     const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
2064     const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
2065     const int c0_linesize = in->linesize[ plane + 0 ];
2066     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
2067     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
2068     const uint8_t *c0_data = in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
2069     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
2070     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
2071     const int d0_linesize = out->linesize[ plane + 0 ];
2072     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
2073     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
2074     const int max = 255 - intensity;
2075     int x, y;
2076
2077     if (column) {
2078         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
2079         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
2080         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
2081         uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
2082         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
2083         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
2084         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
2085         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
2086         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
2087         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
2088         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
2089         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
2090
2091         for (y = 0; y < src_h; y++) {
2092             for (x = slicew_start; x < slicew_end; x++) {
2093                 const int c0 = c0_data[x >> c0_shift_w];
2094                 const int c1 = c1_data[x >> c1_shift_w];
2095                 const int c2 = c2_data[x >> c2_shift_w];
2096
2097                 update(d0 + d0_signed_linesize * c0 + x, max, intensity);
2098                 *(d1 + d1_signed_linesize * c0 + x) = c1;
2099                 *(d2 + d2_signed_linesize * c0 + x) = c2;
2100             }
2101
2102             if (!c0_shift_h || (y & c0_shift_h))
2103                 c0_data += c0_linesize;
2104             if (!c1_shift_h || (y & c1_shift_h))
2105                 c1_data += c1_linesize;
2106             if (!c2_shift_h || (y & c2_shift_h))
2107                 c2_data += c2_linesize;
2108             d0_data += d0_linesize;
2109             d1_data += d1_linesize;
2110             d2_data += d2_linesize;
2111         }
2112     } else {
2113         uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
2114         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
2115         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
2116
2117         if (mirror) {
2118             d0_data += s->size - 1;
2119             d1_data += s->size - 1;
2120             d2_data += s->size - 1;
2121         }
2122
2123         for (y = sliceh_start; y < sliceh_end; y++) {
2124             for (x = 0; x < src_w; x++) {
2125                 const int c0 = c0_data[x >> c0_shift_w];
2126                 const int c1 = c1_data[x >> c1_shift_w];
2127                 const int c2 = c2_data[x >> c2_shift_w];
2128
2129                 if (mirror) {
2130                     update(d0_data - c0, max, intensity);
2131                     *(d1_data - c0) = c1;
2132                     *(d2_data - c0) = c2;
2133                 } else {
2134                     update(d0_data + c0, max, intensity);
2135                     *(d1_data + c0) = c1;
2136                     *(d2_data + c0) = c2;
2137                 }
2138             }
2139
2140             if (!c0_shift_h || (y & c0_shift_h))
2141                 c0_data += c0_linesize;
2142             if (!c1_shift_h || (y & c1_shift_h))
2143                 c1_data += c1_linesize;
2144             if (!c2_shift_h || (y & c2_shift_h))
2145                 c2_data += c2_linesize;
2146             d0_data += d0_linesize;
2147             d1_data += d1_linesize;
2148             d2_data += d2_linesize;
2149         }
2150     }
2151 }
2152
2153 #define ACOLOR_FUNC(name, column, mirror)        \
2154 static int acolor_##name(AVFilterContext *ctx,   \
2155                          void *arg, int jobnr,   \
2156                          int nb_jobs)            \
2157 {                                                \
2158     WaveformContext *s = ctx->priv;              \
2159     ThreadData *td = arg;                        \
2160     AVFrame *in = td->in;                        \
2161     AVFrame *out = td->out;                      \
2162     int component = td->component;               \
2163     int offset_y = td->offset_y;                 \
2164     int offset_x = td->offset_x;                 \
2165                                                  \
2166     acolor(s, in, out, component, s->intensity,  \
2167            offset_y, offset_x, column, mirror,   \
2168            jobnr, nb_jobs);                      \
2169                                                  \
2170     return 0;                                    \
2171 }
2172
2173 ACOLOR_FUNC(column_mirror, 1, 1)
2174 ACOLOR_FUNC(column,        1, 0)
2175 ACOLOR_FUNC(row_mirror,    0, 1)
2176 ACOLOR_FUNC(row,           0, 0)
2177
2178 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
2179 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
2180
2181 static const GraticuleLines aflat_digital8[] = {
2182     { { {  "16",  16+128 }, {  "16",  16+128 }, {  "16",  16+128 }, {   "0",   0+128 } } },
2183     { { { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 } } },
2184     { { { "235", 235+128 }, { "240", 240+128 }, { "240", 240+128 }, { "255", 255+128 } } },
2185 };
2186
2187 static const GraticuleLines aflat_digital9[] = {
2188     { { {  "32",  32+256 }, {  "32",  32+256 }, {  "32",  32+256 }, {   "0",   0+256 } } },
2189     { { { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 } } },
2190     { { { "470", 470+256 }, { "480", 480+256 }, { "480", 480+256 }, { "511", 511+256 } } },
2191 };
2192
2193 static const GraticuleLines aflat_digital10[] = {
2194     { { {  "64",  64+512 }, {  "64",  64+512 }, {  "64",  64+512 }, {    "0",    0+512 } } },
2195     { { { "512", 512+512 }, { "512", 512+512 }, { "512", 512+512 }, {  "512",  512+512 } } },
2196     { { { "940", 940+512 }, { "960", 960+512 }, { "960", 960+512 }, { "1023", 1023+512 } } },
2197 };
2198
2199 static const GraticuleLines aflat_digital12[] = {
2200     { { {  "256",  256+2048 }, {  "256",  256+2048 }, {  "256",  256+2048 }, {    "0",    0+2048 } } },
2201     { { { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 } } },
2202     { { { "3760", 3760+2048 }, { "3840", 3840+2048 }, { "3840", 3840+2048 }, { "4095", 4095+2048 } } },
2203 };
2204
2205 static const GraticuleLines aflat_millivolts8[] = {
2206     { { {   "0",  16+128 }, {   "0",  16+128 }, {   "0",  16+128 }, {   "0",   0+128 } } },
2207     { { { "175",  71+128 }, { "175",  72+128 }, { "175",  72+128 }, { "175",  64+128 } } },
2208     { { { "350", 126+128 }, { "350", 128+128 }, { "350", 128+128 }, { "350", 128+128 } } },
2209     { { { "525", 180+128 }, { "525", 184+128 }, { "525", 184+128 }, { "525", 192+128 } } },
2210     { { { "700", 235+128 }, { "700", 240+128 }, { "700", 240+128 }, { "700", 255+128 } } },
2211 };
2212
2213 static const GraticuleLines aflat_millivolts9[] = {
2214     { { {   "0",  32+256 }, {   "0",  32+256 }, {   "0",  32+256 }, {   "0",   0+256 } } },
2215     { { { "175", 142+256 }, { "175", 144+256 }, { "175", 144+256 }, { "175", 128+256 } } },
2216     { { { "350", 251+256 }, { "350", 256+256 }, { "350", 256+256 }, { "350", 256+256 } } },
2217     { { { "525", 361+256 }, { "525", 368+256 }, { "525", 368+256 }, { "525", 384+256 } } },
2218     { { { "700", 470+256 }, { "700", 480+256 }, { "700", 480+256 }, { "700", 511+256 } } },
2219 };
2220
2221 static const GraticuleLines aflat_millivolts10[] = {
2222     { { {   "0",  64+512 }, {   "0",  64+512 }, {   "0",  64+512 }, {   "0",    0+512 } } },
2223     { { { "175", 283+512 }, { "175", 288+512 }, { "175", 288+512 }, { "175",  256+512 } } },
2224     { { { "350", 502+512 }, { "350", 512+512 }, { "350", 512+512 }, { "350",  512+512 } } },
2225     { { { "525", 721+512 }, { "525", 736+512 }, { "525", 736+512 }, { "525",  768+512 } } },
2226     { { { "700", 940+512 }, { "700", 960+512 }, { "700", 960+512 }, { "700", 1023+512 } } },
2227 };
2228
2229 static const GraticuleLines aflat_millivolts12[] = {
2230     { { {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",    0+2048 } } },
2231     { { { "175", 1132+2048 }, { "175", 1152+2048 }, { "175", 1152+2048 }, { "175", 1024+2048 } } },
2232     { { { "350", 2008+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 } } },
2233     { { { "525", 2884+2048 }, { "525", 2944+2048 }, { "525", 2944+2048 }, { "525", 3072+2048 } } },
2234     { { { "700", 3760+2048 }, { "700", 3840+2048 }, { "700", 3840+2048 }, { "700", 4095+2048 } } },
2235 };
2236
2237 static const GraticuleLines aflat_ire8[] = {
2238     { { { "-25", -39+128 }, { "-25", -40+128 }, { "-25", -40+128 }, { "-25", -64+128 } } },
2239     { { {   "0",  16+128 }, {   "0",  16+128 }, {   "0",  16+128 }, {   "0",   0+128 } } },
2240     { { {  "25",  71+128 }, {  "25",  72+128 }, {  "25",  72+128 }, {  "25",  64+128 } } },
2241     { { {  "50", 126+128 }, {  "50", 128+128 }, {  "50", 128+128 }, {  "50", 128+128 } } },
2242     { { {  "75", 180+128 }, {  "75", 184+128 }, {  "75", 184+128 }, {  "75", 192+128 } } },
2243     { { { "100", 235+128 }, { "100", 240+128 }, { "100", 240+128 }, { "100", 256+128 } } },
2244     { { { "125", 290+128 }, { "125", 296+128 }, { "125", 296+128 }, { "125", 320+128 } } },
2245 };
2246
2247 static const GraticuleLines aflat_ire9[] = {
2248     { { { "-25", -78+256 }, { "-25", -80+256 }, { "-25", -80+256 }, { "-25",-128+256 } } },
2249     { { {   "0",  32+256 }, {   "0",  32+256 }, {   "0",  32+256 }, {   "0",   0+256 } } },
2250     { { {  "25", 142+256 }, {  "25", 144+256 }, {  "25", 144+256 }, {  "25", 128+256 } } },
2251     { { {  "50", 251+256 }, {  "50", 256+256 }, {  "50", 256+256 }, {  "50", 256+256 } } },
2252     { { {  "75", 361+256 }, {  "75", 368+256 }, {  "75", 368+256 }, {  "75", 384+256 } } },
2253     { { { "100", 470+256 }, { "100", 480+256 }, { "100", 480+256 }, { "100", 512+256 } } },
2254     { { { "125", 580+256 }, { "125", 592+256 }, { "125", 592+256 }, { "125", 640+256 } } },
2255 };
2256
2257 static const GraticuleLines aflat_ire10[] = {
2258     { { { "-25",-156+512 }, { "-25",-160+512 }, { "-25",-160+512 }, { "-25", -256+512 } } },
2259     { { {   "0",  64+512 }, {   "0",  64+512 }, {  "0",   64+512 }, {   "0",    0+512 } } },
2260     { { {  "25", 283+512 }, {  "25", 288+512 }, {  "25", 288+512 }, {  "25",  256+512 } } },
2261     { { {  "50", 502+512 }, {  "50", 512+512 }, {  "50", 512+512 }, {  "50",  512+512 } } },
2262     { { {  "75", 721+512 }, {  "75", 736+512 }, {  "75", 736+512 }, {  "75",  768+512 } } },
2263     { { { "100", 940+512 }, { "100", 960+512 }, { "100", 960+512 }, { "100", 1024+512 } } },
2264     { { { "125",1160+512 }, { "125",1184+512 }, { "125",1184+512 }, { "125", 1280+512 } } },
2265 };
2266
2267 static const GraticuleLines aflat_ire12[] = {
2268     { { { "-25", -624+2048 }, { "-25", -640+2048 }, { "-25", -640+2048 }, { "-25",-1024+2048 } } },
2269     { { {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",  256+2048 }, {   "0",    0+2048 } } },
2270     { { {  "25", 1132+2048 }, {  "25", 1152+2048 }, {  "25", 1152+2048 }, {  "25", 1024+2048 } } },
2271     { { {  "50", 2008+2048 }, {  "50", 2048+2048 }, {  "50", 2048+2048 }, {  "50", 2048+2048 } } },
2272     { { {  "75", 2884+2048 }, {  "75", 2944+2048 }, {  "75", 2944+2048 }, {  "75", 3072+2048 } } },
2273     { { { "100", 3760+2048 }, { "100", 3840+2048 }, { "100", 3840+2048 }, { "100", 4096+2048 } } },
2274     { { { "125", 4640+2048 }, { "125", 4736+2048 }, { "125", 4736+2048 }, { "125", 5120+2048 } } },
2275 };
2276
2277 static const GraticuleLines flat_digital8[] = {
2278     { { {  "16",  16+256 }, {  "16",  16+256 }, {  "16",  16+256 }, {   "0",   0+256 } } },
2279     { { { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 } } },
2280     { { { "235", 235+256 }, { "240", 240+256 }, { "240", 240+256 }, { "255", 255+256 } } },
2281 };
2282
2283 static const GraticuleLines flat_digital9[] = {
2284     { { {  "32",  32+512 }, {  "32",  32+512 }, {  "32",  32+512 }, {   "0",   0+512 } } },
2285     { { { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 } } },
2286     { { { "470", 470+512 }, { "480", 480+512 }, { "480", 480+512 }, { "511", 511+512 } } },
2287 };
2288
2289 static const GraticuleLines flat_digital10[] = {
2290     { { {  "64",  64+1024 }, {  "64",  64+1024 }, {  "64",  64+1024 }, {    "0",    0+1024 } } },
2291     { { { "512", 512+1024 }, { "512", 512+1024 }, { "512", 512+1024 }, {  "512",  512+1024 } } },
2292     { { { "940", 940+1024 }, { "960", 960+1024 }, { "960", 960+1024 }, { "1023", 1023+1024 } } },
2293 };
2294
2295 static const GraticuleLines flat_digital12[] = {
2296     { { {  "256",  256+4096 }, {  "256",  256+4096 }, {  "256",  256+4096 }, {    "0",    0+4096 } } },
2297     { { { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 } } },
2298     { { { "3760", 3760+4096 }, { "3840", 3840+4096 }, { "3840", 3840+4096 }, { "4095", 4095+4096 } } },
2299 };
2300
2301 static const GraticuleLines flat_millivolts8[] = {
2302     { { {   "0",  16+256 }, {   "0",  16+256 }, {   "0",  16+256 }, {   "0",   0+256 } } },
2303     { { { "175",  71+256 }, { "175",  72+256 }, { "175",  72+256 }, { "175",  64+256 } } },
2304     { { { "350", 126+256 }, { "350", 128+256 }, { "350", 128+256 }, { "350", 128+256 } } },
2305     { { { "525", 180+256 }, { "525", 184+256 }, { "525", 184+256 }, { "525", 192+256 } } },
2306     { { { "700", 235+256 }, { "700", 240+256 }, { "700", 240+256 }, { "700", 255+256 } } },
2307 };
2308
2309 static const GraticuleLines flat_millivolts9[] = {
2310     { { {   "0",  32+512 }, {   "0",  32+512 }, {   "0",  32+512 }, {   "0",   0+512 } } },
2311     { { { "175", 142+512 }, { "175", 144+512 }, { "175", 144+512 }, { "175", 128+512 } } },
2312     { { { "350", 251+512 }, { "350", 256+512 }, { "350", 256+512 }, { "350", 256+512 } } },
2313     { { { "525", 361+512 }, { "525", 368+512 }, { "525", 368+512 }, { "525", 384+512 } } },
2314     { { { "700", 470+512 }, { "700", 480+512 }, { "700", 480+512 }, { "700", 511+512 } } },
2315 };
2316
2317 static const GraticuleLines flat_millivolts10[] = {
2318     { { {   "0",  64+1024 }, {   "0",  64+1024 }, {   "0",  64+1024 }, {   "0",    0+1024 } } },
2319     { { { "175", 283+1024 }, { "175", 288+1024 }, { "175", 288+1024 }, { "175",  256+1024 } } },
2320     { { { "350", 502+1024 }, { "350", 512+1024 }, { "350", 512+1024 }, { "350",  512+1024 } } },
2321     { { { "525", 721+1024 }, { "525", 736+1024 }, { "525", 736+1024 }, { "525",  768+1024 } } },
2322     { { { "700", 940+1024 }, { "700", 960+1024 }, { "700", 960+1024 }, { "700", 1023+1024 } } },
2323 };
2324
2325 static const GraticuleLines flat_millivolts12[] = {
2326     { { {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",    0+4096 } } },
2327     { { { "175", 1132+4096 }, { "175", 1152+4096 }, { "175", 1152+4096 }, { "175", 1024+4096 } } },
2328     { { { "350", 2008+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 } } },
2329     { { { "525", 2884+4096 }, { "525", 2944+4096 }, { "525", 2944+4096 }, { "525", 3072+4096 } } },
2330     { { { "700", 3760+4096 }, { "700", 3840+4096 }, { "700", 3840+4096 }, { "700", 4095+4096 } } },
2331 };
2332
2333 static const GraticuleLines flat_ire8[] = {
2334     { { { "-25", -39+256 }, { "-25", -40+256 }, { "-25", -40+256 }, { "-25", -64+256 } } },
2335     { { {   "0",  16+256 }, {   "0",  16+256 }, {   "0",  16+256 }, {   "0",   0+256 } } },
2336     { { {  "25",  71+256 }, {  "25",  72+256 }, {  "25",  72+256 }, {  "25",  64+256 } } },
2337     { { {  "50", 126+256 }, {  "50", 128+256 }, {  "50", 128+256 }, {  "50", 128+256 } } },
2338     { { {  "75", 180+256 }, {  "75", 184+256 }, {  "75", 184+256 }, {  "75", 192+256 } } },
2339     { { { "100", 235+256 }, { "100", 240+256 }, { "100", 240+256 }, { "100", 256+256 } } },
2340     { { { "125", 290+256 }, { "125", 296+256 }, { "125", 296+256 }, { "125", 320+256 } } },
2341 };
2342
2343 static const GraticuleLines flat_ire9[] = {
2344     { { { "-25", -78+512 }, { "-25", -80+512 }, { "-25", -80+512 }, { "-25",-128+512 } } },
2345     { { {   "0",  32+512 }, {   "0",  32+512 }, {   "0",  32+512 }, {   "0",   0+512 } } },
2346     { { {  "25", 142+512 }, {  "25", 144+512 }, {  "25", 144+512 }, {  "25", 128+512 } } },
2347     { { {  "50", 251+512 }, {  "50", 256+512 }, {  "50", 256+512 }, {  "50", 256+512 } } },
2348     { { {  "75", 361+512 }, {  "75", 368+512 }, {  "75", 368+512 }, {  "75", 384+512 } } },
2349     { { { "100", 470+512 }, { "100", 480+512 }, { "100", 480+512 }, { "100", 512+512 } } },
2350     { { { "125", 580+512 }, { "125", 592+512 }, { "125", 592+512 }, { "125", 640+512 } } },
2351 };
2352
2353 static const GraticuleLines flat_ire10[] = {
2354     { { { "-25",-156+1024 }, { "-25",-160+1024 }, { "-25",-160+1024 }, { "-25", -256+1024 } } },
2355     { { {   "0",  64+1024 }, {   "0",  64+1024 }, {  "0",   64+1024 }, {   "0",    0+1024 } } },
2356     { { {  "25", 283+1024 }, {  "25", 288+1024 }, {  "25", 288+1024 }, {  "25",  256+1024 } } },
2357     { { {  "50", 502+1024 }, {  "50", 512+1024 }, {  "50", 512+1024 }, {  "50",  512+1024 } } },
2358     { { {  "75", 721+1024 }, {  "75", 736+1024 }, {  "75", 736+1024 }, {  "75",  768+1024 } } },
2359     { { { "100", 940+1024 }, { "100", 960+1024 }, { "100", 960+1024 }, { "100", 1024+1024 } } },
2360     { { { "125",1160+1024 }, { "125",1184+1024 }, { "125",1184+1024 }, { "125", 1280+1024 } } },
2361 };
2362
2363 static const GraticuleLines flat_ire12[] = {
2364     { { { "-25", -624+4096 }, { "-25", -640+4096 }, { "-25", -640+4096 }, { "-25",-1024+4096 } } },
2365     { { {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",  256+4096 }, {   "0",    0+4096 } } },
2366     { { {  "25", 1132+4096 }, {  "25", 1152+4096 }, {  "25", 1152+4096 }, {  "25", 1024+4096 } } },
2367     { { {  "50", 2008+4096 }, {  "50", 2048+4096 }, {  "50", 2048+4096 }, {  "50", 2048+4096 } } },
2368     { { {  "75", 2884+4096 }, {  "75", 2944+4096 }, {  "75", 2944+4096 }, {  "75", 3072+4096 } } },
2369     { { { "100", 3760+4096 }, { "100", 3840+4096 }, { "100", 3840+4096 }, { "100", 4096+4096 } } },
2370     { { { "125", 4640+4096 }, { "125", 4736+4096 }, { "125", 4736+4096 }, { "125", 5120+4096 } } },
2371 };
2372
2373 static const GraticuleLines digital8[] = {
2374     { { {  "16",  16 }, {  "16",  16 }, {  "16",  16 }, {   "0",   0 } } },
2375     { { { "128", 128 }, { "128", 128 }, { "128", 128 }, { "128", 128 } } },
2376     { { { "235", 235 }, { "240", 240 }, { "240", 240 }, { "255", 255 } } },
2377 };
2378
2379 static const GraticuleLines digital9[] = {
2380     { { {  "32",  32 }, {  "32",  32 }, {  "32",  32 }, {   "0",   0 } } },
2381     { { { "256", 256 }, { "256", 256 }, { "256", 256 }, { "256", 256 } } },
2382     { { { "470", 470 }, { "480", 480 }, { "480", 480 }, { "511", 511 } } },
2383 };
2384
2385 static const GraticuleLines digital10[] = {
2386     { { {  "64",  64 }, {  "64",  64 }, {  "64",  64 }, {    "0",    0 } } },
2387     { { { "512", 512 }, { "512", 512 }, { "512", 512 }, {  "512",  512 } } },
2388     { { { "940", 940 }, { "960", 960 }, { "960", 960 }, { "1023", 1023 } } },
2389 };
2390
2391 static const GraticuleLines digital12[] = {
2392     { { {  "256",  256 }, {  "256",  256 }, {  "256",  256 }, {    "0",    0 } } },
2393     { { { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 } } },
2394     { { { "3760", 3760 }, { "3840", 3840 }, { "3840", 3840 }, { "4095", 4095 } } },
2395 };
2396
2397 static const GraticuleLines millivolts8[] = {
2398     { { {   "0",  16 }, {   "0",  16 }, {   "0",  16 }, {   "0",   0 } } },
2399     { { { "175",  71 }, { "175",  72 }, { "175",  72 }, { "175",  64 } } },
2400     { { { "350", 126 }, { "350", 128 }, { "350", 128 }, { "350", 128 } } },
2401     { { { "525", 180 }, { "525", 184 }, { "525", 184 }, { "525", 192 } } },
2402     { { { "700", 235 }, { "700", 240 }, { "700", 240 }, { "700", 255 } } },
2403 };
2404
2405 static const GraticuleLines millivolts9[] = {
2406     { { {   "0",  32 }, {   "0",  32 }, {   "0",  32 }, {   "0",   0 } } },
2407     { { { "175", 142 }, { "175", 144 }, { "175", 144 }, { "175", 128 } } },
2408     { { { "350", 251 }, { "350", 256 }, { "350", 256 }, { "350", 256 } } },
2409     { { { "525", 361 }, { "525", 368 }, { "525", 368 }, { "525", 384 } } },
2410     { { { "700", 470 }, { "700", 480 }, { "700", 480 }, { "700", 511 } } },
2411 };
2412
2413 static const GraticuleLines millivolts10[] = {
2414     { { {   "0",  64 }, {   "0",  64 }, {   "0",  64 }, {   "0",    0 } } },
2415     { { { "175", 283 }, { "175", 288 }, { "175", 288 }, { "175",  256 } } },
2416     { { { "350", 502 }, { "350", 512 }, { "350", 512 }, { "350",  512 } } },
2417     { { { "525", 721 }, { "525", 736 }, { "525", 736 }, { "525",  768 } } },
2418     { { { "700", 940 }, { "700", 960 }, { "700", 960 }, { "700", 1023 } } },
2419 };
2420
2421 static const GraticuleLines millivolts12[] = {
2422     { { {   "0",  256 }, {   "0",  256 }, {   "0",  256 }, {   "0",    0 } } },
2423     { { { "175", 1132 }, { "175", 1152 }, { "175", 1152 }, { "175", 1024 } } },
2424     { { { "350", 2008 }, { "350", 2048 }, { "350", 2048 }, { "350", 2048 } } },
2425     { { { "525", 2884 }, { "525", 2944 }, { "525", 2944 }, { "525", 3072 } } },
2426     { { { "700", 3760 }, { "700", 3840 }, { "700", 3840 }, { "700", 4095 } } },
2427 };
2428
2429 static const GraticuleLines ire8[] = {
2430     { { {   "0",  16 }, {   "0",  16 }, {   "0",  16 }, {   "0",   0 } } },
2431     { { {  "25",  71 }, {  "25",  72 }, {  "25",  72 }, {  "25",  64 } } },
2432     { { {  "50", 126 }, {  "50", 128 }, {  "50", 128 }, {  "50", 128 } } },
2433     { { {  "75", 180 }, {  "75", 184 }, {  "75", 184 }, {  "75", 192 } } },
2434     { { { "100", 235 }, { "100", 240 }, { "100", 240 }, { "100", 255 } } },
2435 };
2436
2437 static const GraticuleLines ire9[] = {
2438     { { {   "0",  32 }, {   "0",  32 }, {   "0",  32 }, {   "0",   0 } } },
2439     { { {  "25", 142 }, {  "25", 144 }, {  "25", 144 }, {  "25", 128 } } },
2440     { { {  "50", 251 }, {  "50", 256 }, {  "50", 256 }, {  "50", 256 } } },
2441     { { {  "75", 361 }, {  "75", 368 }, {  "75", 368 }, {  "75", 384 } } },
2442     { { { "100", 470 }, { "100", 480 }, { "100", 480 }, { "100", 511 } } },
2443 };
2444
2445 static const GraticuleLines ire10[] = {
2446     { { {   "0",  64 }, {   "0",  64 }, {  "0",   64 }, {   "0",    0 } } },
2447     { { {  "25", 283 }, {  "25", 288 }, {  "25", 288 }, {  "25",  256 } } },
2448     { { {  "50", 502 }, {  "50", 512 }, {  "50", 512 }, {  "50",  512 } } },
2449     { { {  "75", 721 }, {  "75", 736 }, {  "75", 736 }, {  "75",  768 } } },
2450     { { { "100", 940 }, { "100", 960 }, { "100", 960 }, { "100", 1023 } } },
2451 };
2452
2453 static const GraticuleLines ire12[] = {
2454     { { {   "0",  256 }, {   "0",  256 }, {   "0",  256 }, {   "0",    0 } } },
2455     { { {  "25", 1132 }, {  "25", 1152 }, {  "25", 1152 }, {  "25", 1024 } } },
2456     { { {  "50", 2008 }, {  "50", 2048 }, {  "50", 2048 }, {  "50", 2048 } } },
2457     { { {  "75", 2884 }, {  "75", 2944 }, {  "75", 2944 }, {  "75", 3072 } } },
2458     { { { "100", 3760 }, { "100", 3840 }, { "100", 3840 }, { "100", 4095 } } },
2459 };
2460
2461 static const GraticuleLines chroma_digital8[] = {
2462     { { {  "50",  50 }, {  "50",  50 }, {  "50",  50 }, {  "50",  50 } } },
2463     { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
2464     { { { "150", 150 }, { "150", 150 }, { "150", 150 }, { "150", 150 } } },
2465     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2466     { { { "255", 255 }, { "255", 255 }, { "255", 255 }, { "255", 255 } } },
2467 };
2468
2469 static const GraticuleLines chroma_digital9[] = {
2470     { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
2471     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2472     { { { "300", 300 }, { "300", 300 }, { "300", 300 }, { "300", 300 } } },
2473     { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
2474     { { { "500", 500 }, { "500", 500 }, { "500", 500 }, { "500", 500 } } },
2475 };
2476
2477 static const GraticuleLines chroma_digital10[] = {
2478     { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2479     { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
2480     { { { "600", 600 }, { "600", 600 }, { "600", 600 }, { "600", 600 } } },
2481     { { { "800", 800 }, { "800", 800 }, { "800", 800 }, { "800", 800 } } },
2482     { { {"1000",1000 }, {"1000",1000 }, {"1000",1000 }, {"1000",1000 } } },
2483 };
2484
2485 static const GraticuleLines chroma_digital12[] = {
2486     { { {  "800",  800 }, {  "800",  800 }, {  "800",  800 }, {  "800",  800 } } },
2487     { { { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 } } },
2488     { { { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 } } },
2489     { { { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 } } },
2490     { { { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 } } },
2491 };
2492
2493 static void blend_vline(uint8_t *dst, int height, int linesize, float o1, float o2, int v, int step)
2494 {
2495     int y;
2496
2497     for (y = 0; y < height; y += step) {
2498         dst[0] = v * o1 + dst[0] * o2;
2499
2500         dst += linesize * step;
2501     }
2502 }
2503
2504 static void blend_vline16(uint8_t *ddst, int height, int linesize, float o1, float o2, int v, int step)
2505 {
2506     uint16_t *dst = (uint16_t *)ddst;
2507     int y;
2508
2509     for (y = 0; y < height; y += step) {
2510         dst[0] = v * o1 + dst[0] * o2;
2511
2512         dst += (linesize / 2) * step;
2513     }
2514 }
2515
2516 static void blend_hline(uint8_t *dst, int width, int unused, float o1, float o2, int v, int step)
2517 {
2518     int x;
2519
2520     for (x = 0; x < width; x += step) {
2521         dst[x] = v * o1 + dst[x] * o2;
2522     }
2523 }
2524
2525 static void blend_hline16(uint8_t *ddst, int width, int unused, float o1, float o2, int v, int step)
2526 {
2527     uint16_t *dst = (uint16_t *)ddst;
2528     int x;
2529
2530     for (x = 0; x < width; x += step) {
2531         dst[x] = v * o1 + dst[x] * o2;
2532     }
2533 }
2534
2535 static void draw_htext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2536 {
2537     const uint8_t *font;
2538     int font_height;
2539     int i, plane;
2540
2541     font = avpriv_cga_font,   font_height =  8;
2542
2543     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2544         for (i = 0; txt[i]; i++) {
2545             int char_y, mask;
2546             int v = color[plane];
2547
2548             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
2549             for (char_y = 0; char_y < font_height; char_y++) {
2550                 for (mask = 0x80; mask; mask >>= 1) {
2551                     if (font[txt[i] * font_height + char_y] & mask)
2552                         p[0] = p[0] * o2 + v * o1;
2553                     p++;
2554                 }
2555                 p += out->linesize[plane] - 8;
2556             }
2557         }
2558     }
2559 }
2560
2561 static void draw_htext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2562 {
2563     const uint8_t *font;
2564     int font_height;
2565     int i, plane;
2566
2567     font = avpriv_cga_font,   font_height =  8;
2568
2569     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2570         for (i = 0; txt[i]; i++) {
2571             int char_y, mask;
2572             int v = color[plane] * mult;
2573
2574             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
2575             for (char_y = 0; char_y < font_height; char_y++) {
2576                 for (mask = 0x80; mask; mask >>= 1) {
2577                     if (font[txt[i] * font_height + char_y] & mask)
2578                         p[0] = p[0] * o2 + v * o1;
2579                     p++;
2580                 }
2581                 p += out->linesize[plane] / 2 - 8;
2582             }
2583         }
2584     }
2585 }
2586
2587 static void draw_vtext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2588 {
2589     const uint8_t *font;
2590     int font_height;
2591     int i, plane;
2592
2593     font = avpriv_cga_font,   font_height =  8;
2594
2595     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2596         for (i = 0; txt[i]; i++) {
2597             int char_y, mask;
2598             int v = color[plane];
2599
2600             for (char_y = font_height - 1; char_y >= 0; char_y--) {
2601                 uint8_t *p = out->data[plane] + (y + i * 10) * out->linesize[plane] + x;
2602                 for (mask = 0x80; mask; mask >>= 1) {
2603                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2604                         p[char_y] = p[char_y] * o2 + v * o1;
2605                     p += out->linesize[plane];
2606                 }
2607             }
2608         }
2609     }
2610 }
2611
2612 static void draw_vtext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2613 {
2614     const uint8_t *font;
2615     int font_height;
2616     int i, plane;
2617
2618     font = avpriv_cga_font,   font_height =  8;
2619
2620     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2621         for (i = 0; txt[i]; i++) {
2622             int char_y, mask;
2623             int v = color[plane] * mult;
2624
2625             for (char_y = 0; char_y < font_height; char_y++) {
2626                 uint16_t *p = (uint16_t *)(out->data[plane] + (y + i * 10) * out->linesize[plane]) + x;
2627                 for (mask = 0x80; mask; mask >>= 1) {
2628                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2629                         p[char_y] = p[char_y] * o2 + v * o1;
2630                     p += out->linesize[plane] / 2;
2631                 }
2632             }
2633         }
2634     }
2635 }
2636
2637 static void iblend_vline(uint8_t *dst, int height, int linesize, float o1, float o2, int v, int step)
2638 {
2639     int y;
2640
2641     for (y = 0; y < height; y += step) {
2642         dst[0] = (v - dst[0]) * o1 + dst[0] * o2;
2643
2644         dst += linesize * step;
2645     }
2646 }
2647
2648 static void iblend_vline16(uint8_t *ddst, int height, int linesize, float o1, float o2, int v, int step)
2649 {
2650     uint16_t *dst = (uint16_t *)ddst;
2651     int y;
2652
2653     for (y = 0; y < height; y += step) {
2654         dst[0] = (v - dst[0]) * o1 + dst[0] * o2;
2655
2656         dst += (linesize / 2) * step;
2657     }
2658 }
2659
2660 static void iblend_hline(uint8_t *dst, int width, int unused, float o1, float o2, int v, int step)
2661 {
2662     int x;
2663
2664     for (x = 0; x < width; x += step) {
2665         dst[x] = (v - dst[x]) * o1 + dst[x] * o2;
2666     }
2667 }
2668
2669 static void iblend_hline16(uint8_t *ddst, int width, int unused, float o1, float o2, int v, int step)
2670 {
2671     uint16_t *dst = (uint16_t *)ddst;
2672     int x;
2673
2674     for (x = 0; x < width; x += step) {
2675         dst[x] = (v - dst[x]) * o1 + dst[x] * o2;
2676     }
2677 }
2678
2679 static void idraw_htext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2680 {
2681     const uint8_t *font;
2682     int font_height;
2683     int i, plane;
2684
2685     font = avpriv_cga_font,   font_height =  8;
2686
2687     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2688         for (i = 0; txt[i]; i++) {
2689             int char_y, mask;
2690             int v = color[plane];
2691
2692             uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
2693             for (char_y = 0; char_y < font_height; char_y++) {
2694                 for (mask = 0x80; mask; mask >>= 1) {
2695                     if (font[txt[i] * font_height + char_y] & mask)
2696                         p[0] = p[0] * o2 + (v - p[0]) * o1;
2697                     p++;
2698                 }
2699                 p += out->linesize[plane] - 8;
2700             }
2701         }
2702     }
2703 }
2704
2705 static void idraw_htext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2706 {
2707     const uint8_t *font;
2708     int font_height;
2709     int i, plane;
2710
2711     font = avpriv_cga_font,   font_height =  8;
2712
2713     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2714         for (i = 0; txt[i]; i++) {
2715             int char_y, mask;
2716             int v = color[plane] * mult;
2717
2718             uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
2719             for (char_y = 0; char_y < font_height; char_y++) {
2720                 for (mask = 0x80; mask; mask >>= 1) {
2721                     if (font[txt[i] * font_height + char_y] & mask)
2722                         p[0] = p[0] * o2 + (v - p[0]) * o1;
2723                     p++;
2724                 }
2725                 p += out->linesize[plane] / 2 - 8;
2726             }
2727         }
2728     }
2729 }
2730
2731 static void idraw_vtext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2732 {
2733     const uint8_t *font;
2734     int font_height;
2735     int i, plane;
2736
2737     font = avpriv_cga_font,   font_height =  8;
2738
2739     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2740         for (i = 0; txt[i]; i++) {
2741             int char_y, mask;
2742             int v = color[plane];
2743
2744             for (char_y = font_height - 1; char_y >= 0; char_y--) {
2745                 uint8_t *p = out->data[plane] + (y + i * 10) * out->linesize[plane] + x;
2746                 for (mask = 0x80; mask; mask >>= 1) {
2747                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2748                         p[char_y] = p[char_y] * o2 + (v - p[char_y]) * o1;
2749                     p += out->linesize[plane];
2750                 }
2751             }
2752         }
2753     }
2754 }
2755
2756 static void idraw_vtext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2757 {
2758     const uint8_t *font;
2759     int font_height;
2760     int i, plane;
2761
2762     font = avpriv_cga_font,   font_height =  8;
2763
2764     for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2765         for (i = 0; txt[i]; i++) {
2766             int char_y, mask;
2767             int v = color[plane] * mult;
2768
2769             for (char_y = 0; char_y < font_height; char_y++) {
2770                 uint16_t *p = (uint16_t *)(out->data[plane] + (y + i * 10) * out->linesize[plane]) + x;
2771                 for (mask = 0x80; mask; mask >>= 1) {
2772                     if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2773                         p[char_y] = p[char_y] * o2 + (v - p[char_y]) * o1;
2774                     p += out->linesize[plane] / 2;
2775                 }
2776             }
2777         }
2778     }
2779 }
2780
2781 static void graticule_none(WaveformContext *s, AVFrame *out)
2782 {
2783 }
2784
2785 static void graticule_row(WaveformContext *s, AVFrame *out)
2786 {
2787     const int step = (s->flags & 2) + 1;
2788     const float o1 = s->opacity;
2789     const float o2 = 1. - o1;
2790     const int height = s->display == PARADE ? out->height / s->acomp : out->height;
2791     int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2792
2793     for (c = 0; c < s->ncomp; c++) {
2794         if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
2795             continue;
2796
2797         k++;
2798         C = s->rgb ? 0 : c;
2799         for (p = 0; p < s->ncomp; p++) {
2800             const int v = s->grat_yuva_color[p];
2801             for (l = 0; l < s->nb_glines; l++) {
2802                 const uint16_t pos = s->glines[l].line[C].pos;
2803                 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
2804                 uint8_t *dst = out->data[p] + offset_y * out->linesize[p] + x;
2805
2806                 s->blend_line(dst, height, out->linesize[p], o1, o2, v, step);
2807             }
2808         }
2809
2810         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2811             const char *name = s->glines[l].line[C].name;
2812             const uint16_t pos = s->glines[l].line[C].pos;
2813             int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
2814
2815             if (x < 0)
2816                 x = 4;
2817
2818             s->draw_text(out, x, offset_y + 2, 1, o1, o2, name, s->grat_yuva_color);
2819         }
2820
2821         offset_x += s->size * (s->display == STACK);
2822         offset_y += height * (s->display == PARADE);
2823     }
2824 }
2825
2826 static void graticule16_row(WaveformContext *s, AVFrame *out)
2827 {
2828     const int step = (s->flags & 2) + 1;
2829     const float o1 = s->opacity;
2830     const float o2 = 1. - o1;
2831     const int mult = s->max / 256;
2832     const int height = s->display == PARADE ? out->height / s->acomp : out->height;
2833     int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2834
2835     for (c = 0; c < s->ncomp; c++) {
2836         if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
2837             continue;
2838
2839         k++;
2840         C = s->rgb ? 0 : c;
2841         for (p = 0; p < s->ncomp; p++) {
2842             const int v = s->grat_yuva_color[p] * mult;
2843             for (l = 0; l < s->nb_glines ; l++) {
2844                 const uint16_t pos = s->glines[l].line[C].pos;
2845                 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
2846                 uint8_t *dst = (uint8_t *)(out->data[p] + offset_y * out->linesize[p]) + x * 2;
2847
2848                 s->blend_line(dst, height, out->linesize[p], o1, o2, v, step);
2849             }
2850         }
2851
2852         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2853             const char *name = s->glines[l].line[C].name;
2854             const uint16_t pos = s->glines[l].line[C].pos;
2855             int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
2856
2857             if (x < 0)
2858                 x = 4;
2859
2860             s->draw_text(out, x, offset_y + 2, mult, o1, o2, name, s->grat_yuva_color);
2861         }
2862
2863         offset_x += s->size * (s->display == STACK);
2864         offset_y += height * (s->display == PARADE);
2865     }
2866 }
2867
2868 static void graticule_column(WaveformContext *s, AVFrame *out)
2869 {
2870     const int step = (s->flags & 2) + 1;
2871     const float o1 = s->opacity;
2872     const float o2 = 1. - o1;
2873     const int width = s->display == PARADE ? out->width / s->acomp : out->width;
2874     int C, k = 0, c, p, l, offset_y = 0, offset_x = 0;
2875
2876     for (c = 0; c < s->ncomp; c++) {
2877         if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
2878             continue;
2879
2880         k++;
2881         C = s->rgb ? 0 : c;
2882         for (p = 0; p < s->ncomp; p++) {
2883             const int v = s->grat_yuva_color[p];
2884             for (l = 0; l < s->nb_glines ; l++) {
2885                 const uint16_t pos = s->glines[l].line[C].pos;
2886                 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
2887                 uint8_t *dst = out->data[p] + y * out->linesize[p] + offset_x;
2888
2889                 s->blend_line(dst, width, 1, o1, o2, v, step);
2890             }
2891         }
2892
2893         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2894             const char *name = s->glines[l].line[C].name;
2895             const uint16_t pos = s->glines[l].line[C].pos;
2896             int y = offset_y + (s->mirror ? s->size - 1 - pos : pos) - 10;
2897
2898             if (y < 0)
2899                 y = 4;
2900
2901             s->draw_text(out, 2 + offset_x, y, 1, o1, o2, name, s->grat_yuva_color);
2902         }
2903
2904         offset_y += s->size * (s->display == STACK);
2905         offset_x += width * (s->display == PARADE);
2906     }
2907 }
2908
2909 static void graticule16_column(WaveformContext *s, AVFrame *out)
2910 {
2911     const int step = (s->flags & 2) + 1;
2912     const float o1 = s->opacity;
2913     const float o2 = 1. - o1;
2914     const int mult = s->max / 256;
2915     const int width = s->display == PARADE ? out->width / s->acomp : out->width;
2916     int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2917
2918     for (c = 0; c < s->ncomp; c++) {
2919         if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
2920             continue;
2921
2922         k++;
2923         C = s->rgb ? 0 : c;
2924         for (p = 0; p < s->ncomp; p++) {
2925             const int v = s->grat_yuva_color[p] * mult;
2926             for (l = 0; l < s->nb_glines ; l++) {
2927                 const uint16_t pos = s->glines[l].line[C].pos;
2928                 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
2929                 uint8_t *dst = (uint8_t *)(out->data[p] + y * out->linesize[p]) + offset_x * 2;
2930
2931                 s->blend_line(dst, width, 1, o1, o2, v, step);
2932             }
2933         }
2934
2935         for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2936             const char *name = s->glines[l].line[C].name;
2937             const uint16_t pos = s->glines[l].line[C].pos;
2938             int y = offset_y + (s->mirror ? s->size - 1 - pos: pos) - 10;
2939
2940             if (y < 0)
2941                 y = 4;
2942
2943             s->draw_text(out, 2 + offset_x, y, mult, o1, o2, name, s->grat_yuva_color);
2944         }
2945
2946         offset_y += s->size * (s->display == STACK);
2947         offset_x += width * (s->display == PARADE);
2948     }
2949 }
2950
2951 static int config_input(AVFilterLink *inlink)
2952 {
2953     AVFilterContext *ctx = inlink->dst;
2954     WaveformContext *s = ctx->priv;
2955
2956     s->desc  = av_pix_fmt_desc_get(inlink->format);
2957     s->ncomp = s->desc->nb_components;
2958     s->bits = s->desc->comp[0].depth;
2959     s->max = 1 << s->bits;
2960     s->intensity = s->fintensity * (s->max - 1);
2961
2962     s->shift_w[0] = s->shift_w[3] = 0;
2963     s->shift_h[0] = s->shift_h[3] = 0;
2964     s->shift_w[1] = s->shift_w[2] = s->desc->log2_chroma_w;
2965     s->shift_h[1] = s->shift_h[2] = s->desc->log2_chroma_h;
2966
2967     s->graticulef = graticule_none;
2968
2969     switch (s->filter) {
2970     case XFLAT:
2971     case YFLAT:
2972     case AFLAT: s->size = 256 * 2; break;
2973     case FLAT:  s->size = 256 * 3; break;
2974     default:    s->size = 256;     break;
2975     }
2976
2977     switch (s->filter | ((s->bits > 8) << 4) |
2978             (s->mode << 8) | (s->mirror << 12)) {
2979     case 0x1100: s->waveform_slice = lowpass_column_mirror; break;
2980     case 0x1000: s->waveform_slice = lowpass_row_mirror;    break;
2981     case 0x0100: s->waveform_slice = lowpass_column;        break;
2982     case 0x0000: s->waveform_slice = lowpass_row;           break;
2983     case 0x1110: s->waveform_slice = lowpass16_column_mirror; break;
2984     case 0x1010: s->waveform_slice = lowpass16_row_mirror;    break;
2985     case 0x0110: s->waveform_slice = lowpass16_column;        break;
2986     case 0x0010: s->waveform_slice = lowpass16_row;           break;
2987     case 0x1101: s->waveform_slice = flat_column_mirror; break;
2988     case 0x1001: s->waveform_slice = flat_row_mirror;    break;
2989     case 0x0101: s->waveform_slice = flat_column;        break;
2990     case 0x0001: s->waveform_slice = flat_row;           break;
2991     case 0x1111: s->waveform_slice = flat16_column_mirror; break;
2992     case 0x1011: s->waveform_slice = flat16_row_mirror;    break;
2993     case 0x0111: s->waveform_slice = flat16_column;        break;
2994     case 0x0011: s->waveform_slice = flat16_row;           break;
2995     case 0x1102: s->waveform_slice = aflat_column_mirror; break;
2996     case 0x1002: s->waveform_slice = aflat_row_mirror;    break;
2997     case 0x0102: s->waveform_slice = aflat_column;        break;
2998     case 0x0002: s->waveform_slice = aflat_row;           break;
2999     case 0x1112: s->waveform_slice = aflat16_column_mirror; break;
3000     case 0x1012: s->waveform_slice = aflat16_row_mirror;    break;
3001     case 0x0112: s->waveform_slice = aflat16_column;        break;
3002     case 0x0012: s->waveform_slice = aflat16_row;           break;
3003     case 0x1103: s->waveform_slice = chroma_column_mirror; break;
3004     case 0x1003: s->waveform_slice = chroma_row_mirror;    break;
3005     case 0x0103: s->waveform_slice = chroma_column;        break;
3006     case 0x0003: s->waveform_slice = chroma_row;           break;
3007     case 0x1113: s->waveform_slice = chroma16_column_mirror; break;
3008     case 0x1013: s->waveform_slice = chroma16_row_mirror;    break;
3009     case 0x0113: s->waveform_slice = chroma16_column;        break;
3010     case 0x0013: s->waveform_slice = chroma16_row;           break;
3011     case 0x1104: s->waveform_slice = color_column_mirror; break;
3012     case 0x1004: s->waveform_slice = color_row_mirror;    break;
3013     case 0x0104: s->waveform_slice = color_column;        break;
3014     case 0x0004: s->waveform_slice = color_row;           break;
3015     case 0x1114: s->waveform_slice = color16_column_mirror; break;
3016     case 0x1014: s->waveform_slice = color16_row_mirror;    break;
3017     case 0x0114: s->waveform_slice = color16_column;        break;
3018     case 0x0014: s->waveform_slice = color16_row;           break;
3019     case 0x1105: s->waveform_slice = acolor_column_mirror; break;
3020     case 0x1005: s->waveform_slice = acolor_row_mirror;    break;
3021     case 0x0105: s->waveform_slice = acolor_column;        break;
3022     case 0x0005: s->waveform_slice = acolor_row;           break;
3023     case 0x1115: s->waveform_slice = acolor16_column_mirror; break;
3024     case 0x1015: s->waveform_slice = acolor16_row_mirror;    break;
3025     case 0x0115: s->waveform_slice = acolor16_column;        break;
3026     case 0x0015: s->waveform_slice = acolor16_row;           break;
3027     case 0x1106: s->waveform_slice = xflat_column_mirror; break;
3028     case 0x1006: s->waveform_slice = xflat_row_mirror;    break;
3029     case 0x0106: s->waveform_slice = xflat_column;        break;
3030     case 0x0006: s->waveform_slice = xflat_row;           break;
3031     case 0x1116: s->waveform_slice = xflat16_column_mirror; break;
3032     case 0x1016: s->waveform_slice = xflat16_row_mirror;    break;
3033     case 0x0116: s->waveform_slice = xflat16_column;        break;
3034     case 0x0016: s->waveform_slice = xflat16_row;           break;
3035     case 0x1107: s->waveform_slice = yflat_column_mirror; break;
3036     case 0x1007: s->waveform_slice = yflat_row_mirror;    break;
3037     case 0x0107: s->waveform_slice = yflat_column;        break;
3038     case 0x0007: s->waveform_slice = yflat_row;           break;
3039     case 0x1117: s->waveform_slice = yflat16_column_mirror; break;
3040     case 0x1017: s->waveform_slice = yflat16_row_mirror;    break;
3041     case 0x0117: s->waveform_slice = yflat16_column;        break;
3042     case 0x0017: s->waveform_slice = yflat16_row;           break;
3043     }
3044
3045     s->grat_yuva_color[0] = 255;
3046     s->grat_yuva_color[1] = s->graticule == GRAT_INVERT ? 255 : 0;
3047     s->grat_yuva_color[2] = s->graticule == GRAT_ORANGE || s->graticule == GRAT_INVERT ? 255 : 0;
3048     s->grat_yuva_color[3] = 255;
3049
3050     if (s->mode == 0 && s->graticule != GRAT_INVERT) {
3051         s->blend_line = s->bits <= 8 ? blend_vline : blend_vline16;
3052         s->draw_text  = s->bits <= 8 ? draw_vtext  : draw_vtext16;
3053     } else if (s->graticule != GRAT_INVERT) {
3054         s->blend_line = s->bits <= 8 ? blend_hline : blend_hline16;
3055         s->draw_text  = s->bits <= 8 ? draw_htext  : draw_htext16;
3056     } else if (s->mode == 0 && s->graticule == GRAT_INVERT) {
3057         s->blend_line = s->bits <= 8 ? iblend_vline : iblend_vline16;
3058         s->draw_text  = s->bits <= 8 ? idraw_vtext  : idraw_vtext16;
3059     } else if (s->graticule == GRAT_INVERT) {
3060         s->blend_line = s->bits <= 8 ? iblend_hline : iblend_hline16;
3061         s->draw_text  = s->bits <= 8 ? idraw_htext  : idraw_htext16;
3062     }
3063
3064     switch (s->filter) {
3065     case LOWPASS:
3066     case COLOR:
3067     case ACOLOR:
3068     case CHROMA:
3069     case AFLAT:
3070     case XFLAT:
3071     case YFLAT:
3072     case FLAT:
3073         if (s->graticule > GRAT_NONE && s->mode == 1)
3074             s->graticulef = s->bits > 8 ? graticule16_column : graticule_column;
3075         else if (s->graticule > GRAT_NONE && s->mode == 0)
3076             s->graticulef = s->bits > 8 ? graticule16_row : graticule_row;
3077         break;
3078     }
3079
3080     switch (s->filter) {
3081     case COLOR:
3082     case ACOLOR:
3083     case LOWPASS:
3084         switch (s->scale) {
3085         case DIGITAL:
3086             switch (s->bits) {
3087             case  8: s->glines = (GraticuleLines *)digital8;  s->nb_glines = FF_ARRAY_ELEMS(digital8);  break;
3088             case  9: s->glines = (GraticuleLines *)digital9;  s->nb_glines = FF_ARRAY_ELEMS(digital9);  break;
3089             case 10: s->glines = (GraticuleLines *)digital10; s->nb_glines = FF_ARRAY_ELEMS(digital10); break;
3090             case 12: s->glines = (GraticuleLines *)digital12; s->nb_glines = FF_ARRAY_ELEMS(digital12); break;
3091             }
3092             break;
3093         case MILLIVOLTS:
3094             switch (s->bits) {
3095             case  8: s->glines = (GraticuleLines *)millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(millivolts8);  break;
3096             case  9: s->glines = (GraticuleLines *)millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(millivolts9);  break;
3097             case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
3098             case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
3099             }
3100             break;
3101         case IRE:
3102             switch (s->bits) {
3103             case  8: s->glines = (GraticuleLines *)ire8;  s->nb_glines = FF_ARRAY_ELEMS(ire8);  break;
3104             case  9: s->glines = (GraticuleLines *)ire9;  s->nb_glines = FF_ARRAY_ELEMS(ire9);  break;
3105             case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
3106             case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
3107             }
3108             break;
3109         }
3110         break;
3111     case CHROMA:
3112         switch (s->scale) {
3113         case DIGITAL:
3114             switch (s->bits) {
3115             case  8: s->glines = (GraticuleLines *)chroma_digital8;  s->nb_glines = FF_ARRAY_ELEMS(chroma_digital8);  break;
3116             case  9: s->glines = (GraticuleLines *)chroma_digital9;  s->nb_glines = FF_ARRAY_ELEMS(chroma_digital9);  break;
3117             case 10: s->glines = (GraticuleLines *)chroma_digital10; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital10); break;
3118             case 12: s->glines = (GraticuleLines *)chroma_digital12; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital12); break;
3119             }
3120             break;
3121         case MILLIVOLTS:
3122             switch (s->bits) {
3123             case  8: s->glines = (GraticuleLines *)millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(millivolts8);  break;
3124             case  9: s->glines = (GraticuleLines *)millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(millivolts9);  break;
3125             case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
3126             case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
3127             }
3128             break;
3129         case IRE:
3130             switch (s->bits) {
3131             case  8: s->glines = (GraticuleLines *)ire8;  s->nb_glines = FF_ARRAY_ELEMS(ire8);  break;
3132             case  9: s->glines = (GraticuleLines *)ire9;  s->nb_glines = FF_ARRAY_ELEMS(ire9);  break;
3133             case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
3134             case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
3135             }
3136             break;
3137         }
3138         break;
3139     case XFLAT:
3140     case YFLAT:
3141     case AFLAT:
3142         switch (s->scale) {
3143         case DIGITAL:
3144             switch (s->bits) {
3145             case  8: s->glines = (GraticuleLines *)aflat_digital8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_digital8);  break;
3146             case  9: s->glines = (GraticuleLines *)aflat_digital9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_digital9);  break;
3147             case 10: s->glines = (GraticuleLines *)aflat_digital10; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital10); break;
3148             case 12: s->glines = (GraticuleLines *)aflat_digital12; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital12); break;
3149             }
3150             break;
3151         case MILLIVOLTS:
3152             switch (s->bits) {
3153             case  8: s->glines = (GraticuleLines *)aflat_millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts8);  break;
3154             case  9: s->glines = (GraticuleLines *)aflat_millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts9);  break;
3155             case 10: s->glines = (GraticuleLines *)aflat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts10); break;
3156             case 12: s->glines = (GraticuleLines *)aflat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts12); break;
3157             }
3158             break;
3159         case IRE:
3160             switch (s->bits) {
3161             case  8: s->glines = (GraticuleLines *)aflat_ire8;  s->nb_glines = FF_ARRAY_ELEMS(aflat_ire8);  break;
3162             case  9: s->glines = (GraticuleLines *)aflat_ire9;  s->nb_glines = FF_ARRAY_ELEMS(aflat_ire9);  break;
3163             case 10: s->glines = (GraticuleLines *)aflat_ire10; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire10); break;
3164             case 12: s->glines = (GraticuleLines *)aflat_ire12; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire12); break;
3165             }
3166             break;
3167         }
3168         break;
3169     case FLAT:
3170         switch (s->scale) {
3171         case DIGITAL:
3172             switch (s->bits) {
3173             case  8: s->glines = (GraticuleLines *)flat_digital8;  s->nb_glines = FF_ARRAY_ELEMS(flat_digital8);  break;
3174             case  9: s->glines = (GraticuleLines *)flat_digital9;  s->nb_glines = FF_ARRAY_ELEMS(flat_digital9);  break;
3175             case 10: s->glines = (GraticuleLines *)flat_digital10; s->nb_glines = FF_ARRAY_ELEMS(flat_digital10); break;
3176             case 12: s->glines = (GraticuleLines *)flat_digital12; s->nb_glines = FF_ARRAY_ELEMS(flat_digital12); break;
3177             }
3178             break;
3179         case MILLIVOLTS:
3180             switch (s->bits) {
3181             case  8: s->glines = (GraticuleLines *)flat_millivolts8;  s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts8);  break;
3182             case  9: s->glines = (GraticuleLines *)flat_millivolts9;  s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts9);  break;
3183             case 10: s->glines = (GraticuleLines *)flat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts10); break;
3184             case 12: s->glines = (GraticuleLines *)flat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts12); break;
3185             }
3186             break;
3187         case IRE:
3188             switch (s->bits) {
3189             case  8: s->glines = (GraticuleLines *)flat_ire8;  s->nb_glines = FF_ARRAY_ELEMS(flat_ire8);  break;
3190             case  9: s->glines = (GraticuleLines *)flat_ire9;  s->nb_glines = FF_ARRAY_ELEMS(flat_ire9);  break;
3191             case 10: s->glines = (GraticuleLines *)flat_ire10; s->nb_glines = FF_ARRAY_ELEMS(flat_ire10); break;
3192             case 12: s->glines = (GraticuleLines *)flat_ire12; s->nb_glines = FF_ARRAY_ELEMS(flat_ire12); break;
3193             }
3194             break;
3195         }
3196         break;
3197     }
3198
3199     s->size = s->size << (s->bits - 8);
3200
3201     switch (inlink->format) {
3202     case AV_PIX_FMT_GBRAP:
3203     case AV_PIX_FMT_GBRP:
3204     case AV_PIX_FMT_GBRP9:
3205     case AV_PIX_FMT_GBRP10:
3206     case AV_PIX_FMT_GBRP12:
3207         s->rgb = 1;
3208         memcpy(s->bg_color, black_gbrp_color, sizeof(s->bg_color));
3209         break;
3210     default:
3211         memcpy(s->bg_color, black_yuva_color, sizeof(s->bg_color));
3212     }
3213
3214     s->bg_color[3] *= s->bgopacity;
3215
3216     return 0;
3217 }
3218
3219 static int config_output(AVFilterLink *outlink)
3220 {
3221     AVFilterContext *ctx = outlink->src;
3222     AVFilterLink *inlink = ctx->inputs[0];
3223     WaveformContext *s = ctx->priv;
3224     int comp = 0, i, j = 0, k, p, size;
3225
3226     for (i = 0; i < s->ncomp; i++) {
3227         if ((1 << i) & s->pcomp)
3228             comp++;
3229     }
3230     s->acomp = comp;
3231     if (s->acomp == 0)
3232         return AVERROR(EINVAL);
3233
3234     s->odesc = av_pix_fmt_desc_get(outlink->format);
3235     s->dcomp = s->odesc->nb_components;
3236
3237     av_freep(&s->peak);
3238
3239     if (s->mode) {
3240         outlink->h = s->size * FFMAX(comp * (s->display == STACK), 1);
3241         outlink->w = inlink->w * FFMAX(comp * (s->display == PARADE), 1);
3242         size = inlink->w;
3243     } else {
3244         outlink->w = s->size * FFMAX(comp * (s->display == STACK), 1);
3245         outlink->h = inlink->h * FFMAX(comp * (s->display == PARADE), 1);
3246         size = inlink->h;
3247     }
3248
3249     s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
3250     if (!s->peak)
3251         return AVERROR(ENOMEM);
3252
3253     for (p = 0; p < s->ncomp; p++) {
3254         const int plane = s->desc->comp[p].plane;
3255         int offset;
3256
3257         if (!((1 << p) & s->pcomp))
3258             continue;
3259
3260         for (k = 0; k < 4; k++) {
3261             s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
3262             s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
3263         }
3264
3265         offset = j++ * s->size * (s->display == STACK);
3266         s->estart[plane] = offset;
3267         s->eend[plane]   = (offset + s->size - 1);
3268         for (i = 0; i < size; i++) {
3269             for (k = 0; k < 4; k++) {
3270                 s->emax[plane][k][i] = s->estart[plane];
3271                 s->emin[plane][k][i] = s->eend[plane];
3272             }
3273         }
3274     }
3275
3276     outlink->sample_aspect_ratio = (AVRational){1,1};
3277
3278     return 0;
3279 }
3280
3281 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
3282 {
3283     AVFilterContext *ctx  = inlink->dst;
3284     WaveformContext *s    = ctx->priv;
3285     AVFilterLink *outlink = ctx->outputs[0];
3286     AVFrame *out;
3287     int i, j, k;
3288
3289     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
3290     if (!out) {
3291         av_frame_free(&in);
3292         return AVERROR(ENOMEM);
3293     }
3294     out->pts = in->pts;
3295     out->color_range = AVCOL_RANGE_JPEG;
3296
3297     for (k = 0; k < s->dcomp; k++) {
3298         if (s->bits <= 8) {
3299             for (i = 0; i < outlink->h ; i++)
3300                 memset(out->data[s->odesc->comp[k].plane] +
3301                        i * out->linesize[s->odesc->comp[k].plane],
3302                        s->bg_color[k], outlink->w);
3303         } else {
3304             const int mult = s->max / 256;
3305             uint16_t *dst = (uint16_t *)out->data[s->odesc->comp[k].plane];
3306
3307             for (i = 0; i < outlink->h ; i++) {
3308                 for (j = 0; j < outlink->w; j++)
3309                     dst[j] = s->bg_color[k] * mult;
3310                 dst += out->linesize[s->odesc->comp[k].plane] / 2;
3311             }
3312         }
3313     }
3314
3315     for (k = 0, i = 0; k < s->ncomp; k++) {
3316         if ((1 << k) & s->pcomp) {
3317             const int plane = s->desc->comp[k].plane;
3318             ThreadData td;
3319             int offset_y;
3320             int offset_x;
3321
3322             if (s->display == PARADE) {
3323                 offset_x = s->mode ? i++ * inlink->w : 0;
3324                 offset_y = s->mode ? 0 : i++ * inlink->h;
3325             } else {
3326                 offset_y = s->mode ? i++ * s->size * !!s->display : 0;
3327                 offset_x = s->mode ? 0 : i++ * s->size * !!s->display;
3328             }
3329
3330             td.in = in;
3331             td.out = out;
3332             td.component = k;
3333             td.offset_y = offset_y;
3334             td.offset_x = offset_x;
3335             ctx->internal->execute(ctx, s->waveform_slice, &td, NULL, ff_filter_get_nb_threads(ctx));
3336             switch (s->filter) {
3337             case ACOLOR:
3338             case CHROMA:
3339             case COLOR:
3340             case LOWPASS:
3341                 if (s->bits <= 8)
3342                     envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
3343                 else
3344                     envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
3345                 break;
3346             case FLAT:
3347                 if (s->bits <= 8) {
3348                     envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
3349                     envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3350                 } else {
3351                     envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
3352                     envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3353                 }
3354                 break;
3355             case AFLAT:
3356             case XFLAT:
3357             case YFLAT:
3358                 if (s->bits <= 8) {
3359                     envelope(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
3360                     envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3361                     envelope(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
3362                 } else {
3363                     envelope16(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
3364                     envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3365                     envelope16(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
3366                 }
3367                 break;
3368             }
3369         }
3370     }
3371     s->graticulef(s, out);
3372
3373     av_frame_free(&in);
3374     return ff_filter_frame(outlink, out);
3375 }
3376
3377 static av_cold void uninit(AVFilterContext *ctx)
3378 {
3379     WaveformContext *s = ctx->priv;
3380
3381     av_freep(&s->peak);
3382 }
3383
3384 static const AVFilterPad inputs[] = {
3385     {
3386         .name         = "default",
3387         .type         = AVMEDIA_TYPE_VIDEO,
3388         .filter_frame = filter_frame,
3389         .config_props = config_input,
3390     },
3391     { NULL }
3392 };
3393
3394 static const AVFilterPad outputs[] = {
3395     {
3396         .name         = "default",
3397         .type         = AVMEDIA_TYPE_VIDEO,
3398         .config_props = config_output,
3399     },
3400     { NULL }
3401 };
3402
3403 AVFilter ff_vf_waveform = {
3404     .name          = "waveform",
3405     .description   = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
3406     .priv_size     = sizeof(WaveformContext),
3407     .priv_class    = &waveform_class,
3408     .query_formats = query_formats,
3409     .uninit        = uninit,
3410     .inputs        = inputs,
3411     .outputs       = outputs,
3412     .flags         = AVFILTER_FLAG_SLICE_THREADS,
3413 };