avfilter/waveform: use AV_OPT_TYPE_BOOL for mirror option
[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                 int p;
569
570                 target = d0 + x + d0_signed_linesize * c0;
571                 update(target, max, intensity);
572
573                 for (p = c0 - c1; p < c0 + c1; p++) {
574                     target = d1 + x + d1_signed_linesize * p;
575                     update(target, max, 1);
576                 }
577                 c0_data += c0_linesize;
578                 c1_data += c1_linesize;
579                 c2_data += c2_linesize;
580                 d0_data += d0_linesize;
581                 d1_data += d1_linesize;
582             }
583         }
584     } else {
585         const uint8_t *c0_data = in->data[plane];
586         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
587         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
588         uint8_t *d0_data = out->data[plane] + offset;
589         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
590
591         if (mirror) {
592             d0_data += s->size - 1;
593             d1_data += s->size - 1;
594         }
595
596         for (y = 0; y < src_h; y++) {
597             for (x = 0; x < src_w; x++) {
598                 int c0 = c0_data[x] + 256;
599                 const int c1 = FFABS(c1_data[x] - 128) + FFABS(c2_data[x] - 128);
600                 uint8_t *target;
601                 int p;
602
603                 if (mirror)
604                     target = d0_data - c0;
605                 else
606                     target = d0_data + c0;
607
608                 update(target, max, intensity);
609
610                 for (p = c0 - c1; p < c0 + c1; p++) {
611                     if (mirror)
612                         target = d1_data - p;
613                     else
614                         target = d1_data + p;
615
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                 int p;
673
674                 target = d0 + x + d0_signed_linesize * c0;
675                 update(target, max, intensity);
676
677                 for (p = c0 + c1; p < c0; p++) {
678                     target = d1 + x + d1_signed_linesize * p;
679                     update(target, max, 1);
680                 }
681
682                 for (p = c0 + c1 - 1; p > c0; p--) {
683                     target = d1 + x + d1_signed_linesize * p;
684                     update(target, max, 1);
685                 }
686
687                 for (p = c0 + c2; p < c0; p++) {
688                     target = d2 + x + d2_signed_linesize * p;
689                     update(target, max, 1);
690                 }
691
692                 for (p = c0 + c2 - 1; p > c0; p--) {
693                     target = d2 + x + d2_signed_linesize * p;
694                     update(target, max, 1);
695                 }
696
697                 c0_data += c0_linesize;
698                 c1_data += c1_linesize;
699                 c2_data += c2_linesize;
700                 d0_data += d0_linesize;
701                 d1_data += d1_linesize;
702                 d2_data += d2_linesize;
703             }
704         }
705     } else {
706         const uint8_t *c0_data = in->data[plane];
707         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
708         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
709         uint8_t *d0_data = out->data[plane] + offset;
710         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
711         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
712
713         if (mirror) {
714             d0_data += s->size - 1;
715             d1_data += s->size - 1;
716             d2_data += s->size - 1;
717         }
718
719         for (y = 0; y < src_h; y++) {
720             for (x = 0; x < src_w; x++) {
721                 const int c0 = c0_data[x] + 128;
722                 const int c1 = c1_data[x] - 128;
723                 const int c2 = c2_data[x] - 128;
724                 uint8_t *target;
725                 int p;
726
727                 if (mirror)
728                     target = d0_data - c0;
729                 else
730                     target = d0_data + c0;
731
732                 update(target, max, intensity);
733
734                 for (p = c0 + c1; p < c0; p++) {
735                     if (mirror)
736                         target = d1_data - p;
737                     else
738                         target = d1_data + p;
739
740                     update(target, max, 1);
741                 }
742
743                 for (p = c0 + 1; p < c0 + c1; p++) {
744                     if (mirror)
745                         target = d1_data - p;
746                     else
747                         target = d1_data + p;
748
749                     update(target, max, 1);
750                 }
751
752                 for (p = c0 + c2; p < c0; p++) {
753                     if (mirror)
754                         target = d2_data - p;
755                     else
756                         target = d2_data + p;
757
758                     update(target, max, 1);
759                 }
760
761                 for (p = c0 + 1; p < c0 + c2; p++) {
762                     if (mirror)
763                         target = d2_data - p;
764                     else
765                         target = d2_data + p;
766
767                     update(target, max, 1);
768                 }
769             }
770
771             c0_data += c0_linesize;
772             c1_data += c1_linesize;
773             c2_data += c2_linesize;
774             d0_data += d0_linesize;
775             d1_data += d1_linesize;
776             d2_data += d2_linesize;
777         }
778     }
779
780     envelope(s, out, plane, (plane + 0) % s->ncomp);
781     envelope(s, out, plane, (plane + 1) % s->ncomp);
782     envelope(s, out, plane, (plane + 2) % s->ncomp);
783 }
784
785 static void chroma(WaveformContext *s, AVFrame *in, AVFrame *out,
786                    int component, int intensity, int offset, int column)
787 {
788     const int plane = s->desc->comp[component].plane;
789     const int mirror = s->mirror;
790     const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
791     const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
792     const int dst_linesize = out->linesize[plane];
793     const int max = 255 - intensity;
794     const int src_h = in->height;
795     const int src_w = in->width;
796     int x, y;
797
798     if (column) {
799         const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
800
801         for (x = 0; x < src_w; x++) {
802             const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
803             const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
804             uint8_t *dst_data = out->data[plane] + offset * dst_linesize;
805             uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
806             uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
807             uint8_t *dst = dst_line;
808
809             for (y = 0; y < src_h; y++) {
810                 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
811                 uint8_t *target;
812                 int p;
813
814                 for (p = 256 - sum; p < 256 + sum; p++) {
815                     target = dst + x + dst_signed_linesize * p;
816                     update(target, max, 1);
817                 }
818
819                 c0_data += c0_linesize;
820                 c1_data += c1_linesize;
821                 dst_data += dst_linesize;
822             }
823         }
824     } else {
825         const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
826         const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
827         uint8_t *dst_data = out->data[plane] + offset;
828
829         if (mirror)
830             dst_data += s->size - 1;
831         for (y = 0; y < src_h; y++) {
832             for (x = 0; x < src_w; x++) {
833                 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
834                 uint8_t *target;
835                 int p;
836
837                 for (p = 256 - sum; p < 256 + sum; p++) {
838                     if (mirror)
839                         target = dst_data - p;
840                     else
841                         target = dst_data + p;
842
843                     update(target, max, 1);
844                 }
845             }
846
847             c0_data += c0_linesize;
848             c1_data += c1_linesize;
849             dst_data += dst_linesize;
850         }
851     }
852
853     envelope(s, out, plane, (plane + 0) % s->ncomp);
854 }
855
856 static void achroma(WaveformContext *s, AVFrame *in, AVFrame *out,
857                     int component, int intensity, int offset, int column)
858 {
859     const int plane = s->desc->comp[component].plane;
860     const int mirror = s->mirror;
861     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
862     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
863     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
864     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
865     const int max = 255 - intensity;
866     const int src_h = in->height;
867     const int src_w = in->width;
868     int x, y;
869
870     if (column) {
871         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
872         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
873
874         for (x = 0; x < src_w; x++) {
875             const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
876             const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
877             uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
878             uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
879             uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
880             uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
881             uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
882             uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
883
884             for (y = 0; y < src_h; y++) {
885                 const int c1 = c1_data[x] - 128;
886                 const int c2 = c2_data[x] - 128;
887                 uint8_t *target;
888                 int p;
889
890                 for (p = 128 + c1; p < 128; p++) {
891                     target = d1 + x + d1_signed_linesize * p;
892                     update(target, max, 1);
893                 }
894
895                 for (p = 128 + c1 - 1; p > 128; p--) {
896                     target = d1 + x + d1_signed_linesize * p;
897                     update(target, max, 1);
898                 }
899
900                 for (p = 128 + c2; p < 128; p++) {
901                     target = d2 + x + d2_signed_linesize * p;
902                     update(target, max, 1);
903                 }
904
905                 for (p = 128 + c2 - 1; p > 128; p--) {
906                     target = d2 + x + d2_signed_linesize * p;
907                     update(target, max, 1);
908                 }
909
910                 c1_data += c1_linesize;
911                 c2_data += c2_linesize;
912                 d1_data += d1_linesize;
913                 d2_data += d2_linesize;
914             }
915         }
916     } else {
917         const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
918         const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
919         uint8_t *d0_data = out->data[plane] + offset;
920         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
921         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
922
923         if (mirror) {
924             d0_data += s->size - 1;
925             d1_data += s->size - 1;
926             d2_data += s->size - 1;
927         }
928
929         for (y = 0; y < src_h; y++) {
930             for (x = 0; x < src_w; x++) {
931                 const int c1 = c1_data[x] - 128;
932                 const int c2 = c2_data[x] - 128;
933                 uint8_t *target;
934                 int p;
935
936                 for (p = 128 + c1; p < 128; p++) {
937                     if (mirror)
938                         target = d1_data - p;
939                     else
940                         target = d1_data + p;
941
942                     update(target, max, 1);
943                 }
944
945                 for (p = 128 + 1; p < 128 + c1; p++) {
946                     if (mirror)
947                         target = d1_data - p;
948                     else
949                         target = d1_data + p;
950
951                     update(target, max, 1);
952                 }
953
954                 for (p = 128 + c2; p < 128; p++) {
955                     if (mirror)
956                         target = d2_data - p;
957                     else
958                         target = d2_data + p;
959
960                     update(target, max, 1);
961                 }
962
963                 for (p = 128 + 1; p < 128 + c2; p++) {
964                     if (mirror)
965                         target = d2_data - p;
966                     else
967                         target = d2_data + p;
968
969                     update(target, max, 1);
970                 }
971             }
972
973             c1_data += c1_linesize;
974             c2_data += c2_linesize;
975             d1_data += d1_linesize;
976             d2_data += d2_linesize;
977         }
978     }
979
980     envelope(s, out, plane, (plane + 1) % s->ncomp);
981     envelope(s, out, plane, (plane + 2) % s->ncomp);
982 }
983
984 static void color16(WaveformContext *s, AVFrame *in, AVFrame *out,
985                     int component, int intensity, int offset, int column)
986 {
987     const int plane = s->desc->comp[component].plane;
988     const int mirror = s->mirror;
989     const int limit = s->max - 1;
990     const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0];
991     const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp];
992     const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp];
993     const int c0_linesize = in->linesize[ plane + 0 ] / 2;
994     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
995     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
996     const int d0_linesize = out->linesize[ plane + 0 ] / 2;
997     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
998     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
999     const int src_h = in->height;
1000     const int src_w = in->width;
1001     int x, y;
1002
1003     if (s->mode) {
1004         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1005         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1006         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1007         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset * d0_linesize;
1008         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
1009         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
1010         uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1011         uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1012         uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1013         uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1014         uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1015         uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1016
1017         for (y = 0; y < src_h; y++) {
1018             for (x = 0; x < src_w; x++) {
1019                 const int c0 = FFMIN(c0_data[x], limit);
1020                 const int c1 = c1_data[x];
1021                 const int c2 = c2_data[x];
1022
1023                 *(d0 + d0_signed_linesize * c0 + x) = c0;
1024                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1025                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1026             }
1027
1028             c0_data += c0_linesize;
1029             c1_data += c1_linesize;
1030             c2_data += c2_linesize;
1031             d0_data += d0_linesize;
1032             d1_data += d1_linesize;
1033             d2_data += d2_linesize;
1034         }
1035     } else {
1036         uint16_t *d0_data = (uint16_t *)out->data[plane] + offset;
1037         uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset;
1038         uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset;
1039
1040         if (mirror) {
1041             d0_data += s->size - 1;
1042             d1_data += s->size - 1;
1043             d2_data += s->size - 1;
1044         }
1045
1046         for (y = 0; y < src_h; y++) {
1047             for (x = 0; x < src_w; x++) {
1048                 const int c0 = FFMIN(c0_data[x], limit);
1049                 const int c1 = c1_data[x];
1050                 const int c2 = c2_data[x];
1051
1052                 if (mirror) {
1053                     *(d0_data - c0) = c0;
1054                     *(d1_data - c0) = c1;
1055                     *(d2_data - c0) = c2;
1056                 } else {
1057                     *(d0_data + c0) = c0;
1058                     *(d1_data + c0) = c1;
1059                     *(d2_data + c0) = c2;
1060                 }
1061             }
1062
1063             c0_data += c0_linesize;
1064             c1_data += c1_linesize;
1065             c2_data += c2_linesize;
1066             d0_data += d0_linesize;
1067             d1_data += d1_linesize;
1068             d2_data += d2_linesize;
1069         }
1070     }
1071
1072     envelope16(s, out, plane, plane);
1073 }
1074
1075 static void color(WaveformContext *s, AVFrame *in, AVFrame *out,
1076                   int component, int intensity, int offset, int column)
1077 {
1078     const int plane = s->desc->comp[component].plane;
1079     const int mirror = s->mirror;
1080     const uint8_t *c0_data = in->data[plane + 0];
1081     const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
1082     const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
1083     const int c0_linesize = in->linesize[ plane + 0 ];
1084     const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1085     const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1086     const int d0_linesize = out->linesize[ plane + 0 ];
1087     const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1088     const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1089     const int src_h = in->height;
1090     const int src_w = in->width;
1091     int x, y;
1092
1093     if (s->mode) {
1094         const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1095         const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1096         const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1097         uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
1098         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
1099         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
1100         uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1101         uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1102         uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1103         uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1104         uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1105         uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1106
1107         for (y = 0; y < src_h; y++) {
1108             for (x = 0; x < src_w; x++) {
1109                 const int c0 = c0_data[x];
1110                 const int c1 = c1_data[x];
1111                 const int c2 = c2_data[x];
1112
1113                 *(d0 + d0_signed_linesize * c0 + x) = c0;
1114                 *(d1 + d1_signed_linesize * c0 + x) = c1;
1115                 *(d2 + d2_signed_linesize * c0 + x) = c2;
1116             }
1117
1118             c0_data += c0_linesize;
1119             c1_data += c1_linesize;
1120             c2_data += c2_linesize;
1121             d0_data += d0_linesize;
1122             d1_data += d1_linesize;
1123             d2_data += d2_linesize;
1124         }
1125     } else {
1126         uint8_t *d0_data = out->data[plane] + offset;
1127         uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
1128         uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
1129
1130         if (mirror) {
1131             d0_data += s->size - 1;
1132             d1_data += s->size - 1;
1133             d2_data += s->size - 1;
1134         }
1135
1136         for (y = 0; y < src_h; y++) {
1137             for (x = 0; x < src_w; x++) {
1138                 const int c0 = c0_data[x];
1139                 const int c1 = c1_data[x];
1140                 const int c2 = c2_data[x];
1141
1142                 if (mirror) {
1143                     *(d0_data - c0) = c0;
1144                     *(d1_data - c0) = c1;
1145                     *(d2_data - c0) = c2;
1146                 } else {
1147                     *(d0_data + c0) = c0;
1148                     *(d1_data + c0) = c1;
1149                     *(d2_data + c0) = c2;
1150                 }
1151             }
1152
1153             c0_data += c0_linesize;
1154             c1_data += c1_linesize;
1155             c2_data += c2_linesize;
1156             d0_data += d0_linesize;
1157             d1_data += d1_linesize;
1158             d2_data += d2_linesize;
1159         }
1160     }
1161
1162     envelope(s, out, plane, plane);
1163 }
1164
1165 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
1166 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
1167
1168 static int config_input(AVFilterLink *inlink)
1169 {
1170     AVFilterContext *ctx = inlink->dst;
1171     WaveformContext *s = ctx->priv;
1172
1173     s->desc  = av_pix_fmt_desc_get(inlink->format);
1174     s->ncomp = s->desc->nb_components;
1175     s->bits = s->desc->comp[0].depth;
1176     s->max = 1 << s->bits;
1177     s->intensity = s->fintensity * (s->max - 1);
1178
1179     switch (s->filter) {
1180     case LOWPASS:
1181             s->size = 256;
1182             s->waveform = s->bits > 8 ? lowpass16 : lowpass; break;
1183     case FLAT:
1184             s->size = 256 * 3;
1185             s->waveform = flat;    break;
1186     case AFLAT:
1187             s->size = 256 * 2;
1188             s->waveform = aflat;   break;
1189     case CHROMA:
1190             s->size = 256 * 2;
1191             s->waveform = chroma;  break;
1192     case ACHROMA:
1193             s->size = 256;
1194             s->waveform = achroma; break;
1195     case COLOR:
1196             s->size = 256;
1197             s->waveform = s->bits > 8 ?   color16 :   color; break;
1198     }
1199
1200     s->size = s->size << (s->bits - 8);
1201
1202     switch (inlink->format) {
1203     case AV_PIX_FMT_GBRAP:
1204     case AV_PIX_FMT_GBRP:
1205     case AV_PIX_FMT_GBRP9:
1206     case AV_PIX_FMT_GBRP10:
1207         s->bg_color = black_gbrp_color;
1208         break;
1209     default:
1210         s->bg_color = black_yuva_color;
1211     }
1212
1213     return 0;
1214 }
1215
1216 static int config_output(AVFilterLink *outlink)
1217 {
1218     AVFilterContext *ctx = outlink->src;
1219     AVFilterLink *inlink = ctx->inputs[0];
1220     WaveformContext *s = ctx->priv;
1221     int comp = 0, i, j = 0, k, p, size, shift;
1222
1223     for (i = 0; i < s->ncomp; i++) {
1224         if ((1 << i) & s->pcomp)
1225             comp++;
1226     }
1227
1228     av_freep(&s->peak);
1229
1230     if (s->mode) {
1231         outlink->h = s->size * FFMAX(comp * s->display, 1);
1232         size = inlink->w;
1233     } else {
1234         outlink->w = s->size * FFMAX(comp * s->display, 1);
1235         size = inlink->h;
1236     }
1237
1238     s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
1239     if (!s->peak)
1240         return AVERROR(ENOMEM);
1241
1242     for (p = 0; p < 4; p++) {
1243         const int is_chroma = (p == 1 || p == 2);
1244         const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
1245         const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
1246         const int plane = s->desc->comp[p].plane;
1247         int offset;
1248
1249         if (!((1 << p) & s->pcomp))
1250             continue;
1251
1252         shift = s->mode ? shift_h : shift_w;
1253
1254         for (k = 0; k < 4; k++) {
1255             s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
1256             s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
1257         }
1258
1259         offset = j++ * s->size * s->display;
1260         s->estart[plane] = offset >> shift;
1261         s->eend[plane]   = (offset + s->size - 1) >> shift;
1262         for (i = 0; i < size; i++) {
1263             for (k = 0; k < 4; k++) {
1264                 s->emax[plane][k][i] = s->estart[plane];
1265                 s->emin[plane][k][i] = s->eend[plane];
1266             }
1267         }
1268     }
1269
1270     outlink->sample_aspect_ratio = (AVRational){1,1};
1271
1272     return 0;
1273 }
1274
1275 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1276 {
1277     AVFilterContext *ctx  = inlink->dst;
1278     WaveformContext *s    = ctx->priv;
1279     AVFilterLink *outlink = ctx->outputs[0];
1280     AVFrame *out;
1281     int i, j, k;
1282
1283     out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1284     if (!out) {
1285         av_frame_free(&in);
1286         return AVERROR(ENOMEM);
1287     }
1288     out->pts = in->pts;
1289
1290     for (k = 0; k < s->ncomp; k++) {
1291         const int is_chroma = (k == 1 || k == 2);
1292         const int dst_h = FF_CEIL_RSHIFT(outlink->h, (is_chroma ? s->desc->log2_chroma_h : 0));
1293         const int dst_w = FF_CEIL_RSHIFT(outlink->w, (is_chroma ? s->desc->log2_chroma_w : 0));
1294         if (s->bits <= 8) {
1295             for (i = 0; i < dst_h ; i++)
1296                 memset(out->data[s->desc->comp[k].plane] +
1297                        i * out->linesize[s->desc->comp[k].plane],
1298                        s->bg_color[k], dst_w);
1299         } else {
1300             const int mult = s->size / 256;
1301             uint16_t *dst = (uint16_t *)out->data[s->desc->comp[k].plane];
1302
1303             for (i = 0; i < dst_h ; i++) {
1304                 for (j = 0; j < dst_w; j++)
1305                     dst[j] = s->bg_color[k] * mult;
1306                 dst += out->linesize[s->desc->comp[k].plane] / 2;
1307             }
1308         }
1309     }
1310
1311     for (k = 0, i = 0; k < s->ncomp; k++) {
1312         if ((1 << k) & s->pcomp) {
1313             const int offset = i++ * s->size * s->display;
1314             s->waveform(s, in, out, k, s->intensity, offset, s->mode);
1315         }
1316     }
1317
1318     av_frame_free(&in);
1319     return ff_filter_frame(outlink, out);
1320 }
1321
1322 static av_cold void uninit(AVFilterContext *ctx)
1323 {
1324     WaveformContext *s = ctx->priv;
1325
1326     av_freep(&s->peak);
1327 }
1328
1329 static const AVFilterPad inputs[] = {
1330     {
1331         .name         = "default",
1332         .type         = AVMEDIA_TYPE_VIDEO,
1333         .filter_frame = filter_frame,
1334         .config_props = config_input,
1335     },
1336     { NULL }
1337 };
1338
1339 static const AVFilterPad outputs[] = {
1340     {
1341         .name         = "default",
1342         .type         = AVMEDIA_TYPE_VIDEO,
1343         .config_props = config_output,
1344     },
1345     { NULL }
1346 };
1347
1348 AVFilter ff_vf_waveform = {
1349     .name          = "waveform",
1350     .description   = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
1351     .priv_size     = sizeof(WaveformContext),
1352     .priv_class    = &waveform_class,
1353     .query_formats = query_formats,
1354     .uninit        = uninit,
1355     .inputs        = inputs,
1356     .outputs       = outputs,
1357 };