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