d384258b834236446907d715626b0b10523358f4
[ffmpeg.git] / libavfilter / vf_waveform.c
1 /*
2  * Copyright (c) 2012-2015 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 "avfilter.h"
27 #include "formats.h"
28 #include "internal.h"
29 #include "video.h"
30
31 enum FilterType {
32     LOWPASS,
33     FLAT,
34     AFLAT,
35     CHROMA,
36     ACHROMA,
37     COLOR,
38     NB_FILTERS
39 };
40
41 typedef struct WaveformContext {
42     const AVClass *class;
43     int            mode;
44     int            ncomp;
45     int            pcomp;
46     const uint8_t  *bg_color;
47     float          fintensity;
48     int            intensity;
49     int            mirror;
50     int            display;
51     int            envelope;
52     int            estart[4];
53     int            eend[4];
54     int            *emax[4][4];
55     int            *emin[4][4];
56     int            *peak;
57     int            filter;
58     int            bits;
59     int            max;
60     int            size;
61     void (*waveform)(struct WaveformContext *s, AVFrame *in, AVFrame *out,
62                      int component, int intensity, int offset, int column);
63     const AVPixFmtDescriptor *desc;
64 } WaveformContext;
65
66 #define OFFSET(x) offsetof(WaveformContext, x)
67 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
68
69 static const AVOption waveform_options[] = {
70     { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
71     { "m",    "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
72         { "row",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
73         { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
74     { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
75     { "i",         "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
76     { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
77     { "r",      "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
78     { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display" },
79     { "d",       "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display" },
80         { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "display" },
81         { "parade",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "display" },
82     { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
83     { "c",          "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
84     { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
85     { "e",        "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
86         { "none",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
87         { "instant",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
88         { "peak",         NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
89         { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
90     { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
91     { "f",      "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
92         { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, "filter" },
93         { "flat"   , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT},    0, 0, FLAGS, "filter" },
94         { "aflat"  , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT},   0, 0, FLAGS, "filter" },
95         { "chroma",  NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA},  0, 0, FLAGS, "filter" },
96         { "achroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACHROMA}, 0, 0, FLAGS, "filter" },
97         { "color",   NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR},   0, 0, FLAGS, "filter" },
98     { NULL }
99 };
100
101 AVFILTER_DEFINE_CLASS(waveform);
102
103 static const enum AVPixelFormat lowpass_pix_fmts[] = {
104     AV_PIX_FMT_GBRP,     AV_PIX_FMT_GBRAP,
105     AV_PIX_FMT_GBRP9,    AV_PIX_FMT_GBRP10,
106     AV_PIX_FMT_YUV422P,  AV_PIX_FMT_YUV420P,
107     AV_PIX_FMT_YUV444P,  AV_PIX_FMT_YUV440P,
108     AV_PIX_FMT_YUV411P,  AV_PIX_FMT_YUV410P,
109     AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
110     AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
111     AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
112     AV_PIX_FMT_GRAY8,
113     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
114     AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
115     AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
116     AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
117     AV_PIX_FMT_NONE
118 };
119
120 static const enum AVPixelFormat flat_pix_fmts[] = {
121     AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE
122 };
123
124 static const enum AVPixelFormat color_pix_fmts[] = {
125     AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
126     AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
127     AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
128     AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
129     AV_PIX_FMT_NONE
130 };
131
132 static int query_formats(AVFilterContext *ctx)
133 {
134     WaveformContext *s = ctx->priv;
135     AVFilterFormats *fmts_list;
136     const enum AVPixelFormat *pix_fmts;
137
138     switch (s->filter) {
139     case LOWPASS: pix_fmts = lowpass_pix_fmts; break;
140     case FLAT:
141     case AFLAT:
142     case CHROMA:
143     case ACHROMA: pix_fmts = flat_pix_fmts;    break;
144     case COLOR:   pix_fmts = color_pix_fmts;   break;
145     }
146
147     fmts_list = ff_make_format_list(pix_fmts);
148     if (!fmts_list)
149         return AVERROR(ENOMEM);
150     return ff_set_common_formats(ctx, fmts_list);
151 }
152
153 static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component)
154 {
155     const int dst_linesize = out->linesize[component] / 2;
156     const int bg = s->bg_color[component] * (s->max / 256);
157     const int limit = s->max - 1;
158     const int is_chroma = (component == 1 || component == 2);
159     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
160     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
161     const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
162     const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
163     const int start = s->estart[plane];
164     const int end = s->eend[plane];
165     uint16_t *dst;
166     int x, y;
167
168     if (s->mode) {
169         for (x = 0; x < dst_w; x++) {
170             for (y = start; y < end; y++) {
171                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
172                 if (dst[0] != bg) {
173                     dst[0] = limit;
174                     break;
175                 }
176             }
177             for (y = end - 1; y >= start; y--) {
178                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
179                 if (dst[0] != bg) {
180                     dst[0] = limit;
181                     break;
182                 }
183             }
184         }
185     } else {
186         for (y = 0; y < dst_h; y++) {
187             dst = (uint16_t *)out->data[component] + y * dst_linesize;
188             for (x = start; x < end; x++) {
189                 if (dst[x] != bg) {
190                     dst[x] = limit;
191                     break;
192                 }
193             }
194             for (x = end - 1; x >= start; x--) {
195                 if (dst[x] != bg) {
196                     dst[x] = limit;
197                     break;
198                 }
199             }
200         }
201     }
202 }
203
204 static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component)
205 {
206     const int dst_linesize = out->linesize[component];
207     const uint8_t bg = s->bg_color[component];
208     const int is_chroma = (component == 1 || component == 2);
209     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
210     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
211     const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
212     const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
213     const int start = s->estart[plane];
214     const int end = s->eend[plane];
215     uint8_t *dst;
216     int x, y;
217
218     if (s->mode) {
219         for (x = 0; x < dst_w; x++) {
220             for (y = start; y < end; y++) {
221                 dst = out->data[component] + y * dst_linesize + x;
222                 if (dst[0] != bg) {
223                     dst[0] = 255;
224                     break;
225                 }
226             }
227             for (y = end - 1; y >= start; y--) {
228                 dst = out->data[component] + y * dst_linesize + x;
229                 if (dst[0] != bg) {
230                     dst[0] = 255;
231                     break;
232                 }
233             }
234         }
235     } else {
236         for (y = 0; y < dst_h; y++) {
237             dst = out->data[component] + y * dst_linesize;
238             for (x = start; x < end; x++) {
239                 if (dst[x] != bg) {
240                     dst[x] = 255;
241                     break;
242                 }
243             }
244             for (x = end - 1; x >= start; x--) {
245                 if (dst[x] != bg) {
246                     dst[x] = 255;
247                     break;
248                 }
249             }
250         }
251     }
252 }
253
254 static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component)
255 {
256     const int dst_linesize = out->linesize[component] / 2;
257     const int bg = s->bg_color[component] * (s->max / 256);
258     const int limit = s->max - 1;
259     const int is_chroma = (component == 1 || component == 2);
260     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
261     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
262     const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
263     const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
264     const int start = s->estart[plane];
265     const int end = s->eend[plane];
266     int *emax = s->emax[plane][component];
267     int *emin = s->emin[plane][component];
268     uint16_t *dst;
269     int x, y;
270
271     if (s->mode) {
272         for (x = 0; x < dst_w; x++) {
273             for (y = start; y < end && y < emin[x]; y++) {
274                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
275                 if (dst[0] != bg) {
276                     emin[x] = y;
277                     break;
278                 }
279             }
280             for (y = end - 1; y >= start && y >= emax[x]; y--) {
281                 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
282                 if (dst[0] != bg) {
283                     emax[x] = y;
284                     break;
285                 }
286             }
287         }
288
289         if (s->envelope == 3)
290             envelope_instant16(s, out, plane, component);
291
292         for (x = 0; x < dst_w; x++) {
293             dst = (uint16_t *)out->data[component] + emin[x] * dst_linesize + x;
294             dst[0] = limit;
295             dst = (uint16_t *)out->data[component] + emax[x] * dst_linesize + x;
296             dst[0] = limit;
297         }
298     } else {
299         for (y = 0; y < dst_h; y++) {
300             dst = (uint16_t *)out->data[component] + y * dst_linesize;
301             for (x = start; x < end && x < emin[y]; x++) {
302                 if (dst[x] != bg) {
303                     emin[y] = x;
304                     break;
305                 }
306             }
307             for (x = end - 1; x >= start && x >= emax[y]; x--) {
308                 if (dst[x] != bg) {
309                     emax[y] = x;
310                     break;
311                 }
312             }
313         }
314
315         if (s->envelope == 3)
316             envelope_instant16(s, out, plane, component);
317
318         for (y = 0; y < dst_h; y++) {
319             dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y];
320             dst[0] = limit;
321             dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y];
322             dst[0] = limit;
323         }
324     }
325 }
326
327 static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component)
328 {
329     const int dst_linesize = out->linesize[component];
330     const int bg = s->bg_color[component];
331     const int is_chroma = (component == 1 || component == 2);
332     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
333     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
334     const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
335     const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
336     const int start = s->estart[plane];
337     const int end = s->eend[plane];
338     int *emax = s->emax[plane][component];
339     int *emin = s->emin[plane][component];
340     uint8_t *dst;
341     int x, y;
342
343     if (s->mode) {
344         for (x = 0; x < dst_w; x++) {
345             for (y = start; y < end && y < emin[x]; y++) {
346                 dst = out->data[component] + y * dst_linesize + x;
347                 if (dst[0] != bg) {
348                     emin[x] = y;
349                     break;
350                 }
351             }
352             for (y = end - 1; y >= start && y >= emax[x]; y--) {
353                 dst = out->data[component] + y * dst_linesize + x;
354                 if (dst[0] != bg) {
355                     emax[x] = y;
356                     break;
357                 }
358             }
359         }
360
361         if (s->envelope == 3)
362             envelope_instant(s, out, plane, component);
363
364         for (x = 0; x < dst_w; x++) {
365             dst = out->data[component] + emin[x] * dst_linesize + x;
366             dst[0] = 255;
367             dst = out->data[component] + emax[x] * dst_linesize + x;
368             dst[0] = 255;
369         }
370     } else {
371         for (y = 0; y < dst_h; y++) {
372             dst = out->data[component] + y * dst_linesize;
373             for (x = start; x < end && x < emin[y]; x++) {
374                 if (dst[x] != bg) {
375                     emin[y] = x;
376                     break;
377                 }
378             }
379             for (x = end - 1; x >= start && x >= emax[y]; x--) {
380                 if (dst[x] != bg) {
381                     emax[y] = x;
382                     break;
383                 }
384             }
385         }
386
387         if (s->envelope == 3)
388             envelope_instant(s, out, plane, component);
389
390         for (y = 0; y < dst_h; y++) {
391             dst = out->data[component] + y * dst_linesize + emin[y];
392             dst[0] = 255;
393             dst = out->data[component] + y * dst_linesize + emax[y];
394             dst[0] = 255;
395         }
396     }
397 }
398
399 static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component)
400 {
401     if (s->envelope == 0) {
402         return;
403     } else if (s->envelope == 1) {
404         envelope_instant16(s, out, plane, component);
405     } else {
406         envelope_peak16(s, out, plane, component);
407     }
408 }
409
410 static void envelope(WaveformContext *s, AVFrame *out, int plane, int component)
411 {
412     if (s->envelope == 0) {
413         return;
414     } else if (s->envelope == 1) {
415         envelope_instant(s, out, plane, component);
416     } else {
417         envelope_peak(s, out, plane, component);
418     }
419 }
420
421 static void update16(uint16_t *target, int max, int intensity, int limit)
422 {
423     if (*target <= max)
424         *target += intensity;
425     else
426         *target = limit;
427 }
428
429 static void update(uint8_t *target, int max, int intensity)
430 {
431     if (*target <= max)
432         *target += intensity;
433     else
434         *target = 255;
435 }
436
437 static void lowpass16(WaveformContext *s, AVFrame *in, AVFrame *out,
438                       int component, int intensity, int offset, int column)
439 {
440     const int plane = s->desc->comp[component].plane;
441     const int mirror = s->mirror;
442     const int is_chroma = (component == 1 || component == 2);
443     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
444     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
445     const int src_linesize = in->linesize[plane] / 2;
446     const int dst_linesize = out->linesize[plane] / 2;
447     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
448     const int limit = s->max - 1;
449     const int max = limit - intensity;
450     const int src_h = FF_CEIL_RSHIFT(in->height, shift_h);
451     const int src_w = FF_CEIL_RSHIFT(in->width, shift_w);
452     const uint16_t *src_data = (const uint16_t *)in->data[plane];
453     uint16_t *dst_data = (uint16_t *)out->data[plane] + (column ? (offset >> shift_h) * dst_linesize : offset >> shift_w);
454     uint16_t * const dst_bottom_line = dst_data + dst_linesize * ((s->size >> shift_h) - 1);
455     uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
456     const uint16_t *p;
457     int y;
458
459     if (!column && mirror)
460         dst_data += s->size >> shift_w;
461
462     for (y = 0; y < src_h; y++) {
463         const uint16_t *src_data_end = src_data + src_w;
464         uint16_t *dst = dst_line;
465
466         for (p = src_data; p < src_data_end; p++) {
467             uint16_t *target;
468             int v = FFMIN(*p, limit);
469
470             if (column) {
471                 target = dst++ + dst_signed_linesize * (v >> shift_h);
472             } else {
473                 if (mirror)
474                     target = dst_data - (v >> shift_w) - 1;
475                 else
476                     target = dst_data + (v >> shift_w);
477             }
478             update16(target, max, intensity, limit);
479         }
480         src_data += src_linesize;
481         dst_data += dst_linesize;
482     }
483
484     envelope16(s, out, plane, plane);
485 }
486
487 static void lowpass(WaveformContext *s, AVFrame *in, AVFrame *out,
488                     int component, int intensity, int offset, int column)
489 {
490     const int plane = s->desc->comp[component].plane;
491     const int mirror = s->mirror;
492     const int is_chroma = (component == 1 || component == 2);
493     const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
494     const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
495     const int src_linesize = in->linesize[plane];
496     const int dst_linesize = out->linesize[plane];
497     const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
498     const int max = 255 - intensity;
499     const int src_h = FF_CEIL_RSHIFT(in->height, shift_h);
500     const int src_w = FF_CEIL_RSHIFT(in->width, shift_w);
501     const uint8_t *src_data = in->data[plane];
502     uint8_t *dst_data = out->data[plane] + (column ? (offset >> shift_h) * dst_linesize : offset >> shift_w);
503     uint8_t * const dst_bottom_line = dst_data + dst_linesize * ((s->size >> shift_h) - 1);
504     uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
505     const uint8_t *p;
506     int y;
507
508     if (!column && mirror)
509         dst_data += s->size >> shift_w;
510
511     for (y = 0; y < src_h; y++) {
512         const uint8_t *src_data_end = src_data + src_w;
513         uint8_t *dst = dst_line;
514
515         for (p = src_data; p < src_data_end; p++) {
516             uint8_t *target;
517             if (column) {
518                 target = dst++ + dst_signed_linesize * (*p >> shift_h);
519             } else {
520                 if (mirror)
521                     target = dst_data - (*p >> shift_w) - 1;
522                 else
523                     target = dst_data + (*p >> shift_w);
524             }
525             update(target, max, intensity);
526         }
527         src_data += src_linesize;
528         dst_data += dst_linesize;
529     }
530
531     envelope(s, out, plane, plane);
532 }
533
534 static void flat(WaveformContext *s, AVFrame *in, AVFrame *out,
535                  int component, int intensity, int offset, int column)
536 {
537     const int plane = s->desc->comp[component].plane;
538     const int mirror = s->mirror;
539     const int c0_linesize = in->linesize[ plane + 0 ];
540     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
541     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
542     const int d0_linesize = out->linesize[ plane + 0 ];
543     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
544     const int max = 255 - intensity;
545     const int src_h = in->height;
546     const int src_w = in->width;
547     int x, y;
548
549     if (column) {
550         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
551         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
552
553         for (x = 0; x < src_w; x++) {
554             const uint8_t *c0_data = in->data[plane + 0];
555             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
556             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
557             uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
558             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
559             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
560             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
561             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
562             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
563
564             for (y = 0; y < src_h; y++) {
565                 const int c0 = c0_data[x] + 256;
566                 const int c1 = FFABS(c1_data[x] - 128) + FFABS(c2_data[x] - 128);
567                 uint8_t *target;
568
569                 target = d0 + x + d0_signed_linesize * c0;
570                 update(target, max, intensity);
571                 target = d1 + x + d1_signed_linesize * (c0 - c1);
572                 update(target, max, 1);
573                 target = d1 + x + d1_signed_linesize * (c0 + c1);
574                 update(target, max, 1);
575
576                 c0_data += c0_linesize;
577                 c1_data += c1_linesize;
578                 c2_data += c2_linesize;
579                 d0_data += d0_linesize;
580                 d1_data += d1_linesize;
581             }
582         }
583     } else {
584         const uint8_t *c0_data = in->data[plane];
585         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
586         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
587         uint8_t *d0_data = out->data[plane] + offset;
588         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
589
590         if (mirror) {
591             d0_data += s->size - 1;
592             d1_data += s->size - 1;
593         }
594
595         for (y = 0; y < src_h; y++) {
596             for (x = 0; x < src_w; x++) {
597                 int c0 = c0_data[x] + 256;
598                 const int c1 = FFABS(c1_data[x] - 128) + FFABS(c2_data[x] - 128);
599                 uint8_t *target;
600
601                 if (mirror) {
602                     target = d0_data - c0;
603                     update(target, max, intensity);
604                     target = d1_data - (c0 - c1);
605                     update(target, max, 1);
606                     target = d1_data - (c0 + c1);
607                     update(target, max, 1);
608                 } else {
609                     target = d0_data + c0;
610                     update(target, max, intensity);
611                     target = d1_data + (c0 - c1);
612                     update(target, max, 1);
613                     target = d1_data + (c0 + c1);
614                     update(target, max, 1);
615                 }
616             }
617
618             c0_data += c0_linesize;
619             c1_data += c1_linesize;
620             c2_data += c2_linesize;
621             d0_data += d0_linesize;
622             d1_data += d1_linesize;
623         }
624     }
625
626     envelope(s, out, plane, plane);
627     envelope(s, out, plane, (plane + 1) % s->ncomp);
628 }
629
630 static void aflat(WaveformContext *s, AVFrame *in, AVFrame *out,
631                   int component, int intensity, int offset, int column)
632 {
633     const int plane = s->desc->comp[component].plane;
634     const int mirror = s->mirror;
635     const int c0_linesize = in->linesize[ plane + 0 ];
636     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
637     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
638     const int d0_linesize = out->linesize[ plane + 0 ];
639     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
640     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
641     const int max = 255 - intensity;
642     const int src_h = in->height;
643     const int src_w = in->width;
644     int x, y;
645
646     if (column) {
647         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
648         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
649         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
650
651         for (x = 0; x < src_w; x++) {
652             const uint8_t *c0_data = in->data[plane + 0];
653             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
654             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
655             uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
656             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
657             uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
658             uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
659             uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
660             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
661             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
662             uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
663             uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
664
665             for (y = 0; y < src_h; y++) {
666                 const int c0 = c0_data[x] + 128;
667                 const int c1 = c1_data[x] - 128;
668                 const int c2 = c2_data[x] - 128;
669                 uint8_t *target;
670
671                 target = d0 + x + d0_signed_linesize * c0;
672                 update(target, max, intensity);
673
674                 target = d1 + x + d1_signed_linesize * (c0 + c1);
675                 update(target, max, 1);
676
677                 target = d2 + x + d2_signed_linesize * (c0 + c2);
678                 update(target, max, 1);
679
680                 c0_data += c0_linesize;
681                 c1_data += c1_linesize;
682                 c2_data += c2_linesize;
683                 d0_data += d0_linesize;
684                 d1_data += d1_linesize;
685                 d2_data += d2_linesize;
686             }
687         }
688     } else {
689         const uint8_t *c0_data = in->data[plane];
690         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
691         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
692         uint8_t *d0_data = out->data[plane] + offset;
693         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
694         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
695
696         if (mirror) {
697             d0_data += s->size - 1;
698             d1_data += s->size - 1;
699             d2_data += s->size - 1;
700         }
701
702         for (y = 0; y < src_h; y++) {
703             for (x = 0; x < src_w; x++) {
704                 const int c0 = c0_data[x] + 128;
705                 const int c1 = c1_data[x] - 128;
706                 const int c2 = c2_data[x] - 128;
707                 uint8_t *target;
708
709                 if (mirror) {
710                     target = d0_data - c0;
711                     update(target, max, intensity);
712                     target = d1_data - (c0 + c1);
713                     update(target, max, 1);
714                     target = d2_data - (c0 + c2);
715                     update(target, max, 1);
716                 } else {
717                     target = d0_data + c0;
718                     update(target, max, intensity);
719                     target = d1_data + (c0 + c1);
720                     update(target, max, 1);
721                     target = d2_data + (c0 + c2);
722                     update(target, max, 1);
723                 }
724             }
725
726             c0_data += c0_linesize;
727             c1_data += c1_linesize;
728             c2_data += c2_linesize;
729             d0_data += d0_linesize;
730             d1_data += d1_linesize;
731             d2_data += d2_linesize;
732         }
733     }
734
735     envelope(s, out, plane, (plane + 0) % s->ncomp);
736     envelope(s, out, plane, (plane + 1) % s->ncomp);
737     envelope(s, out, plane, (plane + 2) % s->ncomp);
738 }
739
740 static void chroma(WaveformContext *s, AVFrame *in, AVFrame *out,
741                    int component, int intensity, int offset, int column)
742 {
743     const int plane = s->desc->comp[component].plane;
744     const int mirror = s->mirror;
745     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
746     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
747     const int dst_linesize = out->linesize[plane];
748     const int max = 255 - intensity;
749     const int src_h = in->height;
750     const int src_w = in->width;
751     int x, y;
752
753     if (column) {
754         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
755
756         for (x = 0; x < src_w; x++) {
757             const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
758             const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
759             uint8_t *dst_data = out->data[plane] + offset * dst_linesize;
760             uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
761             uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
762             uint8_t *dst = dst_line;
763
764             for (y = 0; y < src_h; y++) {
765                 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
766                 uint8_t *target;
767
768                 target = dst + x + dst_signed_linesize * (256 - sum);
769                 update(target, max, intensity);
770                 target = dst + x + dst_signed_linesize * (255 + sum);
771                 update(target, max, intensity);
772
773                 c0_data += c0_linesize;
774                 c1_data += c1_linesize;
775                 dst_data += dst_linesize;
776             }
777         }
778     } else {
779         const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
780         const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
781         uint8_t *dst_data = out->data[plane] + offset;
782
783         if (mirror)
784             dst_data += s->size - 1;
785         for (y = 0; y < src_h; y++) {
786             for (x = 0; x < src_w; x++) {
787                 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
788                 uint8_t *target;
789
790                 if (mirror) {
791                     target = dst_data - (256 - sum);
792                     update(target, max, intensity);
793                     target = dst_data - (255 + sum);
794                     update(target, max, intensity);
795                 } else {
796                     target = dst_data + (256 - sum);
797                     update(target, max, intensity);
798                     target = dst_data + (255 + sum);
799                     update(target, max, intensity);
800                 }
801             }
802
803             c0_data += c0_linesize;
804             c1_data += c1_linesize;
805             dst_data += dst_linesize;
806         }
807     }
808
809     envelope(s, out, plane, (plane + 0) % s->ncomp);
810 }
811
812 static void achroma(WaveformContext *s, AVFrame *in, AVFrame *out,
813                     int component, int intensity, int offset, int column)
814 {
815     const int plane = s->desc->comp[component].plane;
816     const int mirror = s->mirror;
817     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
818     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
819     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
820     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
821     const int max = 255 - intensity;
822     const int src_h = in->height;
823     const int src_w = in->width;
824     int x, y;
825
826     if (column) {
827         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
828         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
829
830         for (x = 0; x < src_w; x++) {
831             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
832             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
833             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
834             uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
835             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
836             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
837             uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
838             uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
839
840             for (y = 0; y < src_h; y++) {
841                 const int c1 = c1_data[x] - 128;
842                 const int c2 = c2_data[x] - 128;
843                 uint8_t *target;
844
845                 target = d1 + x + d1_signed_linesize * (128 + c1);
846                 update(target, max, intensity);
847
848                 target = d2 + x + d2_signed_linesize * (128 + c2);
849                 update(target, max, intensity);
850
851                 c1_data += c1_linesize;
852                 c2_data += c2_linesize;
853                 d1_data += d1_linesize;
854                 d2_data += d2_linesize;
855             }
856         }
857     } else {
858         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
859         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
860         uint8_t *d0_data = out->data[plane] + offset;
861         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
862         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
863
864         if (mirror) {
865             d0_data += s->size - 1;
866             d1_data += s->size - 1;
867             d2_data += s->size - 1;
868         }
869
870         for (y = 0; y < src_h; y++) {
871             for (x = 0; x < src_w; x++) {
872                 const int c1 = c1_data[x] - 128;
873                 const int c2 = c2_data[x] - 128;
874                 uint8_t *target;
875
876                 if (mirror) {
877                     target = d1_data - (128 + c1);
878                     update(target, max, intensity);
879                     target = d2_data - (128 + c2);
880                     update(target, max, intensity);
881                 } else {
882                     target = d1_data + (128 + c1);
883                     update(target, max, intensity);
884                     target = d2_data + (128 + c2);
885                     update(target, max, intensity);
886                 }
887             }
888
889             c1_data += c1_linesize;
890             c2_data += c2_linesize;
891             d1_data += d1_linesize;
892             d2_data += d2_linesize;
893         }
894     }
895
896     envelope(s, out, plane, (plane + 1) % s->ncomp);
897     envelope(s, out, plane, (plane + 2) % s->ncomp);
898 }
899
900 static void color16(WaveformContext *s, AVFrame *in, AVFrame *out,
901                     int component, int intensity, int offset, int column)
902 {
903     const int plane = s->desc->comp[component].plane;
904     const int mirror = s->mirror;
905     const int limit = s->max - 1;
906     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0];
907     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp];
908     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp];
909     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
910     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
911     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
912     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
913     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
914     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
915     const int src_h = in->height;
916     const int src_w = in->width;
917     int x, y;
918
919     if (s->mode) {
920         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
921         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
922         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
923         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset * d0_linesize;
924         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
925         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
926         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
927         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
928         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
929         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
930         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
931         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
932
933         for (y = 0; y < src_h; y++) {
934             for (x = 0; x < src_w; x++) {
935                 const int c0 = FFMIN(c0_data[x], limit);
936                 const int c1 = c1_data[x];
937                 const int c2 = c2_data[x];
938
939                 *(d0 + d0_signed_linesize * c0 + x) = c0;
940                 *(d1 + d1_signed_linesize * c0 + x) = c1;
941                 *(d2 + d2_signed_linesize * c0 + x) = c2;
942             }
943
944             c0_data += c0_linesize;
945             c1_data += c1_linesize;
946             c2_data += c2_linesize;
947             d0_data += d0_linesize;
948             d1_data += d1_linesize;
949             d2_data += d2_linesize;
950         }
951     } else {
952         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset;
953         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset;
954         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset;
955
956         if (mirror) {
957             d0_data += s->size - 1;
958             d1_data += s->size - 1;
959             d2_data += s->size - 1;
960         }
961
962         for (y = 0; y < src_h; y++) {
963             for (x = 0; x < src_w; x++) {
964                 const int c0 = FFMIN(c0_data[x], limit);
965                 const int c1 = c1_data[x];
966                 const int c2 = c2_data[x];
967
968                 if (mirror) {
969                     *(d0_data - c0) = c0;
970                     *(d1_data - c0) = c1;
971                     *(d2_data - c0) = c2;
972                 } else {
973                     *(d0_data + c0) = c0;
974                     *(d1_data + c0) = c1;
975                     *(d2_data + c0) = c2;
976                 }
977             }
978
979             c0_data += c0_linesize;
980             c1_data += c1_linesize;
981             c2_data += c2_linesize;
982             d0_data += d0_linesize;
983             d1_data += d1_linesize;
984             d2_data += d2_linesize;
985         }
986     }
987
988     envelope16(s, out, plane, plane);
989 }
990
991 static void color(WaveformContext *s, AVFrame *in, AVFrame *out,
992                   int component, int intensity, int offset, int column)
993 {
994     const int plane = s->desc->comp[component].plane;
995     const int mirror = s->mirror;
996     const uint8_t *c0_data = in->data[plane + 0];
997     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
998     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
999     const int c0_linesize = in->linesize[ plane + 0 ];
1000     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1001     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1002     const int d0_linesize = out->linesize[ plane + 0 ];
1003     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1004     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1005     const int src_h = in->height;
1006     const int src_w = in->width;
1007     int x, y;
1008
1009     if (s->mode) {
1010         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1011         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1012         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1013         uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
1014         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
1015         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
1016         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1017         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1018         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1019         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1020         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1021         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1022
1023         for (y = 0; y < src_h; y++) {
1024             for (x = 0; x < src_w; x++) {
1025                 const int c0 = c0_data[x];
1026                 const int c1 = c1_data[x];
1027                 const int c2 = c2_data[x];
1028
1029                 *(d0 + d0_signed_linesize * c0 + x) = c0;
1030                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1031                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1032             }
1033
1034             c0_data += c0_linesize;
1035             c1_data += c1_linesize;
1036             c2_data += c2_linesize;
1037             d0_data += d0_linesize;
1038             d1_data += d1_linesize;
1039             d2_data += d2_linesize;
1040         }
1041     } else {
1042         uint8_t *d0_data = out->data[plane] + offset;
1043         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
1044         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
1045
1046         if (mirror) {
1047             d0_data += s->size - 1;
1048             d1_data += s->size - 1;
1049             d2_data += s->size - 1;
1050         }
1051
1052         for (y = 0; y < src_h; y++) {
1053             for (x = 0; x < src_w; x++) {
1054                 const int c0 = c0_data[x];
1055                 const int c1 = c1_data[x];
1056                 const int c2 = c2_data[x];
1057
1058                 if (mirror) {
1059                     *(d0_data - c0) = c0;
1060                     *(d1_data - c0) = c1;
1061                     *(d2_data - c0) = c2;
1062                 } else {
1063                     *(d0_data + c0) = c0;
1064                     *(d1_data + c0) = c1;
1065                     *(d2_data + c0) = c2;
1066                 }
1067             }
1068
1069             c0_data += c0_linesize;
1070             c1_data += c1_linesize;
1071             c2_data += c2_linesize;
1072             d0_data += d0_linesize;
1073             d1_data += d1_linesize;
1074             d2_data += d2_linesize;
1075         }
1076     }
1077
1078     envelope(s, out, plane, plane);
1079 }
1080
1081 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
1082 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
1083
1084 static int config_input(AVFilterLink *inlink)
1085 {
1086     AVFilterContext *ctx = inlink->dst;
1087     WaveformContext *s = ctx->priv;
1088
1089     s->desc  = av_pix_fmt_desc_get(inlink->format);
1090     s->ncomp = s->desc->nb_components;
1091     s->bits = s->desc->comp[0].depth;
1092     s->max = 1 << s->bits;
1093     s->intensity = s->fintensity * (s->max - 1);
1094
1095     switch (s->filter) {
1096     case LOWPASS:
1097             s->size = 256;
1098             s->waveform = s->bits > 8 ? lowpass16 : lowpass; break;
1099     case FLAT:
1100             s->size = 256 * 3;
1101             s->waveform = flat;    break;
1102     case AFLAT:
1103             s->size = 256 * 2;
1104             s->waveform = aflat;   break;
1105     case CHROMA:
1106             s->size = 256 * 2;
1107             s->waveform = chroma;  break;
1108     case ACHROMA:
1109             s->size = 256;
1110             s->waveform = achroma; break;
1111     case COLOR:
1112             s->size = 256;
1113             s->waveform = s->bits > 8 ?   color16 :   color; break;
1114     }
1115
1116     s->size = s->size << (s->bits - 8);
1117
1118     switch (inlink->format) {
1119     case AV_PIX_FMT_GBRAP:
1120     case AV_PIX_FMT_GBRP:
1121     case AV_PIX_FMT_GBRP9:
1122     case AV_PIX_FMT_GBRP10:
1123         s->bg_color = black_gbrp_color;
1124         break;
1125     default:
1126         s->bg_color = black_yuva_color;
1127     }
1128
1129     return 0;
1130 }
1131
1132 static int config_output(AVFilterLink *outlink)
1133 {
1134     AVFilterContext *ctx = outlink->src;
1135     AVFilterLink *inlink = ctx->inputs[0];
1136     WaveformContext *s = ctx->priv;
1137     int comp = 0, i, j = 0, k, p, size, shift;
1138
1139     for (i = 0; i < s->ncomp; i++) {
1140         if ((1 << i) & s->pcomp)
1141             comp++;
1142     }
1143
1144     av_freep(&s->peak);
1145
1146     if (s->mode) {
1147         outlink->h = s->size * FFMAX(comp * s->display, 1);
1148         size = inlink->w;
1149     } else {
1150         outlink->w = s->size * FFMAX(comp * s->display, 1);
1151         size = inlink->h;
1152     }
1153
1154     s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
1155     if (!s->peak)
1156         return AVERROR(ENOMEM);
1157
1158     for (p = 0; p < 4; p++) {
1159         const int is_chroma = (p == 1 || p == 2);
1160         const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
1161         const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
1162         const int plane = s->desc->comp[p].plane;
1163         int offset;
1164
1165         if (!((1 << p) & s->pcomp))
1166             continue;
1167
1168         shift = s->mode ? shift_h : shift_w;
1169
1170         for (k = 0; k < 4; k++) {
1171             s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
1172             s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
1173         }
1174
1175         offset = j++ * s->size * s->display;
1176         s->estart[plane] = offset >> shift;
1177         s->eend[plane]   = (offset + s->size - 1) >> shift;
1178         for (i = 0; i < size; i++) {
1179             for (k = 0; k < 4; k++) {
1180                 s->emax[plane][k][i] = s->estart[plane];
1181                 s->emin[plane][k][i] = s->eend[plane];
1182             }
1183         }
1184     }
1185
1186     outlink->sample_aspect_ratio = (AVRational){1,1};
1187
1188     return 0;
1189 }
1190
1191 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1192 {
1193     AVFilterContext *ctx  = inlink->dst;
1194     WaveformContext *s    = ctx->priv;
1195     AVFilterLink *outlink = ctx->outputs[0];
1196     AVFrame *out;
1197     int i, j, k;
1198
1199     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1200     if (!out) {
1201         av_frame_free(&in);
1202         return AVERROR(ENOMEM);
1203     }
1204     out->pts = in->pts;
1205
1206     for (k = 0; k < s->ncomp; k++) {
1207         const int is_chroma = (k == 1 || k == 2);
1208         const int dst_h = FF_CEIL_RSHIFT(outlink->h, (is_chroma ? s->desc->log2_chroma_h : 0));
1209         const int dst_w = FF_CEIL_RSHIFT(outlink->w, (is_chroma ? s->desc->log2_chroma_w : 0));
1210         if (s->bits <= 8) {
1211             for (i = 0; i < dst_h ; i++)
1212                 memset(out->data[s->desc->comp[k].plane] +
1213                        i * out->linesize[s->desc->comp[k].plane],
1214                        s->bg_color[k], dst_w);
1215         } else {
1216             const int mult = s->size / 256;
1217             uint16_t *dst = (uint16_t *)out->data[s->desc->comp[k].plane];
1218
1219             for (i = 0; i < dst_h ; i++) {
1220                 for (j = 0; j < dst_w; j++)
1221                     dst[j] = s->bg_color[k] * mult;
1222                 dst += out->linesize[s->desc->comp[k].plane] / 2;
1223             }
1224         }
1225     }
1226
1227     for (k = 0, i = 0; k < s->ncomp; k++) {
1228         if ((1 << k) & s->pcomp) {
1229             const int offset = i++ * s->size * s->display;
1230             s->waveform(s, in, out, k, s->intensity, offset, s->mode);
1231         }
1232     }
1233
1234     av_frame_free(&in);
1235     return ff_filter_frame(outlink, out);
1236 }
1237
1238 static av_cold void uninit(AVFilterContext *ctx)
1239 {
1240     WaveformContext *s = ctx->priv;
1241
1242     av_freep(&s->peak);
1243 }
1244
1245 static const AVFilterPad inputs[] = {
1246     {
1247         .name         = "default",
1248         .type         = AVMEDIA_TYPE_VIDEO,
1249         .filter_frame = filter_frame,
1250         .config_props = config_input,
1251     },
1252     { NULL }
1253 };
1254
1255 static const AVFilterPad outputs[] = {
1256     {
1257         .name         = "default",
1258         .type         = AVMEDIA_TYPE_VIDEO,
1259         .config_props = config_output,
1260     },
1261     { NULL }
1262 };
1263
1264 AVFilter ff_vf_waveform = {
1265     .name          = "waveform",
1266     .description   = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
1267     .priv_size     = sizeof(WaveformContext),
1268     .priv_class    = &waveform_class,
1269     .query_formats = query_formats,
1270     .uninit        = uninit,
1271     .inputs        = inputs,
1272     .outputs       = outputs,
1273 };