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