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