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