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