2 * Copyright (c) 2012-2015 Paul B Mahol
3 * Copyright (c) 2013 Marton Balint
5 * This file is part of FFmpeg.
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.
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.
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
22 #include "libavutil/avassert.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/parseutils.h"
25 #include "libavutil/pixdesc.h"
41 typedef struct WaveformContext {
46 const uint8_t *bg_color;
59 void (*waveform)(struct WaveformContext *s, AVFrame *in, AVFrame *out,
60 int component, int intensity, int offset, int column);
61 const AVPixFmtDescriptor *desc;
64 #define OFFSET(x) offsetof(WaveformContext, x)
65 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
67 static const AVOption waveform_options[] = {
68 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
69 { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
70 { "row", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
71 { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
72 { "intensity", "set intensity", OFFSET(intensity), AV_OPT_TYPE_INT, {.i64=10}, 1, 1023, FLAGS },
73 { "i", "set intensity", OFFSET(intensity), AV_OPT_TYPE_INT, {.i64=10}, 1, 1023, FLAGS },
74 { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
75 { "r", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS },
76 { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display" },
77 { "d", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "display" },
78 { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "display" },
79 { "parade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "display" },
80 { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
81 { "c", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
82 { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
83 { "e", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
84 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
85 { "instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
86 { "peak", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
87 { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
88 { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
89 { "f", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
90 { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, "filter" },
91 { "flat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "filter" },
92 { "aflat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT}, 0, 0, FLAGS, "filter" },
93 { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA}, 0, 0, FLAGS, "filter" },
94 { "achroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACHROMA}, 0, 0, FLAGS, "filter" },
95 { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR}, 0, 0, FLAGS, "filter" },
99 AVFILTER_DEFINE_CLASS(waveform);
101 static const enum AVPixelFormat lowpass_pix_fmts[] = {
102 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
103 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
104 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
105 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
106 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
107 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
108 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
109 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
111 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
112 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
113 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
114 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
118 static const enum AVPixelFormat flat_pix_fmts[] = {
119 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE
122 static const enum AVPixelFormat color_pix_fmts[] = {
123 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
124 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
125 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
126 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
130 static int query_formats(AVFilterContext *ctx)
132 WaveformContext *s = ctx->priv;
133 AVFilterFormats *fmts_list;
134 const enum AVPixelFormat *pix_fmts;
137 case LOWPASS: pix_fmts = lowpass_pix_fmts; break;
141 case ACHROMA: pix_fmts = flat_pix_fmts; break;
142 case COLOR: pix_fmts = color_pix_fmts; break;
145 fmts_list = ff_make_format_list(pix_fmts);
147 return AVERROR(ENOMEM);
148 return ff_set_common_formats(ctx, fmts_list);
151 static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component)
153 const int dst_linesize = out->linesize[component] / 2;
154 const int bg = s->bg_color[component] * (s->size / 256);
155 const int limit = s->size - 1;
156 const int is_chroma = (component == 1 || component == 2);
157 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
158 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
159 const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
160 const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
161 const int start = s->estart[plane];
162 const int end = s->eend[plane];
167 for (x = 0; x < dst_w; x++) {
168 for (y = start; y < end; y++) {
169 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
175 for (y = end - 1; y >= start; y--) {
176 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
184 for (y = 0; y < dst_h; y++) {
185 dst = (uint16_t *)out->data[component] + y * dst_linesize;
186 for (x = start; x < end; x++) {
192 for (x = end - 1; x >= start; x--) {
202 static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component)
204 const int dst_linesize = out->linesize[component];
205 const uint8_t bg = s->bg_color[component];
206 const int is_chroma = (component == 1 || component == 2);
207 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
208 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
209 const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
210 const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
211 const int start = s->estart[plane];
212 const int end = s->eend[plane];
217 for (x = 0; x < dst_w; x++) {
218 for (y = start; y < end; y++) {
219 dst = out->data[component] + y * dst_linesize + x;
225 for (y = end - 1; y >= start; y--) {
226 dst = out->data[component] + y * dst_linesize + x;
234 for (y = 0; y < dst_h; y++) {
235 dst = out->data[component] + y * dst_linesize;
236 for (x = start; x < end; x++) {
242 for (x = end - 1; x >= start; x--) {
252 static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component)
254 const int dst_linesize = out->linesize[component] / 2;
255 const int bg = s->bg_color[component] * (s->size / 256);
256 const int limit = s->size - 1;
257 const int is_chroma = (component == 1 || component == 2);
258 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
259 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
260 const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
261 const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
262 const int start = s->estart[plane];
263 const int end = s->eend[plane];
264 int *emax = s->emax[plane][component];
265 int *emin = s->emin[plane][component];
270 for (x = 0; x < dst_w; x++) {
271 for (y = start; y < end && y < emin[x]; y++) {
272 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
278 for (y = end - 1; y >= start && y >= emax[x]; y--) {
279 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
287 if (s->envelope == 3)
288 envelope_instant16(s, out, plane, component);
290 for (x = 0; x < dst_w; x++) {
291 dst = (uint16_t *)out->data[component] + emin[x] * dst_linesize + x;
293 dst = (uint16_t *)out->data[component] + emax[x] * dst_linesize + x;
297 for (y = 0; y < dst_h; y++) {
298 dst = (uint16_t *)out->data[component] + y * dst_linesize;
299 for (x = start; x < end && x < emin[y]; x++) {
305 for (x = end - 1; x >= start && x >= emax[y]; x--) {
313 if (s->envelope == 3)
314 envelope_instant16(s, out, plane, component);
316 for (y = 0; y < dst_h; y++) {
317 dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y];
319 dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y];
325 static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component)
327 const int dst_linesize = out->linesize[component];
328 const int bg = s->bg_color[component];
329 const int is_chroma = (component == 1 || component == 2);
330 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
331 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
332 const int dst_h = FF_CEIL_RSHIFT(out->height, shift_h);
333 const int dst_w = FF_CEIL_RSHIFT(out->width, shift_w);
334 const int start = s->estart[plane];
335 const int end = s->eend[plane];
336 int *emax = s->emax[plane][component];
337 int *emin = s->emin[plane][component];
342 for (x = 0; x < dst_w; x++) {
343 for (y = start; y < end && y < emin[x]; y++) {
344 dst = out->data[component] + y * dst_linesize + x;
350 for (y = end - 1; y >= start && y >= emax[x]; y--) {
351 dst = out->data[component] + y * dst_linesize + x;
359 if (s->envelope == 3)
360 envelope_instant(s, out, plane, component);
362 for (x = 0; x < dst_w; x++) {
363 dst = out->data[component] + emin[x] * dst_linesize + x;
365 dst = out->data[component] + emax[x] * dst_linesize + x;
369 for (y = 0; y < dst_h; y++) {
370 dst = out->data[component] + y * dst_linesize;
371 for (x = start; x < end && x < emin[y]; x++) {
377 for (x = end - 1; x >= start && x >= emax[y]; x--) {
385 if (s->envelope == 3)
386 envelope_instant(s, out, plane, component);
388 for (y = 0; y < dst_h; y++) {
389 dst = out->data[component] + y * dst_linesize + emin[y];
391 dst = out->data[component] + y * dst_linesize + emax[y];
397 static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component)
399 if (s->envelope == 0) {
401 } else if (s->envelope == 1) {
402 envelope_instant16(s, out, plane, component);
404 envelope_peak16(s, out, plane, component);
408 static void envelope(WaveformContext *s, AVFrame *out, int plane, int component)
410 if (s->envelope == 0) {
412 } else if (s->envelope == 1) {
413 envelope_instant(s, out, plane, component);
415 envelope_peak(s, out, plane, component);
419 static void update16(uint16_t *target, int max, int intensity, int limit)
422 *target += intensity;
427 static void update(uint8_t *target, int max, int intensity)
430 *target += intensity;
435 static void lowpass16(WaveformContext *s, AVFrame *in, AVFrame *out,
436 int component, int intensity, int offset, int column)
438 const int plane = s->desc->comp[component].plane;
439 const int mirror = s->mirror;
440 const int is_chroma = (component == 1 || component == 2);
441 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
442 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
443 const int src_linesize = in->linesize[plane] / 2;
444 const int dst_linesize = out->linesize[plane] / 2;
445 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
446 const int limit = s->size - 1;
447 const int max = limit - intensity;
448 const int src_h = FF_CEIL_RSHIFT(in->height, shift_h);
449 const int src_w = FF_CEIL_RSHIFT(in->width, shift_w);
450 const uint16_t *src_data = (const uint16_t *)in->data[plane];
451 uint16_t *dst_data = (uint16_t *)out->data[plane] + (column ? (offset >> shift_h) * dst_linesize : offset >> shift_w);
452 uint16_t * const dst_bottom_line = dst_data + dst_linesize * ((s->size >> shift_h) - 1);
453 uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
457 if (!column && mirror)
458 dst_data += s->size >> shift_w;
460 for (y = 0; y < src_h; y++) {
461 const uint16_t *src_data_end = src_data + src_w;
462 uint16_t *dst = dst_line;
464 for (p = src_data; p < src_data_end; p++) {
466 int v = FFMIN(*p, limit);
469 target = dst++ + dst_signed_linesize * (v >> shift_h);
472 target = dst_data - (v >> shift_w) - 1;
474 target = dst_data + (v >> shift_w);
476 update16(target, max, intensity, limit);
478 src_data += src_linesize;
479 dst_data += dst_linesize;
482 envelope16(s, out, plane, plane);
485 static void lowpass(WaveformContext *s, AVFrame *in, AVFrame *out,
486 int component, int intensity, int offset, int column)
488 const int plane = s->desc->comp[component].plane;
489 const int mirror = s->mirror;
490 const int is_chroma = (component == 1 || component == 2);
491 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
492 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
493 const int src_linesize = in->linesize[plane];
494 const int dst_linesize = out->linesize[plane];
495 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
496 const int max = 255 - intensity;
497 const int src_h = FF_CEIL_RSHIFT(in->height, shift_h);
498 const int src_w = FF_CEIL_RSHIFT(in->width, shift_w);
499 const uint8_t *src_data = in->data[plane];
500 uint8_t *dst_data = out->data[plane] + (column ? (offset >> shift_h) * dst_linesize : offset >> shift_w);
501 uint8_t * const dst_bottom_line = dst_data + dst_linesize * ((s->size >> shift_h) - 1);
502 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
506 if (!column && mirror)
507 dst_data += s->size >> shift_w;
509 for (y = 0; y < src_h; y++) {
510 const uint8_t *src_data_end = src_data + src_w;
511 uint8_t *dst = dst_line;
513 for (p = src_data; p < src_data_end; p++) {
516 target = dst++ + dst_signed_linesize * (*p >> shift_h);
519 target = dst_data - (*p >> shift_w) - 1;
521 target = dst_data + (*p >> shift_w);
523 update(target, max, intensity);
525 src_data += src_linesize;
526 dst_data += dst_linesize;
529 envelope(s, out, plane, plane);
532 static void flat(WaveformContext *s, AVFrame *in, AVFrame *out,
533 int component, int intensity, int offset, int column)
535 const int plane = s->desc->comp[component].plane;
536 const int mirror = s->mirror;
537 const int c0_linesize = in->linesize[ plane + 0 ];
538 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
539 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
540 const int d0_linesize = out->linesize[ plane + 0 ];
541 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
542 const int max = 255 - intensity;
543 const int src_h = in->height;
544 const int src_w = in->width;
548 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
549 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
551 for (x = 0; x < src_w; x++) {
552 const uint8_t *c0_data = in->data[plane + 0];
553 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
554 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
555 uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
556 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
557 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
558 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
559 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
560 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
562 for (y = 0; y < src_h; y++) {
563 const int c0 = c0_data[x] + 256;
564 const int c1 = FFABS(c1_data[x] - 128) + FFABS(c2_data[x] - 128);
568 target = d0 + x + d0_signed_linesize * c0;
569 update(target, max, intensity);
571 for (p = c0 - c1; p < c0 + c1; p++) {
572 target = d1 + x + d1_signed_linesize * p;
573 update(target, max, 1);
575 c0_data += c0_linesize;
576 c1_data += c1_linesize;
577 c2_data += c2_linesize;
578 d0_data += d0_linesize;
579 d1_data += d1_linesize;
583 const uint8_t *c0_data = in->data[plane];
584 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
585 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
586 uint8_t *d0_data = out->data[plane] + offset;
587 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
590 d0_data += s->size - 1;
594 for (y = 0; y < src_h; y++) {
595 for (x = 0; x < src_w; x++) {
596 int c0 = c0_data[x] + 256;
597 const int c1 = FFABS(c1_data[x] - 128) + FFABS(c2_data[x] - 128);
602 target = d0_data - c0;
604 target = d0_data + c0;
606 update(target, max, intensity);
608 for (p = c0 - c1; p < c0 + c1; p++) {
610 target = d1_data - p - 1;
612 target = d1_data + p;
614 update(target, max, 1);
618 c0_data += c0_linesize;
619 c1_data += c1_linesize;
620 c2_data += c2_linesize;
621 d0_data += d0_linesize;
622 d1_data += d1_linesize;
626 envelope(s, out, plane, plane);
627 envelope(s, out, plane, (plane + 1) % s->ncomp);
630 static void aflat(WaveformContext *s, AVFrame *in, AVFrame *out,
631 int component, int intensity, int offset, int column)
633 const int plane = s->desc->comp[component].plane;
634 const int mirror = s->mirror;
635 const int c0_linesize = in->linesize[ plane + 0 ];
636 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
637 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
638 const int d0_linesize = out->linesize[ plane + 0 ];
639 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
640 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
641 const int max = 255 - intensity;
642 const int src_h = in->height;
643 const int src_w = in->width;
647 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
648 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
649 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
651 for (x = 0; x < src_w; x++) {
652 const uint8_t *c0_data = in->data[plane + 0];
653 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
654 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
655 uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
656 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
657 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
658 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
659 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
660 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
661 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
662 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
663 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
665 for (y = 0; y < src_h; y++) {
666 const int c0 = c0_data[x] + 128;
667 const int c1 = c1_data[x] - 128;
668 const int c2 = c2_data[x] - 128;
672 target = d0 + x + d0_signed_linesize * c0;
673 update(target, max, intensity);
675 for (p = c0 + c1; p < c0; p++) {
676 target = d1 + x + d1_signed_linesize * p;
677 update(target, max, 1);
680 for (p = c0 + c1 - 1; p > c0; p--) {
681 target = d1 + x + d1_signed_linesize * p;
682 update(target, max, 1);
685 for (p = c0 + c2; p < c0; p++) {
686 target = d2 + x + d2_signed_linesize * p;
687 update(target, max, 1);
690 for (p = c0 + c2 - 1; p > c0; p--) {
691 target = d2 + x + d2_signed_linesize * p;
692 update(target, max, 1);
695 c0_data += c0_linesize;
696 c1_data += c1_linesize;
697 c2_data += c2_linesize;
698 d0_data += d0_linesize;
699 d1_data += d1_linesize;
700 d2_data += d2_linesize;
704 const uint8_t *c0_data = in->data[plane];
705 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
706 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
707 uint8_t *d0_data = out->data[plane] + offset;
708 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
709 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
712 d0_data += s->size - 1;
713 d1_data += s->size - 1;
714 d2_data += s->size - 1;
717 for (y = 0; y < src_h; y++) {
718 for (x = 0; x < src_w; x++) {
719 const int c0 = c0_data[x] + 128;
720 const int c1 = c1_data[x] - 128;
721 const int c2 = c2_data[x] - 128;
726 target = d0_data - c0;
728 target = d0_data + c0;
730 update(target, max, intensity);
732 for (p = c0 + c1; p < c0; p++) {
734 target = d1_data - p;
736 target = d1_data + p;
738 update(target, max, 1);
741 for (p = c0 + 1; p < c0 + c1; p++) {
743 target = d1_data - p;
745 target = d1_data + p;
747 update(target, max, 1);
750 for (p = c0 + c2; p < c0; p++) {
752 target = d2_data - p;
754 target = d2_data + p;
756 update(target, max, 1);
759 for (p = c0 + 1; p < c0 + c2; p++) {
761 target = d2_data - p;
763 target = d2_data + p;
765 update(target, max, 1);
769 c0_data += c0_linesize;
770 c1_data += c1_linesize;
771 c2_data += c2_linesize;
772 d0_data += d0_linesize;
773 d1_data += d1_linesize;
774 d2_data += d2_linesize;
778 envelope(s, out, plane, (plane + 0) % s->ncomp);
779 envelope(s, out, plane, (plane + 1) % s->ncomp);
780 envelope(s, out, plane, (plane + 2) % s->ncomp);
783 static void chroma(WaveformContext *s, AVFrame *in, AVFrame *out,
784 int component, int intensity, int offset, int column)
786 const int plane = s->desc->comp[component].plane;
787 const int mirror = s->mirror;
788 const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
789 const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
790 const int dst_linesize = out->linesize[plane];
791 const int max = 255 - intensity;
792 const int src_h = in->height;
793 const int src_w = in->width;
797 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
799 for (x = 0; x < src_w; x++) {
800 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
801 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
802 uint8_t *dst_data = out->data[plane] + offset * dst_linesize;
803 uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
804 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
805 uint8_t *dst = dst_line;
807 for (y = 0; y < src_h; y++) {
808 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
812 for (p = 256 - sum; p < 256 + sum; p++) {
813 target = dst + x + dst_signed_linesize * p;
814 update(target, max, 1);
817 c0_data += c0_linesize;
818 c1_data += c1_linesize;
819 dst_data += dst_linesize;
823 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
824 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
825 uint8_t *dst_data = out->data[plane] + offset;
828 dst_data += s->size - 1;
829 for (y = 0; y < src_h; y++) {
830 for (x = 0; x < src_w; x++) {
831 const int sum = FFABS(c0_data[x] - 128) + FFABS(c1_data[x] - 128);
835 for (p = 256 - sum; p < 256 + sum; p++) {
837 target = dst_data - p;
839 target = dst_data + p;
841 update(target, max, 1);
845 c0_data += c0_linesize;
846 c1_data += c1_linesize;
847 dst_data += dst_linesize;
851 envelope(s, out, plane, (plane + 0) % s->ncomp);
854 static void achroma(WaveformContext *s, AVFrame *in, AVFrame *out,
855 int component, int intensity, int offset, int column)
857 const int plane = s->desc->comp[component].plane;
858 const int mirror = s->mirror;
859 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
860 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
861 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
862 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
863 const int max = 255 - intensity;
864 const int src_h = in->height;
865 const int src_w = in->width;
869 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
870 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
872 for (x = 0; x < src_w; x++) {
873 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
874 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
875 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
876 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
877 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
878 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
879 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
880 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
882 for (y = 0; y < src_h; y++) {
883 const int c1 = c1_data[x] - 128;
884 const int c2 = c2_data[x] - 128;
888 for (p = 128 + c1; p < 128; p++) {
889 target = d1 + x + d1_signed_linesize * p;
890 update(target, max, 1);
893 for (p = 128 + c1 - 1; p > 128; p--) {
894 target = d1 + x + d1_signed_linesize * p;
895 update(target, max, 1);
898 for (p = 128 + c2; p < 128; p++) {
899 target = d2 + x + d2_signed_linesize * p;
900 update(target, max, 1);
903 for (p = 128 + c2 - 1; p > 128; p--) {
904 target = d2 + x + d2_signed_linesize * p;
905 update(target, max, 1);
908 c1_data += c1_linesize;
909 c2_data += c2_linesize;
910 d1_data += d1_linesize;
911 d2_data += d2_linesize;
915 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
916 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
917 uint8_t *d0_data = out->data[plane] + offset;
918 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
919 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
922 d0_data += s->size - 1;
923 d1_data += s->size - 1;
924 d2_data += s->size - 1;
927 for (y = 0; y < src_h; y++) {
928 for (x = 0; x < src_w; x++) {
929 const int c1 = c1_data[x] - 128;
930 const int c2 = c2_data[x] - 128;
934 for (p = 128 + c1; p < 128; p++) {
936 target = d1_data - p;
938 target = d1_data + p;
940 update(target, max, 1);
943 for (p = 128 + 1; p < 128 + c1; p++) {
945 target = d1_data - p;
947 target = d1_data + p;
949 update(target, max, 1);
952 for (p = 128 + c2; p < 128; p++) {
954 target = d2_data - p;
956 target = d2_data + p;
958 update(target, max, 1);
961 for (p = 128 + 1; p < 128 + c2; p++) {
963 target = d2_data - p;
965 target = d2_data + p;
967 update(target, max, 1);
971 c1_data += c1_linesize;
972 c2_data += c2_linesize;
973 d1_data += d1_linesize;
974 d2_data += d2_linesize;
978 envelope(s, out, plane, (plane + 1) % s->ncomp);
979 envelope(s, out, plane, (plane + 2) % s->ncomp);
982 static void color16(WaveformContext *s, AVFrame *in, AVFrame *out,
983 int component, int intensity, int offset, int column)
985 const int plane = s->desc->comp[component].plane;
986 const int mirror = s->mirror;
987 const int limit = s->size - 1;
988 const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0];
989 const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp];
990 const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp];
991 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
992 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
993 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
994 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
995 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
996 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
997 const int src_h = in->height;
998 const int src_w = in->width;
1002 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1003 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1004 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1005 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset * d0_linesize;
1006 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
1007 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
1008 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1009 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1010 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1011 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1012 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1013 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1015 for (y = 0; y < src_h; y++) {
1016 for (x = 0; x < src_w; x++) {
1017 const int c0 = FFMIN(c0_data[x], limit);
1018 const int c1 = c1_data[x];
1019 const int c2 = c2_data[x];
1021 *(d0 + d0_signed_linesize * c0 + x) = c0;
1022 *(d1 + d1_signed_linesize * c0 + x) = c1;
1023 *(d2 + d2_signed_linesize * c0 + x) = c2;
1026 c0_data += c0_linesize;
1027 c1_data += c1_linesize;
1028 c2_data += c2_linesize;
1029 d0_data += d0_linesize;
1030 d1_data += d1_linesize;
1031 d2_data += d2_linesize;
1034 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset;
1035 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset;
1036 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset;
1039 d0_data += s->size - 1;
1040 d1_data += s->size - 1;
1041 d2_data += s->size - 1;
1044 for (y = 0; y < src_h; y++) {
1045 for (x = 0; x < src_w; x++) {
1046 const int c0 = FFMIN(c0_data[x], limit);
1047 const int c1 = c1_data[x];
1048 const int c2 = c2_data[x];
1051 *(d0_data - c0) = c0;
1052 *(d1_data - c0) = c1;
1053 *(d2_data - c0) = c2;
1055 *(d0_data + c0) = c0;
1056 *(d1_data + c0) = c1;
1057 *(d2_data + c0) = c2;
1061 c0_data += c0_linesize;
1062 c1_data += c1_linesize;
1063 c2_data += c2_linesize;
1064 d0_data += d0_linesize;
1065 d1_data += d1_linesize;
1066 d2_data += d2_linesize;
1070 envelope16(s, out, plane, plane);
1073 static void color(WaveformContext *s, AVFrame *in, AVFrame *out,
1074 int component, int intensity, int offset, int column)
1076 const int plane = s->desc->comp[component].plane;
1077 const int mirror = s->mirror;
1078 const uint8_t *c0_data = in->data[plane + 0];
1079 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
1080 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
1081 const int c0_linesize = in->linesize[ plane + 0 ];
1082 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1083 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1084 const int d0_linesize = out->linesize[ plane + 0 ];
1085 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1086 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1087 const int src_h = in->height;
1088 const int src_w = in->width;
1092 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1093 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1094 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1095 uint8_t *d0_data = out->data[plane] + offset * d0_linesize;
1096 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset * d1_linesize;
1097 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset * d2_linesize;
1098 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1099 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1100 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1101 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1102 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1103 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1105 for (y = 0; y < src_h; y++) {
1106 for (x = 0; x < src_w; x++) {
1107 const int c0 = c0_data[x];
1108 const int c1 = c1_data[x];
1109 const int c2 = c2_data[x];
1111 *(d0 + d0_signed_linesize * c0 + x) = c0;
1112 *(d1 + d1_signed_linesize * c0 + x) = c1;
1113 *(d2 + d2_signed_linesize * c0 + x) = c2;
1116 c0_data += c0_linesize;
1117 c1_data += c1_linesize;
1118 c2_data += c2_linesize;
1119 d0_data += d0_linesize;
1120 d1_data += d1_linesize;
1121 d2_data += d2_linesize;
1124 uint8_t *d0_data = out->data[plane] + offset;
1125 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset;
1126 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset;
1129 d0_data += s->size - 1;
1130 d1_data += s->size - 1;
1131 d2_data += s->size - 1;
1134 for (y = 0; y < src_h; y++) {
1135 for (x = 0; x < src_w; x++) {
1136 const int c0 = c0_data[x];
1137 const int c1 = c1_data[x];
1138 const int c2 = c2_data[x];
1141 *(d0_data - c0) = c0;
1142 *(d1_data - c0) = c1;
1143 *(d2_data - c0) = c2;
1145 *(d0_data + c0) = c0;
1146 *(d1_data + c0) = c1;
1147 *(d2_data + c0) = c2;
1151 c0_data += c0_linesize;
1152 c1_data += c1_linesize;
1153 c2_data += c2_linesize;
1154 d0_data += d0_linesize;
1155 d1_data += d1_linesize;
1156 d2_data += d2_linesize;
1160 envelope(s, out, plane, plane);
1163 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
1164 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
1166 static int config_input(AVFilterLink *inlink)
1168 AVFilterContext *ctx = inlink->dst;
1169 WaveformContext *s = ctx->priv;
1171 s->desc = av_pix_fmt_desc_get(inlink->format);
1172 s->ncomp = s->desc->nb_components;
1173 s->bits = s->desc->comp[0].depth_minus1 + 1;
1175 switch (s->filter) {
1178 s->waveform = s->bits > 8 ? lowpass16 : lowpass; break;
1181 s->waveform = flat; break;
1184 s->waveform = aflat; break;
1187 s->waveform = chroma; break;
1190 s->waveform = achroma; break;
1193 s->waveform = s->bits > 8 ? color16 : color; break;
1196 s->size = s->size << (s->bits - 8);
1198 switch (inlink->format) {
1199 case AV_PIX_FMT_GBRAP:
1200 case AV_PIX_FMT_GBRP:
1201 case AV_PIX_FMT_GBRP9:
1202 case AV_PIX_FMT_GBRP10:
1203 s->bg_color = black_gbrp_color;
1206 s->bg_color = black_yuva_color;
1212 static int config_output(AVFilterLink *outlink)
1214 AVFilterContext *ctx = outlink->src;
1215 AVFilterLink *inlink = ctx->inputs[0];
1216 WaveformContext *s = ctx->priv;
1217 int comp = 0, i, j = 0, k, p, size, shift;
1219 for (i = 0; i < s->ncomp; i++) {
1220 if ((1 << i) & s->pcomp)
1227 outlink->h = s->size * FFMAX(comp * s->display, 1);
1230 outlink->w = s->size * FFMAX(comp * s->display, 1);
1234 s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
1236 return AVERROR(ENOMEM);
1238 for (p = 0; p < 4; p++) {
1239 const int is_chroma = (p == 1 || p == 2);
1240 const int shift_w = (is_chroma ? s->desc->log2_chroma_w : 0);
1241 const int shift_h = (is_chroma ? s->desc->log2_chroma_h : 0);
1242 const int plane = s->desc->comp[p].plane;
1245 if (!((1 << p) & s->pcomp))
1248 shift = s->mode ? shift_h : shift_w;
1250 for (k = 0; k < 4; k++) {
1251 s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
1252 s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
1255 offset = j++ * s->size * s->display;
1256 s->estart[plane] = offset >> shift;
1257 s->eend[plane] = (offset + s->size - 1) >> shift;
1258 for (i = 0; i < size; i++) {
1259 for (k = 0; k < 4; k++) {
1260 s->emax[plane][k][i] = s->estart[plane];
1261 s->emin[plane][k][i] = s->eend[plane];
1266 outlink->sample_aspect_ratio = (AVRational){1,1};
1271 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
1273 AVFilterContext *ctx = inlink->dst;
1274 WaveformContext *s = ctx->priv;
1275 AVFilterLink *outlink = ctx->outputs[0];
1279 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
1282 return AVERROR(ENOMEM);
1286 for (k = 0; k < s->ncomp; k++) {
1287 const int is_chroma = (k == 1 || k == 2);
1288 const int dst_h = FF_CEIL_RSHIFT(outlink->h, (is_chroma ? s->desc->log2_chroma_h : 0));
1289 const int dst_w = FF_CEIL_RSHIFT(outlink->w, (is_chroma ? s->desc->log2_chroma_w : 0));
1291 for (i = 0; i < dst_h ; i++)
1292 memset(out->data[s->desc->comp[k].plane] +
1293 i * out->linesize[s->desc->comp[k].plane],
1294 s->bg_color[k], dst_w);
1296 const int mult = s->size / 256;
1297 uint16_t *dst = (uint16_t *)out->data[s->desc->comp[k].plane];
1299 for (i = 0; i < dst_h ; i++) {
1300 for (j = 0; j < dst_w; j++)
1301 dst[j] = s->bg_color[k] * mult;
1302 dst += out->linesize[s->desc->comp[k].plane] / 2;
1307 for (k = 0, i = 0; k < s->ncomp; k++) {
1308 if ((1 << k) & s->pcomp) {
1309 const int offset = i++ * s->size * s->display;
1310 s->waveform(s, in, out, k, s->intensity, offset, s->mode);
1315 return ff_filter_frame(outlink, out);
1318 static av_cold void uninit(AVFilterContext *ctx)
1320 WaveformContext *s = ctx->priv;
1325 static const AVFilterPad inputs[] = {
1328 .type = AVMEDIA_TYPE_VIDEO,
1329 .filter_frame = filter_frame,
1330 .config_props = config_input,
1335 static const AVFilterPad outputs[] = {
1338 .type = AVMEDIA_TYPE_VIDEO,
1339 .config_props = config_output,
1344 AVFilter ff_vf_waveform = {
1346 .description = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
1347 .priv_size = sizeof(WaveformContext),
1348 .priv_class = &waveform_class,
1349 .query_formats = query_formats,