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