2 * Copyright (c) 2012-2016 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"
26 #include "libavutil/xga_font_data.h"
32 typedef struct ThreadData {
73 typedef struct GraticuleLine {
78 typedef struct GraticuleLines {
79 struct GraticuleLine line[4];
82 typedef struct WaveformContext {
109 uint8_t grat_yuva_color[4];
110 int shift_w[4], shift_h[4];
111 GraticuleLines *glines;
115 int (*waveform_slice)(AVFilterContext *ctx, void *arg,
116 int jobnr, int nb_jobs);
117 void (*graticulef)(struct WaveformContext *s, AVFrame *out);
118 void (*blend_line)(uint8_t *dst, int size, int linesize, float o1, float o2,
120 void (*draw_text)(AVFrame *out, int x, int y, int mult,
121 float o1, float o2, const char *txt,
122 const uint8_t color[4]);
123 const AVPixFmtDescriptor *desc;
124 const AVPixFmtDescriptor *odesc;
127 #define OFFSET(x) offsetof(WaveformContext, x)
128 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
130 static const AVOption waveform_options[] = {
131 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
132 { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "mode" },
133 { "row", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" },
134 { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" },
135 { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
136 { "i", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, FLAGS },
137 { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
138 { "r", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
139 { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
140 { "d", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, "display" },
141 { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY}, 0, 0, FLAGS, "display" },
142 { "stack", NULL, 0, AV_OPT_TYPE_CONST, {.i64=STACK}, 0, 0, FLAGS, "display" },
143 { "parade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PARADE}, 0, 0, FLAGS, "display" },
144 { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
145 { "c", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
146 { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
147 { "e", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "envelope" },
148 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "envelope" },
149 { "instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "envelope" },
150 { "peak", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "envelope" },
151 { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "envelope" },
152 { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
153 { "f", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, "filter" },
154 { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, "filter" },
155 { "flat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, "filter" },
156 { "aflat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT}, 0, 0, FLAGS, "filter" },
157 { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA}, 0, 0, FLAGS, "filter" },
158 { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR}, 0, 0, FLAGS, "filter" },
159 { "acolor", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACOLOR}, 0, 0, FLAGS, "filter" },
160 { "xflat", NULL, 0, AV_OPT_TYPE_CONST, {.i64=XFLAT}, 0, 0, FLAGS, "filter" },
161 { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, "graticule" },
162 { "g", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, "graticule" },
163 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_NONE}, 0, 0, FLAGS, "graticule" },
164 { "green", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_GREEN}, 0, 0, FLAGS, "graticule" },
165 { "orange", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_ORANGE}, 0, 0, FLAGS, "graticule" },
166 { "invert", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_INVERT}, 0, 0, FLAGS, "graticule" },
167 { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
168 { "o", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
169 { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
170 { "fl", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" },
171 { "numbers", "draw numbers", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "flags" },
172 { "dots", "draw dots instead of lines", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "flags" },
173 { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
174 { "s", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, "scale" },
175 { "digital", NULL, 0, AV_OPT_TYPE_CONST, {.i64=DIGITAL}, 0, 0, FLAGS, "scale" },
176 { "millivolts", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MILLIVOLTS}, 0, 0, FLAGS, "scale" },
177 { "ire", NULL, 0, AV_OPT_TYPE_CONST, {.i64=IRE}, 0, 0, FLAGS, "scale" },
178 { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
179 { "b", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS },
183 AVFILTER_DEFINE_CLASS(waveform);
185 static const enum AVPixelFormat in_lowpass_pix_fmts[] = {
186 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
187 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
188 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
189 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
190 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
191 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
192 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
193 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
194 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
195 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
196 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
197 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
198 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
199 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
203 static const enum AVPixelFormat in_color_pix_fmts[] = {
204 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
205 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
206 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
207 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
209 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
210 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
211 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
212 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
213 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
214 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
215 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
216 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
220 static const enum AVPixelFormat in_flat_pix_fmts[] = {
221 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
222 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
224 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
225 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
226 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
227 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
228 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
229 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
230 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
231 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
235 static const enum AVPixelFormat out_rgb8_lowpass_pix_fmts[] = {
236 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
240 static const enum AVPixelFormat out_rgb9_lowpass_pix_fmts[] = {
245 static const enum AVPixelFormat out_rgb10_lowpass_pix_fmts[] = {
246 AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
250 static const enum AVPixelFormat out_rgb12_lowpass_pix_fmts[] = {
251 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
255 static const enum AVPixelFormat out_yuv8_lowpass_pix_fmts[] = {
256 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P,
260 static const enum AVPixelFormat out_yuv9_lowpass_pix_fmts[] = {
261 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9,
265 static const enum AVPixelFormat out_yuv10_lowpass_pix_fmts[] = {
266 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
270 static const enum AVPixelFormat out_yuv12_lowpass_pix_fmts[] = {
271 AV_PIX_FMT_YUV444P12,
275 static const enum AVPixelFormat out_gray8_lowpass_pix_fmts[] = {
280 static const enum AVPixelFormat out_gray9_lowpass_pix_fmts[] = {
285 static const enum AVPixelFormat out_gray10_lowpass_pix_fmts[] = {
290 static const enum AVPixelFormat out_gray12_lowpass_pix_fmts[] = {
295 static const enum AVPixelFormat flat_pix_fmts[] = {
296 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
297 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10,
298 AV_PIX_FMT_YUV444P12,
302 static int query_formats(AVFilterContext *ctx)
304 WaveformContext *s = ctx->priv;
305 const enum AVPixelFormat *out_pix_fmts;
306 const enum AVPixelFormat *in_pix_fmts;
307 const AVPixFmtDescriptor *desc, *desc2;
308 AVFilterFormats *avff, *avff2;
309 int depth, depth2, rgb, i, ret, ncomp, ncomp2;
311 if (!ctx->inputs[0]->in_formats ||
312 !ctx->inputs[0]->in_formats->nb_formats) {
313 return AVERROR(EAGAIN);
317 case LOWPASS: in_pix_fmts = in_lowpass_pix_fmts; break;
321 case FLAT: in_pix_fmts = in_flat_pix_fmts; break;
323 case COLOR: in_pix_fmts = in_color_pix_fmts; break;
324 default: return AVERROR_BUG;
327 if (!ctx->inputs[0]->out_formats) {
328 if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->out_formats)) < 0)
332 avff = ctx->inputs[0]->in_formats;
333 avff2 = ctx->inputs[0]->out_formats;
334 desc = av_pix_fmt_desc_get(avff->formats[0]);
335 desc2 = av_pix_fmt_desc_get(avff2->formats[0]);
336 ncomp = desc->nb_components;
337 ncomp2 = desc2->nb_components;
338 rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
339 depth = desc->comp[0].depth;
340 depth2 = desc2->comp[0].depth;
341 if (ncomp != ncomp2 || depth != depth2)
342 return AVERROR(EAGAIN);
343 for (i = 1; i < avff->nb_formats; i++) {
344 desc = av_pix_fmt_desc_get(avff->formats[i]);
345 if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
346 depth != desc->comp[0].depth)
347 return AVERROR(EAGAIN);
350 if (s->filter == LOWPASS && ncomp == 1 && depth == 8)
351 out_pix_fmts = out_gray8_lowpass_pix_fmts;
352 else if (s->filter == LOWPASS && ncomp == 1 && depth == 9)
353 out_pix_fmts = out_gray9_lowpass_pix_fmts;
354 else if (s->filter == LOWPASS && ncomp == 1 && depth == 10)
355 out_pix_fmts = out_gray10_lowpass_pix_fmts;
356 else if (s->filter == LOWPASS && ncomp == 1 && depth == 12)
357 out_pix_fmts = out_gray12_lowpass_pix_fmts;
358 else if (rgb && depth == 8 && ncomp > 2)
359 out_pix_fmts = out_rgb8_lowpass_pix_fmts;
360 else if (rgb && depth == 9 && ncomp > 2)
361 out_pix_fmts = out_rgb9_lowpass_pix_fmts;
362 else if (rgb && depth == 10 && ncomp > 2)
363 out_pix_fmts = out_rgb10_lowpass_pix_fmts;
364 else if (rgb && depth == 12 && ncomp > 2)
365 out_pix_fmts = out_rgb12_lowpass_pix_fmts;
366 else if (depth == 8 && ncomp > 2)
367 out_pix_fmts = out_yuv8_lowpass_pix_fmts;
368 else if (depth == 9 && ncomp > 2)
369 out_pix_fmts = out_yuv9_lowpass_pix_fmts;
370 else if (depth == 10 && ncomp > 2)
371 out_pix_fmts = out_yuv10_lowpass_pix_fmts;
372 else if (depth == 12 && ncomp > 2)
373 out_pix_fmts = out_yuv12_lowpass_pix_fmts;
375 return AVERROR(EAGAIN);
376 if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats)) < 0)
382 static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
384 const int dst_linesize = out->linesize[component] / 2;
385 const int bg = s->bg_color[component] * (s->max / 256);
386 const int limit = s->max - 1;
387 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
388 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
389 const int start = s->estart[plane];
390 const int end = s->eend[plane];
395 for (x = offset; x < offset + dst_w; x++) {
396 for (y = start; y < end; y++) {
397 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
403 for (y = end - 1; y >= start; y--) {
404 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
412 for (y = offset; y < offset + dst_h; y++) {
413 dst = (uint16_t *)out->data[component] + y * dst_linesize;
414 for (x = start; x < end; x++) {
420 for (x = end - 1; x >= start; x--) {
430 static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
432 const int dst_linesize = out->linesize[component];
433 const uint8_t bg = s->bg_color[component];
434 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
435 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
436 const int start = s->estart[plane];
437 const int end = s->eend[plane];
442 for (x = offset; x < offset + dst_w; x++) {
443 for (y = start; y < end; y++) {
444 dst = out->data[component] + y * dst_linesize + x;
450 for (y = end - 1; y >= start; y--) {
451 dst = out->data[component] + y * dst_linesize + x;
459 for (y = offset; y < offset + dst_h; y++) {
460 dst = out->data[component] + y * dst_linesize;
461 for (x = start; x < end; x++) {
467 for (x = end - 1; x >= start; x--) {
477 static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
479 const int dst_linesize = out->linesize[component] / 2;
480 const int bg = s->bg_color[component] * (s->max / 256);
481 const int limit = s->max - 1;
482 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
483 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
484 const int start = s->estart[plane];
485 const int end = s->eend[plane];
486 int *emax = s->emax[plane][component];
487 int *emin = s->emin[plane][component];
492 for (x = offset; x < offset + dst_w; x++) {
493 for (y = start; y < end && y < emin[x - offset]; y++) {
494 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
496 emin[x - offset] = y;
500 for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
501 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
503 emax[x - offset] = y;
509 if (s->envelope == 3)
510 envelope_instant16(s, out, plane, component, offset);
512 for (x = offset; x < offset + dst_w; x++) {
513 dst = (uint16_t *)out->data[component] + emin[x - offset] * dst_linesize + x;
515 dst = (uint16_t *)out->data[component] + emax[x - offset] * dst_linesize + x;
519 for (y = offset; y < offset + dst_h; y++) {
520 dst = (uint16_t *)out->data[component] + y * dst_linesize;
521 for (x = start; x < end && x < emin[y - offset]; x++) {
523 emin[y - offset] = x;
527 for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
529 emax[y - offset] = x;
535 if (s->envelope == 3)
536 envelope_instant16(s, out, plane, component, offset);
538 for (y = offset; y < offset + dst_h; y++) {
539 dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y - offset];
541 dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y - offset];
547 static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
549 const int dst_linesize = out->linesize[component];
550 const int bg = s->bg_color[component];
551 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
552 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
553 const int start = s->estart[plane];
554 const int end = s->eend[plane];
555 int *emax = s->emax[plane][component];
556 int *emin = s->emin[plane][component];
561 for (x = offset; x < offset + dst_w; x++) {
562 for (y = start; y < end && y < emin[x - offset]; y++) {
563 dst = out->data[component] + y * dst_linesize + x;
565 emin[x - offset] = y;
569 for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
570 dst = out->data[component] + y * dst_linesize + x;
572 emax[x - offset] = y;
578 if (s->envelope == 3)
579 envelope_instant(s, out, plane, component, offset);
581 for (x = offset; x < offset + dst_w; x++) {
582 dst = out->data[component] + emin[x - offset] * dst_linesize + x;
584 dst = out->data[component] + emax[x - offset] * dst_linesize + x;
588 for (y = offset; y < offset + dst_h; y++) {
589 dst = out->data[component] + y * dst_linesize;
590 for (x = start; x < end && x < emin[y - offset]; x++) {
592 emin[y - offset] = x;
596 for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
598 emax[y - offset] = x;
604 if (s->envelope == 3)
605 envelope_instant(s, out, plane, component, offset);
607 for (y = offset; y < offset + dst_h; y++) {
608 dst = out->data[component] + y * dst_linesize + emin[y - offset];
610 dst = out->data[component] + y * dst_linesize + emax[y - offset];
616 static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
618 if (s->envelope == 0) {
620 } else if (s->envelope == 1) {
621 envelope_instant16(s, out, plane, component, offset);
623 envelope_peak16(s, out, plane, component, offset);
627 static void envelope(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
629 if (s->envelope == 0) {
631 } else if (s->envelope == 1) {
632 envelope_instant(s, out, plane, component, offset);
634 envelope_peak(s, out, plane, component, offset);
638 static void update16(uint16_t *target, int max, int intensity, int limit)
641 *target += intensity;
646 static void update(uint8_t *target, int max, int intensity)
649 *target += intensity;
654 static void update_cr(uint8_t *target, int unused, int intensity)
656 if (*target - intensity > 0)
657 *target -= intensity;
662 static void update16_cr(uint16_t *target, int unused, int intensity, int limit)
664 if (*target - intensity > 0)
665 *target -= intensity;
670 static av_always_inline void lowpass16(WaveformContext *s,
671 AVFrame *in, AVFrame *out,
672 int component, int intensity,
673 int offset_y, int offset_x,
674 int column, int mirror,
675 int jobnr, int nb_jobs)
677 const int plane = s->desc->comp[component].plane;
678 const int shift_w = s->shift_w[component];
679 const int shift_h = s->shift_h[component];
680 const int src_linesize = in->linesize[plane] / 2;
681 const int dst_linesize = out->linesize[plane] / 2;
682 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
683 const int limit = s->max - 1;
684 const int max = limit - intensity;
685 const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
686 const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
687 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
688 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
689 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
690 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
691 const int step = column ? 1 << shift_w : 1 << shift_h;
692 const uint16_t *src_data = (const uint16_t *)in->data[plane] + sliceh_start * src_linesize;
693 uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
694 uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
695 uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
699 if (!column && mirror)
702 for (y = sliceh_start; y < sliceh_end; y++) {
703 const uint16_t *src_data_end = src_data + slicew_end;
704 uint16_t *dst = dst_line + slicew_start * step;
706 for (p = src_data + slicew_start; p < src_data_end; p++) {
708 int i = 0, v = FFMIN(*p, limit);
712 target = dst++ + dst_signed_linesize * v;
713 update16(target, max, intensity, limit);
714 } while (++i < step);
716 uint16_t *row = dst_data;
719 target = row - v - 1;
722 update16(target, max, intensity, limit);
724 } while (++i < step);
727 src_data += src_linesize;
728 dst_data += dst_linesize * step;
732 #define LOWPASS16_FUNC(name, column, mirror) \
733 static int lowpass16_##name(AVFilterContext *ctx, \
734 void *arg, int jobnr, \
737 WaveformContext *s = ctx->priv; \
738 ThreadData *td = arg; \
739 AVFrame *in = td->in; \
740 AVFrame *out = td->out; \
741 int component = td->component; \
742 int offset_y = td->offset_y; \
743 int offset_x = td->offset_x; \
745 lowpass16(s, in, out, component, s->intensity, \
746 offset_y, offset_x, column, mirror, \
752 LOWPASS16_FUNC(column_mirror, 1, 1)
753 LOWPASS16_FUNC(column, 1, 0)
754 LOWPASS16_FUNC(row_mirror, 0, 1)
755 LOWPASS16_FUNC(row, 0, 0)
757 static av_always_inline void lowpass(WaveformContext *s,
758 AVFrame *in, AVFrame *out,
759 int component, int intensity,
760 int offset_y, int offset_x,
761 int column, int mirror,
762 int jobnr, int nb_jobs)
764 const int plane = s->desc->comp[component].plane;
765 const int shift_w = s->shift_w[component];
766 const int shift_h = s->shift_h[component];
767 const int src_linesize = in->linesize[plane];
768 const int dst_linesize = out->linesize[plane];
769 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
770 const int max = 255 - intensity;
771 const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
772 const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
773 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
774 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
775 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
776 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
777 const int step = column ? 1 << shift_w : 1 << shift_h;
778 const uint8_t *src_data = in->data[plane] + sliceh_start * src_linesize;
779 uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
780 uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
781 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
785 if (!column && mirror)
788 for (y = sliceh_start; y < sliceh_end; y++) {
789 const uint8_t *src_data_end = src_data + slicew_end;
790 uint8_t *dst = dst_line + slicew_start * step;
792 for (p = src_data + slicew_start; p < src_data_end; p++) {
795 target = dst + dst_signed_linesize * *p;
797 update(target, max, intensity);
799 uint8_t *row = dst_data;
801 target = row - *p - 1;
804 update(target, max, intensity);
808 src_data += src_linesize;
809 dst_data += dst_linesize * step;
812 if (column && step > 1) {
813 const int dst_h = 256;
817 dst = out->data[plane] + offset_y * dst_linesize + offset_x;
818 for (y = 0; y < dst_h; y++) {
819 for (x = slicew_start * step; x < slicew_end * step; x+=step) {
820 for (z = 1; z < step; z++) {
826 } else if (step > 1) {
827 const int dst_w = 256;
831 dst = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
832 for (y = sliceh_start * step; y < sliceh_end * step; y+=step) {
833 for (z = 1; z < step; z++)
834 memcpy(dst + dst_linesize * z, dst, dst_w);
835 dst += dst_linesize * step;
840 #define LOWPASS_FUNC(name, column, mirror) \
841 static int lowpass_##name(AVFilterContext *ctx, \
842 void *arg, int jobnr, \
845 WaveformContext *s = ctx->priv; \
846 ThreadData *td = arg; \
847 AVFrame *in = td->in; \
848 AVFrame *out = td->out; \
849 int component = td->component; \
850 int offset_y = td->offset_y; \
851 int offset_x = td->offset_x; \
853 lowpass(s, in, out, component, s->intensity, \
854 offset_y, offset_x, column, mirror, \
860 LOWPASS_FUNC(column_mirror, 1, 1)
861 LOWPASS_FUNC(column, 1, 0)
862 LOWPASS_FUNC(row_mirror, 0, 1)
863 LOWPASS_FUNC(row, 0, 0)
865 static av_always_inline void flat16(WaveformContext *s,
866 AVFrame *in, AVFrame *out,
867 int component, int intensity,
868 int offset_y, int offset_x,
869 int column, int mirror,
870 int jobnr, int nb_jobs)
872 const int plane = s->desc->comp[component].plane;
873 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
874 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
875 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
876 const int c0_shift_w = s->shift_w[ component + 0 ];
877 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
878 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
879 const int c0_shift_h = s->shift_h[ component + 0 ];
880 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
881 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
882 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
883 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
884 const int limit = s->max - 1;
885 const int max = limit - intensity;
886 const int mid = s->max / 2;
887 const int src_h = in->height;
888 const int src_w = in->width;
889 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
890 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
891 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
892 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
896 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
897 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
899 for (x = slicew_start; x < slicew_end; x++) {
900 const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];
901 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
902 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
903 uint16_t *d0_data = (uint16_t *)(out->data[plane]) + offset_y * d0_linesize + offset_x;
904 uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + offset_y * d1_linesize + offset_x;
905 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
906 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
907 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
908 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
910 for (y = 0; y < src_h; y++) {
911 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
912 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
915 target = d0 + x + d0_signed_linesize * c0;
916 update16(target, max, intensity, limit);
917 target = d1 + x + d1_signed_linesize * (c0 - c1);
918 update16(target, max, intensity, limit);
919 target = d1 + x + d1_signed_linesize * (c0 + c1);
920 update16(target, max, intensity, limit);
922 if (!c0_shift_h || (y & c0_shift_h))
923 c0_data += c0_linesize;
924 if (!c1_shift_h || (y & c1_shift_h))
925 c1_data += c1_linesize;
926 if (!c2_shift_h || (y & c2_shift_h))
927 c2_data += c2_linesize;
928 d0_data += d0_linesize;
929 d1_data += d1_linesize;
933 const uint16_t *c0_data = (uint16_t *)(in->data[plane]) + (sliceh_start >> c0_shift_h) * c0_linesize;
934 const uint16_t *c1_data = (uint16_t *)(in->data[(plane + 1) % s->ncomp]) + (sliceh_start >> c1_shift_h) * c1_linesize;
935 const uint16_t *c2_data = (uint16_t *)(in->data[(plane + 2) % s->ncomp]) + (sliceh_start >> c2_shift_h) * c2_linesize;
936 uint16_t *d0_data = (uint16_t *)(out->data[plane]) + (offset_y + sliceh_start) * d0_linesize + offset_x;
937 uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + (offset_y + sliceh_start) * d1_linesize + offset_x;
940 d0_data += s->size - 1;
941 d1_data += s->size - 1;
944 for (y = sliceh_start; y < sliceh_end; y++) {
945 for (x = 0; x < src_w; x++) {
946 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
947 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
951 target = d0_data - c0;
952 update16(target, max, intensity, limit);
953 target = d1_data - (c0 - c1);
954 update16(target, max, intensity, limit);
955 target = d1_data - (c0 + c1);
956 update16(target, max, intensity, limit);
958 target = d0_data + c0;
959 update16(target, max, intensity, limit);
960 target = d1_data + (c0 - c1);
961 update16(target, max, intensity, limit);
962 target = d1_data + (c0 + c1);
963 update16(target, max, intensity, limit);
967 if (!c0_shift_h || (y & c0_shift_h))
968 c0_data += c0_linesize;
969 if (!c1_shift_h || (y & c1_shift_h))
970 c1_data += c1_linesize;
971 if (!c2_shift_h || (y & c2_shift_h))
972 c2_data += c2_linesize;
973 d0_data += d0_linesize;
974 d1_data += d1_linesize;
979 #define FLAT16_FUNC(name, column, mirror) \
980 static int flat16_##name(AVFilterContext *ctx, \
981 void *arg, int jobnr, \
984 WaveformContext *s = ctx->priv; \
985 ThreadData *td = arg; \
986 AVFrame *in = td->in; \
987 AVFrame *out = td->out; \
988 int component = td->component; \
989 int offset_y = td->offset_y; \
990 int offset_x = td->offset_x; \
992 flat16(s, in, out, component, s->intensity, \
993 offset_y, offset_x, column, mirror, \
999 FLAT16_FUNC(column_mirror, 1, 1)
1000 FLAT16_FUNC(column, 1, 0)
1001 FLAT16_FUNC(row_mirror, 0, 1)
1002 FLAT16_FUNC(row, 0, 0)
1004 static av_always_inline void flat(WaveformContext *s,
1005 AVFrame *in, AVFrame *out,
1006 int component, int intensity,
1007 int offset_y, int offset_x,
1008 int column, int mirror,
1009 int jobnr, int nb_jobs)
1011 const int plane = s->desc->comp[component].plane;
1012 const int c0_linesize = in->linesize[ plane + 0 ];
1013 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1014 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1015 const int c0_shift_w = s->shift_w[ component + 0 ];
1016 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1017 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1018 const int c0_shift_h = s->shift_h[ component + 0 ];
1019 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1020 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1021 const int d0_linesize = out->linesize[ plane + 0 ];
1022 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1023 const int max = 255 - intensity;
1024 const int src_h = in->height;
1025 const int src_w = in->width;
1026 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1027 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1028 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1029 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1033 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1034 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1036 for (x = slicew_start; x < slicew_end; x++) {
1037 const uint8_t *c0_data = in->data[plane + 0];
1038 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
1039 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
1040 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1041 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1042 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1043 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1044 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1045 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1047 for (y = 0; y < src_h; y++) {
1048 const int c0 = c0_data[x >> c0_shift_w] + 256;
1049 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1052 target = d0 + x + d0_signed_linesize * c0;
1053 update(target, max, intensity);
1054 target = d1 + x + d1_signed_linesize * (c0 - c1);
1055 update(target, max, intensity);
1056 target = d1 + x + d1_signed_linesize * (c0 + c1);
1057 update(target, max, intensity);
1059 if (!c0_shift_h || (y & c0_shift_h))
1060 c0_data += c0_linesize;
1061 if (!c1_shift_h || (y & c1_shift_h))
1062 c1_data += c1_linesize;
1063 if (!c2_shift_h || (y & c2_shift_h))
1064 c2_data += c2_linesize;
1065 d0_data += d0_linesize;
1066 d1_data += d1_linesize;
1070 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;
1071 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1072 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1073 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1074 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1077 d0_data += s->size - 1;
1078 d1_data += s->size - 1;
1081 for (y = sliceh_start; y < sliceh_end; y++) {
1082 for (x = 0; x < src_w; x++) {
1083 const int c0 = c0_data[x >> c0_shift_w] + 256;
1084 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1088 target = d0_data - c0;
1089 update(target, max, intensity);
1090 target = d1_data - (c0 - c1);
1091 update(target, max, intensity);
1092 target = d1_data - (c0 + c1);
1093 update(target, max, intensity);
1095 target = d0_data + c0;
1096 update(target, max, intensity);
1097 target = d1_data + (c0 - c1);
1098 update(target, max, intensity);
1099 target = d1_data + (c0 + c1);
1100 update(target, max, intensity);
1104 if (!c0_shift_h || (y & c0_shift_h))
1105 c0_data += c0_linesize;
1106 if (!c1_shift_h || (y & c1_shift_h))
1107 c1_data += c1_linesize;
1108 if (!c2_shift_h || (y & c2_shift_h))
1109 c2_data += c2_linesize;
1110 d0_data += d0_linesize;
1111 d1_data += d1_linesize;
1116 #define FLAT_FUNC(name, column, mirror) \
1117 static int flat_##name(AVFilterContext *ctx, \
1118 void *arg, int jobnr, \
1121 WaveformContext *s = ctx->priv; \
1122 ThreadData *td = arg; \
1123 AVFrame *in = td->in; \
1124 AVFrame *out = td->out; \
1125 int component = td->component; \
1126 int offset_y = td->offset_y; \
1127 int offset_x = td->offset_x; \
1129 flat(s, in, out, component, s->intensity, \
1130 offset_y, offset_x, column, mirror, \
1136 FLAT_FUNC(column_mirror, 1, 1)
1137 FLAT_FUNC(column, 1, 0)
1138 FLAT_FUNC(row_mirror, 0, 1)
1139 FLAT_FUNC(row, 0, 0)
1141 #define AFLAT16(name, update_cr, column, mirror) \
1142 static int name(AVFilterContext *ctx, \
1143 void *arg, int jobnr, \
1146 WaveformContext *s = ctx->priv; \
1147 ThreadData *td = arg; \
1148 AVFrame *in = td->in; \
1149 AVFrame *out = td->out; \
1150 int component = td->component; \
1151 int offset_y = td->offset_y; \
1152 int offset_x = td->offset_x; \
1153 const int intensity = s->intensity; \
1154 const int plane = s->desc->comp[component].plane; \
1155 const int c0_linesize = in->linesize[ plane + 0 ] / 2; \
1156 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; \
1157 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; \
1158 const int c0_shift_w = s->shift_w[ component + 0 ]; \
1159 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \
1160 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \
1161 const int c0_shift_h = s->shift_h[ component + 0 ]; \
1162 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \
1163 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \
1164 const int d0_linesize = out->linesize[ plane + 0 ] / 2; \
1165 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; \
1166 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; \
1167 const int limit = s->max - 1; \
1168 const int max = limit - intensity; \
1169 const int mid = s->max / 2; \
1170 const int src_h = in->height; \
1171 const int src_w = in->width; \
1172 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \
1173 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \
1174 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \
1175 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \
1179 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \
1180 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \
1181 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \
1183 for (x = slicew_start; x < slicew_end; x++) { \
1184 const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; \
1185 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \
1186 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \
1187 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; \
1188 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1189 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1190 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \
1191 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data); \
1192 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \
1193 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data); \
1194 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \
1195 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); \
1197 for (y = 0; y < src_h; y++) { \
1198 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \
1199 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \
1200 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \
1203 target = d0 + x + d0_signed_linesize * c0; \
1204 update16(target, max, intensity, limit); \
1206 target = d1 + x + d1_signed_linesize * (c0 + c1); \
1207 update16(target, max, intensity, limit); \
1209 target = d2 + x + d2_signed_linesize * (c0 + c2); \
1210 update_cr(target, max, intensity, limit); \
1212 if (!c0_shift_h || (y & c0_shift_h)) \
1213 c0_data += c0_linesize; \
1214 if (!c1_shift_h || (y & c1_shift_h)) \
1215 c1_data += c1_linesize; \
1216 if (!c2_shift_h || (y & c2_shift_h)) \
1217 c2_data += c2_linesize; \
1218 d0_data += d0_linesize; \
1219 d1_data += d1_linesize; \
1220 d2_data += d2_linesize; \
1224 const uint16_t *c0_data = (uint16_t *)in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \
1225 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1226 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1227 uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \
1228 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
1229 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
1232 d0_data += s->size - 1; \
1233 d1_data += s->size - 1; \
1234 d2_data += s->size - 1; \
1237 for (y = sliceh_start; y < sliceh_end; y++) { \
1238 for (x = 0; x < src_w; x++) { \
1239 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \
1240 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \
1241 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \
1245 target = d0_data - c0; \
1246 update16(target, max, intensity, limit); \
1247 target = d1_data - (c0 + c1); \
1248 update16(target, max, intensity, limit); \
1249 target = d2_data - (c0 + c2); \
1250 update_cr(target, max, intensity, limit); \
1252 target = d0_data + c0; \
1253 update16(target, max, intensity, limit); \
1254 target = d1_data + (c0 + c1); \
1255 update16(target, max, intensity, limit); \
1256 target = d2_data + (c0 + c2); \
1257 update_cr(target, max, intensity, limit); \
1261 if (!c0_shift_h || (y & c0_shift_h)) \
1262 c0_data += c0_linesize; \
1263 if (!c1_shift_h || (y & c1_shift_h)) \
1264 c1_data += c1_linesize; \
1265 if (!c2_shift_h || (y & c2_shift_h)) \
1266 c2_data += c2_linesize; \
1267 d0_data += d0_linesize; \
1268 d1_data += d1_linesize; \
1269 d2_data += d2_linesize; \
1275 #define AFLAT(name, update_cr, column, mirror) \
1276 static int name(AVFilterContext *ctx, \
1277 void *arg, int jobnr, \
1280 WaveformContext *s = ctx->priv; \
1281 ThreadData *td = arg; \
1282 AVFrame *in = td->in; \
1283 AVFrame *out = td->out; \
1284 int component = td->component; \
1285 int offset_y = td->offset_y; \
1286 int offset_x = td->offset_x; \
1287 const int src_h = in->height; \
1288 const int src_w = in->width; \
1289 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \
1290 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \
1291 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \
1292 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \
1293 const int intensity = s->intensity; \
1294 const int plane = s->desc->comp[component].plane; \
1295 const int c0_linesize = in->linesize[ plane + 0 ]; \
1296 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; \
1297 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; \
1298 const int c0_shift_w = s->shift_w[ component + 0 ]; \
1299 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \
1300 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \
1301 const int c0_shift_h = s->shift_h[ component + 0 ]; \
1302 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \
1303 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \
1304 const int d0_linesize = out->linesize[ plane + 0 ]; \
1305 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; \
1306 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; \
1307 const int max = 255 - intensity; \
1311 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \
1312 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \
1313 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \
1315 for (x = slicew_start; x < slicew_end; x++) { \
1316 const uint8_t *c0_data = in->data[plane + 0]; \
1317 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \
1318 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \
1319 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; \
1320 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1321 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1322 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \
1323 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data); \
1324 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \
1325 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data); \
1326 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \
1327 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); \
1329 for (y = 0; y < src_h; y++) { \
1330 const int c0 = c0_data[x >> c0_shift_w] + 128; \
1331 const int c1 = c1_data[x >> c1_shift_w] - 128; \
1332 const int c2 = c2_data[x >> c2_shift_w] - 128; \
1335 target = d0 + x + d0_signed_linesize * c0; \
1336 update(target, max, intensity); \
1338 target = d1 + x + d1_signed_linesize * (c0 + c1); \
1339 update(target, max, intensity); \
1341 target = d2 + x + d2_signed_linesize * (c0 + c2); \
1342 update_cr(target, max, intensity); \
1344 if (!c0_shift_h || (y & c0_shift_h)) \
1345 c0_data += c0_linesize; \
1346 if (!c1_shift_h || (y & c1_shift_h)) \
1347 c1_data += c1_linesize; \
1348 if (!c1_shift_h || (y & c1_shift_h)) \
1349 c2_data += c1_linesize; \
1350 d0_data += d0_linesize; \
1351 d1_data += d1_linesize; \
1352 d2_data += d2_linesize; \
1356 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \
1357 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1358 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1359 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \
1360 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
1361 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
1364 d0_data += s->size - 1; \
1365 d1_data += s->size - 1; \
1366 d2_data += s->size - 1; \
1369 for (y = sliceh_start; y < sliceh_end; y++) { \
1370 for (x = 0; x < src_w; x++) { \
1371 const int c0 = c0_data[x >> c0_shift_w] + 128; \
1372 const int c1 = c1_data[x >> c1_shift_w] - 128; \
1373 const int c2 = c2_data[x >> c2_shift_w] - 128; \
1377 target = d0_data - c0; \
1378 update(target, max, intensity); \
1379 target = d1_data - (c0 + c1); \
1380 update(target, max, intensity); \
1381 target = d2_data - (c0 + c2); \
1382 update_cr(target, max, intensity); \
1384 target = d0_data + c0; \
1385 update(target, max, intensity); \
1386 target = d1_data + (c0 + c1); \
1387 update(target, max, intensity); \
1388 target = d2_data + (c0 + c2); \
1389 update_cr(target, max, intensity); \
1393 if (!c0_shift_h || (y & c0_shift_h)) \
1394 c0_data += c0_linesize; \
1395 if (!c1_shift_h || (y & c1_shift_h)) \
1396 c1_data += c1_linesize; \
1397 if (!c2_shift_h || (y & c2_shift_h)) \
1398 c2_data += c2_linesize; \
1399 d0_data += d0_linesize; \
1400 d1_data += d1_linesize; \
1401 d2_data += d2_linesize; \
1407 AFLAT16(aflat16_row, update16, 0, 0)
1408 AFLAT16(aflat16_row_mirror, update16, 0, 1)
1409 AFLAT16(aflat16_column, update16, 1, 0)
1410 AFLAT16(aflat16_column_mirror, update16, 1, 1)
1411 AFLAT16(xflat16_row, update16_cr, 0, 0)
1412 AFLAT16(xflat16_row_mirror, update16_cr, 0, 1)
1413 AFLAT16(xflat16_column, update16_cr, 1, 0)
1414 AFLAT16(xflat16_column_mirror, update16_cr, 1, 1)
1416 AFLAT(aflat_row, update, 0, 0)
1417 AFLAT(aflat_row_mirror, update, 0, 1)
1418 AFLAT(aflat_column, update, 1, 0)
1419 AFLAT(aflat_column_mirror, update, 1, 1)
1420 AFLAT(xflat_row, update_cr, 0, 0)
1421 AFLAT(xflat_row_mirror, update_cr, 0, 1)
1422 AFLAT(xflat_column, update_cr, 1, 0)
1423 AFLAT(xflat_column_mirror, update_cr, 1, 1)
1425 static av_always_inline void chroma16(WaveformContext *s,
1426 AVFrame *in, AVFrame *out,
1427 int component, int intensity,
1428 int offset_y, int offset_x,
1429 int column, int mirror,
1430 int jobnr, int nb_jobs)
1432 const int plane = s->desc->comp[component].plane;
1433 const int c0_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1434 const int c1_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1435 const int dst_linesize = out->linesize[plane] / 2;
1436 const int limit = s->max - 1;
1437 const int max = limit - intensity;
1438 const int mid = s->max / 2;
1439 const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1440 const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1441 const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1442 const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1443 const int src_h = in->height;
1444 const int src_w = in->width;
1445 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1446 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1447 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1448 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1452 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1454 for (x = slicew_start; x < slicew_end; x++) {
1455 const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
1456 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
1457 uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x;
1458 uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1459 uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1460 uint16_t *dst = dst_line;
1462 for (y = 0; y < src_h; y++) {
1463 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1466 target = dst + x + dst_signed_linesize * sum;
1467 update16(target, max, intensity, limit);
1469 if (!c0_shift_h || (y & c0_shift_h))
1470 c0_data += c0_linesize;
1471 if (!c1_shift_h || (y & c1_shift_h))
1472 c1_data += c1_linesize;
1473 dst_data += dst_linesize;
1477 const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1478 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1479 uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1482 dst_data += s->size - 1;
1483 for (y = sliceh_start; y < sliceh_end; y++) {
1484 for (x = 0; x < src_w; x++) {
1485 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1489 target = dst_data - sum;
1490 update16(target, max, intensity, limit);
1492 target = dst_data + sum;
1493 update16(target, max, intensity, limit);
1497 if (!c0_shift_h || (y & c0_shift_h))
1498 c0_data += c0_linesize;
1499 if (!c1_shift_h || (y & c1_shift_h))
1500 c1_data += c1_linesize;
1501 dst_data += dst_linesize;
1506 #define CHROMA16_FUNC(name, column, mirror) \
1507 static int chroma16_##name(AVFilterContext *ctx, \
1508 void *arg, int jobnr, \
1511 WaveformContext *s = ctx->priv; \
1512 ThreadData *td = arg; \
1513 AVFrame *in = td->in; \
1514 AVFrame *out = td->out; \
1515 int component = td->component; \
1516 int offset_y = td->offset_y; \
1517 int offset_x = td->offset_x; \
1519 chroma16(s, in, out, component, s->intensity,\
1520 offset_y, offset_x, column, mirror, \
1526 CHROMA16_FUNC(column_mirror, 1, 1)
1527 CHROMA16_FUNC(column, 1, 0)
1528 CHROMA16_FUNC(row_mirror, 0, 1)
1529 CHROMA16_FUNC(row, 0, 0)
1531 static av_always_inline void chroma(WaveformContext *s,
1532 AVFrame *in, AVFrame *out,
1533 int component, int intensity,
1534 int offset_y, int offset_x,
1535 int column, int mirror,
1536 int jobnr, int nb_jobs)
1538 const int plane = s->desc->comp[component].plane;
1539 const int src_h = in->height;
1540 const int src_w = in->width;
1541 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1542 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1543 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1544 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1545 const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
1546 const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
1547 const int dst_linesize = out->linesize[plane];
1548 const int max = 255 - intensity;
1549 const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1550 const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1551 const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1552 const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1556 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1558 for (x = slicew_start; x < slicew_end; x++) {
1559 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
1560 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
1561 uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x;
1562 uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1563 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1564 uint8_t *dst = dst_line;
1566 for (y = 0; y < src_h; y++) {
1567 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1570 target = dst + x + dst_signed_linesize * sum;
1571 update(target, max, intensity);
1573 if (!c0_shift_h || (y & c0_shift_h))
1574 c0_data += c0_linesize;
1575 if (!c1_shift_h || (y & c1_shift_h))
1576 c1_data += c1_linesize;
1577 dst_data += dst_linesize;
1581 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1582 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1583 uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1586 dst_data += s->size - 1;
1587 for (y = sliceh_start; y < sliceh_end; y++) {
1588 for (x = 0; x < src_w; x++) {
1589 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1593 target = dst_data - sum;
1594 update(target, max, intensity);
1596 target = dst_data + sum;
1597 update(target, max, intensity);
1601 if (!c0_shift_h || (y & c0_shift_h))
1602 c0_data += c0_linesize;
1603 if (!c1_shift_h || (y & c1_shift_h))
1604 c1_data += c1_linesize;
1605 dst_data += dst_linesize;
1610 #define CHROMA_FUNC(name, column, mirror) \
1611 static int chroma_##name(AVFilterContext *ctx, \
1612 void *arg, int jobnr, \
1615 WaveformContext *s = ctx->priv; \
1616 ThreadData *td = arg; \
1617 AVFrame *in = td->in; \
1618 AVFrame *out = td->out; \
1619 int component = td->component; \
1620 int offset_y = td->offset_y; \
1621 int offset_x = td->offset_x; \
1623 chroma(s, in, out, component, s->intensity, \
1624 offset_y, offset_x, column, mirror, \
1630 CHROMA_FUNC(column_mirror, 1, 1)
1631 CHROMA_FUNC(column, 1, 0)
1632 CHROMA_FUNC(row_mirror, 0, 1)
1633 CHROMA_FUNC(row, 0, 0)
1635 static av_always_inline void color16(WaveformContext *s,
1636 AVFrame *in, AVFrame *out,
1637 int component, int intensity,
1638 int offset_y, int offset_x,
1639 int column, int mirror,
1640 int jobnr, int nb_jobs)
1642 const int plane = s->desc->comp[component].plane;
1643 const int limit = s->max - 1;
1644 const int src_h = in->height;
1645 const int src_w = in->width;
1646 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1647 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1648 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1649 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1650 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
1651 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1652 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1653 const int c0_shift_h = s->shift_h[ component + 0 ];
1654 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1655 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1656 const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
1657 const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1658 const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1659 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
1660 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
1661 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
1662 const int c0_shift_w = s->shift_w[ component + 0 ];
1663 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1664 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1668 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1669 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1670 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1671 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
1672 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1673 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1674 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1675 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1676 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1677 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1678 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1679 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1681 for (y = 0; y < src_h; y++) {
1682 for (x = slicew_start; x < slicew_end; x++) {
1683 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1684 const int c1 = c1_data[x >> c1_shift_w];
1685 const int c2 = c2_data[x >> c2_shift_w];
1687 *(d0 + d0_signed_linesize * c0 + x) = c0;
1688 *(d1 + d1_signed_linesize * c0 + x) = c1;
1689 *(d2 + d2_signed_linesize * c0 + x) = c2;
1692 if (!c0_shift_h || (y & c0_shift_h))
1693 c0_data += c0_linesize;
1694 if (!c1_shift_h || (y & c1_shift_h))
1695 c1_data += c1_linesize;
1696 if (!c2_shift_h || (y & c2_shift_h))
1697 c2_data += c2_linesize;
1698 d0_data += d0_linesize;
1699 d1_data += d1_linesize;
1700 d2_data += d2_linesize;
1703 uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1704 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1705 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1708 d0_data += s->size - 1;
1709 d1_data += s->size - 1;
1710 d2_data += s->size - 1;
1713 for (y = sliceh_start; y < sliceh_end; y++) {
1714 for (x = 0; x < src_w; x++) {
1715 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1716 const int c1 = c1_data[x >> c1_shift_w];
1717 const int c2 = c2_data[x >> c2_shift_w];
1720 *(d0_data - c0) = c0;
1721 *(d1_data - c0) = c1;
1722 *(d2_data - c0) = c2;
1724 *(d0_data + c0) = c0;
1725 *(d1_data + c0) = c1;
1726 *(d2_data + c0) = c2;
1730 if (!c0_shift_h || (y & c0_shift_h))
1731 c0_data += c0_linesize;
1732 if (!c1_shift_h || (y & c1_shift_h))
1733 c1_data += c1_linesize;
1734 if (!c2_shift_h || (y & c2_shift_h))
1735 c2_data += c2_linesize;
1736 d0_data += d0_linesize;
1737 d1_data += d1_linesize;
1738 d2_data += d2_linesize;
1743 #define COLOR16_FUNC(name, column, mirror) \
1744 static int color16_##name(AVFilterContext *ctx, \
1745 void *arg, int jobnr, \
1748 WaveformContext *s = ctx->priv; \
1749 ThreadData *td = arg; \
1750 AVFrame *in = td->in; \
1751 AVFrame *out = td->out; \
1752 int component = td->component; \
1753 int offset_y = td->offset_y; \
1754 int offset_x = td->offset_x; \
1756 color16(s, in, out, component, s->intensity, \
1757 offset_y, offset_x, column, mirror, \
1763 COLOR16_FUNC(column_mirror, 1, 1)
1764 COLOR16_FUNC(column, 1, 0)
1765 COLOR16_FUNC(row_mirror, 0, 1)
1766 COLOR16_FUNC(row, 0, 0)
1768 static av_always_inline void color(WaveformContext *s,
1769 AVFrame *in, AVFrame *out,
1770 int component, int intensity,
1771 int offset_y, int offset_x,
1772 int column, int mirror,
1773 int jobnr, int nb_jobs)
1775 const int plane = s->desc->comp[component].plane;
1776 const int src_h = in->height;
1777 const int src_w = in->width;
1778 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1779 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1780 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1781 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1782 const int c0_linesize = in->linesize[ plane + 0 ];
1783 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1784 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1785 const int c0_shift_h = s->shift_h[ component + 0 ];
1786 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1787 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1788 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;
1789 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1790 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1791 const int d0_linesize = out->linesize[ plane + 0 ];
1792 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1793 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1794 const int c0_shift_w = s->shift_w[ component + 0 ];
1795 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1796 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1800 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1801 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1802 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1803 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1804 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1805 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1806 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1807 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1808 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1809 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1810 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1811 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1813 for (y = 0; y < src_h; y++) {
1814 for (x = slicew_start; x < slicew_end; x++) {
1815 const int c0 = c0_data[x >> c0_shift_w];
1816 const int c1 = c1_data[x >> c1_shift_w];
1817 const int c2 = c2_data[x >> c2_shift_w];
1819 *(d0 + d0_signed_linesize * c0 + x) = c0;
1820 *(d1 + d1_signed_linesize * c0 + x) = c1;
1821 *(d2 + d2_signed_linesize * c0 + x) = c2;
1824 if (!c0_shift_h || (y & c0_shift_h))
1825 c0_data += c0_linesize;
1826 if (!c1_shift_h || (y & c1_shift_h))
1827 c1_data += c1_linesize;
1828 if (!c2_shift_h || (y & c2_shift_h))
1829 c2_data += c2_linesize;
1830 d0_data += d0_linesize;
1831 d1_data += d1_linesize;
1832 d2_data += d2_linesize;
1835 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1836 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1837 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1840 d0_data += s->size - 1;
1841 d1_data += s->size - 1;
1842 d2_data += s->size - 1;
1845 for (y = sliceh_start; y < sliceh_end; y++) {
1846 for (x = 0; x < src_w; x++) {
1847 const int c0 = c0_data[x >> c0_shift_w];
1848 const int c1 = c1_data[x >> c1_shift_w];
1849 const int c2 = c2_data[x >> c2_shift_w];
1852 *(d0_data - c0) = c0;
1853 *(d1_data - c0) = c1;
1854 *(d2_data - c0) = c2;
1856 *(d0_data + c0) = c0;
1857 *(d1_data + c0) = c1;
1858 *(d2_data + c0) = c2;
1862 if (!c0_shift_h || (y & c0_shift_h))
1863 c0_data += c0_linesize;
1864 if (!c1_shift_h || (y & c1_shift_h))
1865 c1_data += c1_linesize;
1866 if (!c2_shift_h || (y & c2_shift_h))
1867 c2_data += c2_linesize;
1868 d0_data += d0_linesize;
1869 d1_data += d1_linesize;
1870 d2_data += d2_linesize;
1875 #define COLOR_FUNC(name, column, mirror) \
1876 static int color_##name(AVFilterContext *ctx, \
1877 void *arg, int jobnr, \
1880 WaveformContext *s = ctx->priv; \
1881 ThreadData *td = arg; \
1882 AVFrame *in = td->in; \
1883 AVFrame *out = td->out; \
1884 int component = td->component; \
1885 int offset_y = td->offset_y; \
1886 int offset_x = td->offset_x; \
1888 color(s, in, out, component, s->intensity, \
1889 offset_y, offset_x, column, mirror, \
1895 COLOR_FUNC(column_mirror, 1, 1)
1896 COLOR_FUNC(column, 1, 0)
1897 COLOR_FUNC(row_mirror, 0, 1)
1898 COLOR_FUNC(row, 0, 0)
1900 static av_always_inline void acolor16(WaveformContext *s,
1901 AVFrame *in, AVFrame *out,
1902 int component, int intensity,
1903 int offset_y, int offset_x,
1904 int column, int mirror,
1905 int jobnr, int nb_jobs)
1907 const int plane = s->desc->comp[component].plane;
1908 const int limit = s->max - 1;
1909 const int max = limit - intensity;
1910 const int src_h = in->height;
1911 const int src_w = in->width;
1912 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1913 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1914 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1915 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1916 const int c0_shift_h = s->shift_h[ component + 0 ];
1917 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1918 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1919 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
1920 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1921 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1922 const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
1923 const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1924 const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1925 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
1926 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
1927 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
1928 const int c0_shift_w = s->shift_w[ component + 0 ];
1929 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1930 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1934 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1935 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1936 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1937 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
1938 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1939 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1940 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1941 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1942 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1943 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1944 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1945 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1947 for (y = 0; y < src_h; y++) {
1948 for (x = slicew_start; x < slicew_end; x++) {
1949 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1950 const int c1 = c1_data[x >> c1_shift_w];
1951 const int c2 = c2_data[x >> c2_shift_w];
1953 update16(d0 + d0_signed_linesize * c0 + x, max, intensity, limit);
1954 *(d1 + d1_signed_linesize * c0 + x) = c1;
1955 *(d2 + d2_signed_linesize * c0 + x) = c2;
1958 if (!c0_shift_h || (y & c0_shift_h))
1959 c0_data += c0_linesize;
1960 if (!c1_shift_h || (y & c1_shift_h))
1961 c1_data += c1_linesize;
1962 if (!c2_shift_h || (y & c2_shift_h))
1963 c2_data += c2_linesize;
1964 d0_data += d0_linesize;
1965 d1_data += d1_linesize;
1966 d2_data += d2_linesize;
1969 uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1970 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1971 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1974 d0_data += s->size - 1;
1975 d1_data += s->size - 1;
1976 d2_data += s->size - 1;
1979 for (y = sliceh_start; y < sliceh_end; y++) {
1980 for (x = 0; x < src_w; x++) {
1981 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1982 const int c1 = c1_data[x >> c1_shift_w];
1983 const int c2 = c2_data[x >> c2_shift_w];
1986 update16(d0_data - c0, max, intensity, limit);
1987 *(d1_data - c0) = c1;
1988 *(d2_data - c0) = c2;
1990 update16(d0_data + c0, max, intensity, limit);
1991 *(d1_data + c0) = c1;
1992 *(d2_data + c0) = c2;
1996 if (!c0_shift_h || (y & c0_shift_h))
1997 c0_data += c0_linesize;
1998 if (!c1_shift_h || (y & c1_shift_h))
1999 c1_data += c1_linesize;
2000 if (!c2_shift_h || (y & c2_shift_h))
2001 c2_data += c2_linesize;
2002 d0_data += d0_linesize;
2003 d1_data += d1_linesize;
2004 d2_data += d2_linesize;
2009 #define ACOLOR16_FUNC(name, column, mirror) \
2010 static int acolor16_##name(AVFilterContext *ctx, \
2011 void *arg, int jobnr, \
2014 WaveformContext *s = ctx->priv; \
2015 ThreadData *td = arg; \
2016 AVFrame *in = td->in; \
2017 AVFrame *out = td->out; \
2018 int component = td->component; \
2019 int offset_y = td->offset_y; \
2020 int offset_x = td->offset_x; \
2022 acolor16(s, in, out, component, s->intensity,\
2023 offset_y, offset_x, column, mirror, \
2029 ACOLOR16_FUNC(column_mirror, 1, 1)
2030 ACOLOR16_FUNC(column, 1, 0)
2031 ACOLOR16_FUNC(row_mirror, 0, 1)
2032 ACOLOR16_FUNC(row, 0, 0)
2034 static av_always_inline void acolor(WaveformContext *s,
2035 AVFrame *in, AVFrame *out,
2036 int component, int intensity,
2037 int offset_y, int offset_x,
2038 int column, int mirror,
2039 int jobnr, int nb_jobs)
2041 const int plane = s->desc->comp[component].plane;
2042 const int src_h = in->height;
2043 const int src_w = in->width;
2044 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
2045 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
2046 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
2047 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
2048 const int c0_shift_w = s->shift_w[ component + 0 ];
2049 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
2050 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
2051 const int c0_shift_h = s->shift_h[ component + 0 ];
2052 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
2053 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
2054 const int c0_linesize = in->linesize[ plane + 0 ];
2055 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
2056 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
2057 const uint8_t *c0_data = in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
2058 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
2059 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
2060 const int d0_linesize = out->linesize[ plane + 0 ];
2061 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
2062 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
2063 const int max = 255 - intensity;
2067 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
2068 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
2069 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
2070 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
2071 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
2072 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
2073 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
2074 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
2075 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
2076 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
2077 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
2078 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data);
2080 for (y = 0; y < src_h; y++) {
2081 for (x = slicew_start; x < slicew_end; x++) {
2082 const int c0 = c0_data[x >> c0_shift_w];
2083 const int c1 = c1_data[x >> c1_shift_w];
2084 const int c2 = c2_data[x >> c2_shift_w];
2086 update(d0 + d0_signed_linesize * c0 + x, max, intensity);
2087 *(d1 + d1_signed_linesize * c0 + x) = c1;
2088 *(d2 + d2_signed_linesize * c0 + x) = c2;
2091 if (!c0_shift_h || (y & c0_shift_h))
2092 c0_data += c0_linesize;
2093 if (!c1_shift_h || (y & c1_shift_h))
2094 c1_data += c1_linesize;
2095 if (!c2_shift_h || (y & c2_shift_h))
2096 c2_data += c2_linesize;
2097 d0_data += d0_linesize;
2098 d1_data += d1_linesize;
2099 d2_data += d2_linesize;
2102 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
2103 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
2104 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
2107 d0_data += s->size - 1;
2108 d1_data += s->size - 1;
2109 d2_data += s->size - 1;
2112 for (y = sliceh_start; y < sliceh_end; y++) {
2113 for (x = 0; x < src_w; x++) {
2114 const int c0 = c0_data[x >> c0_shift_w];
2115 const int c1 = c1_data[x >> c1_shift_w];
2116 const int c2 = c2_data[x >> c2_shift_w];
2119 update(d0_data - c0, max, intensity);
2120 *(d1_data - c0) = c1;
2121 *(d2_data - c0) = c2;
2123 update(d0_data + c0, max, intensity);
2124 *(d1_data + c0) = c1;
2125 *(d2_data + c0) = c2;
2129 if (!c0_shift_h || (y & c0_shift_h))
2130 c0_data += c0_linesize;
2131 if (!c1_shift_h || (y & c1_shift_h))
2132 c1_data += c1_linesize;
2133 if (!c2_shift_h || (y & c2_shift_h))
2134 c2_data += c2_linesize;
2135 d0_data += d0_linesize;
2136 d1_data += d1_linesize;
2137 d2_data += d2_linesize;
2142 #define ACOLOR_FUNC(name, column, mirror) \
2143 static int acolor_##name(AVFilterContext *ctx, \
2144 void *arg, int jobnr, \
2147 WaveformContext *s = ctx->priv; \
2148 ThreadData *td = arg; \
2149 AVFrame *in = td->in; \
2150 AVFrame *out = td->out; \
2151 int component = td->component; \
2152 int offset_y = td->offset_y; \
2153 int offset_x = td->offset_x; \
2155 acolor(s, in, out, component, s->intensity, \
2156 offset_y, offset_x, column, mirror, \
2162 ACOLOR_FUNC(column_mirror, 1, 1)
2163 ACOLOR_FUNC(column, 1, 0)
2164 ACOLOR_FUNC(row_mirror, 0, 1)
2165 ACOLOR_FUNC(row, 0, 0)
2167 static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 };
2168 static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 };
2170 static const GraticuleLines aflat_digital8[] = {
2171 { { { "16", 16+128 }, { "16", 16+128 }, { "16", 16+128 }, { "0", 0+128 } } },
2172 { { { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 }, { "128", 128+128 } } },
2173 { { { "235", 235+128 }, { "240", 240+128 }, { "240", 240+128 }, { "255", 255+128 } } },
2176 static const GraticuleLines aflat_digital9[] = {
2177 { { { "32", 32+256 }, { "32", 32+256 }, { "32", 32+256 }, { "0", 0+256 } } },
2178 { { { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 }, { "256", 256+256 } } },
2179 { { { "470", 470+256 }, { "480", 480+256 }, { "480", 480+256 }, { "511", 511+256 } } },
2182 static const GraticuleLines aflat_digital10[] = {
2183 { { { "64", 64+512 }, { "64", 64+512 }, { "64", 64+512 }, { "0", 0+512 } } },
2184 { { { "512", 512+512 }, { "512", 512+512 }, { "512", 512+512 }, { "512", 512+512 } } },
2185 { { { "940", 940+512 }, { "960", 960+512 }, { "960", 960+512 }, { "1023", 1023+512 } } },
2188 static const GraticuleLines aflat_digital12[] = {
2189 { { { "256", 256+2048 }, { "256", 256+2048 }, { "256", 256+2048 }, { "0", 0+2048 } } },
2190 { { { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 }, { "2048", 2048+2048 } } },
2191 { { { "3760", 3760+2048 }, { "3840", 3840+2048 }, { "3840", 3840+2048 }, { "4095", 4095+2048 } } },
2194 static const GraticuleLines aflat_millivolts8[] = {
2195 { { { "0", 16+128 }, { "0", 16+128 }, { "0", 16+128 }, { "0", 0+128 } } },
2196 { { { "175", 71+128 }, { "175", 72+128 }, { "175", 72+128 }, { "175", 64+128 } } },
2197 { { { "350", 126+128 }, { "350", 128+128 }, { "350", 128+128 }, { "350", 128+128 } } },
2198 { { { "525", 180+128 }, { "525", 184+128 }, { "525", 184+128 }, { "525", 192+128 } } },
2199 { { { "700", 235+128 }, { "700", 240+128 }, { "700", 240+128 }, { "700", 255+128 } } },
2202 static const GraticuleLines aflat_millivolts9[] = {
2203 { { { "0", 32+256 }, { "0", 32+256 }, { "0", 32+256 }, { "0", 0+256 } } },
2204 { { { "175", 142+256 }, { "175", 144+256 }, { "175", 144+256 }, { "175", 128+256 } } },
2205 { { { "350", 251+256 }, { "350", 256+256 }, { "350", 256+256 }, { "350", 256+256 } } },
2206 { { { "525", 361+256 }, { "525", 368+256 }, { "525", 368+256 }, { "525", 384+256 } } },
2207 { { { "700", 470+256 }, { "700", 480+256 }, { "700", 480+256 }, { "700", 511+256 } } },
2210 static const GraticuleLines aflat_millivolts10[] = {
2211 { { { "0", 64+512 }, { "0", 64+512 }, { "0", 64+512 }, { "0", 0+512 } } },
2212 { { { "175", 283+512 }, { "175", 288+512 }, { "175", 288+512 }, { "175", 256+512 } } },
2213 { { { "350", 502+512 }, { "350", 512+512 }, { "350", 512+512 }, { "350", 512+512 } } },
2214 { { { "525", 721+512 }, { "525", 736+512 }, { "525", 736+512 }, { "525", 768+512 } } },
2215 { { { "700", 940+512 }, { "700", 960+512 }, { "700", 960+512 }, { "700", 1023+512 } } },
2218 static const GraticuleLines aflat_millivolts12[] = {
2219 { { { "0", 256+2048 }, { "0", 256+2048 }, { "0", 256+2048 }, { "0", 0+2048 } } },
2220 { { { "175", 1132+2048 }, { "175", 1152+2048 }, { "175", 1152+2048 }, { "175", 1024+2048 } } },
2221 { { { "350", 2008+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 }, { "350", 2048+2048 } } },
2222 { { { "525", 2884+2048 }, { "525", 2944+2048 }, { "525", 2944+2048 }, { "525", 3072+2048 } } },
2223 { { { "700", 3760+2048 }, { "700", 3840+2048 }, { "700", 3840+2048 }, { "700", 4095+2048 } } },
2226 static const GraticuleLines aflat_ire8[] = {
2227 { { { "-25", -39+128 }, { "-25", -40+128 }, { "-25", -40+128 }, { "-25", -64+128 } } },
2228 { { { "0", 16+128 }, { "0", 16+128 }, { "0", 16+128 }, { "0", 0+128 } } },
2229 { { { "25", 71+128 }, { "25", 72+128 }, { "25", 72+128 }, { "25", 64+128 } } },
2230 { { { "50", 126+128 }, { "50", 128+128 }, { "50", 128+128 }, { "50", 128+128 } } },
2231 { { { "75", 180+128 }, { "75", 184+128 }, { "75", 184+128 }, { "75", 192+128 } } },
2232 { { { "100", 235+128 }, { "100", 240+128 }, { "100", 240+128 }, { "100", 256+128 } } },
2233 { { { "125", 290+128 }, { "125", 296+128 }, { "125", 296+128 }, { "125", 320+128 } } },
2236 static const GraticuleLines aflat_ire9[] = {
2237 { { { "-25", -78+256 }, { "-25", -80+256 }, { "-25", -80+256 }, { "-25",-128+256 } } },
2238 { { { "0", 32+256 }, { "0", 32+256 }, { "0", 32+256 }, { "0", 0+256 } } },
2239 { { { "25", 142+256 }, { "25", 144+256 }, { "25", 144+256 }, { "25", 128+256 } } },
2240 { { { "50", 251+256 }, { "50", 256+256 }, { "50", 256+256 }, { "50", 256+256 } } },
2241 { { { "75", 361+256 }, { "75", 368+256 }, { "75", 368+256 }, { "75", 384+256 } } },
2242 { { { "100", 470+256 }, { "100", 480+256 }, { "100", 480+256 }, { "100", 512+256 } } },
2243 { { { "125", 580+256 }, { "125", 592+256 }, { "125", 592+256 }, { "125", 640+256 } } },
2246 static const GraticuleLines aflat_ire10[] = {
2247 { { { "-25",-156+512 }, { "-25",-160+512 }, { "-25",-160+512 }, { "-25", -256+512 } } },
2248 { { { "0", 64+512 }, { "0", 64+512 }, { "0", 64+512 }, { "0", 0+512 } } },
2249 { { { "25", 283+512 }, { "25", 288+512 }, { "25", 288+512 }, { "25", 256+512 } } },
2250 { { { "50", 502+512 }, { "50", 512+512 }, { "50", 512+512 }, { "50", 512+512 } } },
2251 { { { "75", 721+512 }, { "75", 736+512 }, { "75", 736+512 }, { "75", 768+512 } } },
2252 { { { "100", 940+512 }, { "100", 960+512 }, { "100", 960+512 }, { "100", 1024+512 } } },
2253 { { { "125",1160+512 }, { "125",1184+512 }, { "125",1184+512 }, { "125", 1280+512 } } },
2256 static const GraticuleLines aflat_ire12[] = {
2257 { { { "-25", -624+2048 }, { "-25", -640+2048 }, { "-25", -640+2048 }, { "-25",-1024+2048 } } },
2258 { { { "0", 256+2048 }, { "0", 256+2048 }, { "0", 256+2048 }, { "0", 0+2048 } } },
2259 { { { "25", 1132+2048 }, { "25", 1152+2048 }, { "25", 1152+2048 }, { "25", 1024+2048 } } },
2260 { { { "50", 2008+2048 }, { "50", 2048+2048 }, { "50", 2048+2048 }, { "50", 2048+2048 } } },
2261 { { { "75", 2884+2048 }, { "75", 2944+2048 }, { "75", 2944+2048 }, { "75", 3072+2048 } } },
2262 { { { "100", 3760+2048 }, { "100", 3840+2048 }, { "100", 3840+2048 }, { "100", 4096+2048 } } },
2263 { { { "125", 4640+2048 }, { "125", 4736+2048 }, { "125", 4736+2048 }, { "125", 5120+2048 } } },
2266 static const GraticuleLines flat_digital8[] = {
2267 { { { "16", 16+256 }, { "16", 16+256 }, { "16", 16+256 }, { "0", 0+256 } } },
2268 { { { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 }, { "128", 128+256 } } },
2269 { { { "235", 235+256 }, { "240", 240+256 }, { "240", 240+256 }, { "255", 255+256 } } },
2272 static const GraticuleLines flat_digital9[] = {
2273 { { { "32", 32+512 }, { "32", 32+512 }, { "32", 32+512 }, { "0", 0+512 } } },
2274 { { { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 }, { "256", 256+512 } } },
2275 { { { "470", 470+512 }, { "480", 480+512 }, { "480", 480+512 }, { "511", 511+512 } } },
2278 static const GraticuleLines flat_digital10[] = {
2279 { { { "64", 64+1024 }, { "64", 64+1024 }, { "64", 64+1024 }, { "0", 0+1024 } } },
2280 { { { "512", 512+1024 }, { "512", 512+1024 }, { "512", 512+1024 }, { "512", 512+1024 } } },
2281 { { { "940", 940+1024 }, { "960", 960+1024 }, { "960", 960+1024 }, { "1023", 1023+1024 } } },
2284 static const GraticuleLines flat_digital12[] = {
2285 { { { "256", 256+4096 }, { "256", 256+4096 }, { "256", 256+4096 }, { "0", 0+4096 } } },
2286 { { { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 }, { "2048", 2048+4096 } } },
2287 { { { "3760", 3760+4096 }, { "3840", 3840+4096 }, { "3840", 3840+4096 }, { "4095", 4095+4096 } } },
2290 static const GraticuleLines flat_millivolts8[] = {
2291 { { { "0", 16+256 }, { "0", 16+256 }, { "0", 16+256 }, { "0", 0+256 } } },
2292 { { { "175", 71+256 }, { "175", 72+256 }, { "175", 72+256 }, { "175", 64+256 } } },
2293 { { { "350", 126+256 }, { "350", 128+256 }, { "350", 128+256 }, { "350", 128+256 } } },
2294 { { { "525", 180+256 }, { "525", 184+256 }, { "525", 184+256 }, { "525", 192+256 } } },
2295 { { { "700", 235+256 }, { "700", 240+256 }, { "700", 240+256 }, { "700", 255+256 } } },
2298 static const GraticuleLines flat_millivolts9[] = {
2299 { { { "0", 32+512 }, { "0", 32+512 }, { "0", 32+512 }, { "0", 0+512 } } },
2300 { { { "175", 142+512 }, { "175", 144+512 }, { "175", 144+512 }, { "175", 128+512 } } },
2301 { { { "350", 251+512 }, { "350", 256+512 }, { "350", 256+512 }, { "350", 256+512 } } },
2302 { { { "525", 361+512 }, { "525", 368+512 }, { "525", 368+512 }, { "525", 384+512 } } },
2303 { { { "700", 470+512 }, { "700", 480+512 }, { "700", 480+512 }, { "700", 511+512 } } },
2306 static const GraticuleLines flat_millivolts10[] = {
2307 { { { "0", 64+1024 }, { "0", 64+1024 }, { "0", 64+1024 }, { "0", 0+1024 } } },
2308 { { { "175", 283+1024 }, { "175", 288+1024 }, { "175", 288+1024 }, { "175", 256+1024 } } },
2309 { { { "350", 502+1024 }, { "350", 512+1024 }, { "350", 512+1024 }, { "350", 512+1024 } } },
2310 { { { "525", 721+1024 }, { "525", 736+1024 }, { "525", 736+1024 }, { "525", 768+1024 } } },
2311 { { { "700", 940+1024 }, { "700", 960+1024 }, { "700", 960+1024 }, { "700", 1023+1024 } } },
2314 static const GraticuleLines flat_millivolts12[] = {
2315 { { { "0", 256+4096 }, { "0", 256+4096 }, { "0", 256+4096 }, { "0", 0+4096 } } },
2316 { { { "175", 1132+4096 }, { "175", 1152+4096 }, { "175", 1152+4096 }, { "175", 1024+4096 } } },
2317 { { { "350", 2008+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 }, { "350", 2048+4096 } } },
2318 { { { "525", 2884+4096 }, { "525", 2944+4096 }, { "525", 2944+4096 }, { "525", 3072+4096 } } },
2319 { { { "700", 3760+4096 }, { "700", 3840+4096 }, { "700", 3840+4096 }, { "700", 4095+4096 } } },
2322 static const GraticuleLines flat_ire8[] = {
2323 { { { "-25", -39+256 }, { "-25", -40+256 }, { "-25", -40+256 }, { "-25", -64+256 } } },
2324 { { { "0", 16+256 }, { "0", 16+256 }, { "0", 16+256 }, { "0", 0+256 } } },
2325 { { { "25", 71+256 }, { "25", 72+256 }, { "25", 72+256 }, { "25", 64+256 } } },
2326 { { { "50", 126+256 }, { "50", 128+256 }, { "50", 128+256 }, { "50", 128+256 } } },
2327 { { { "75", 180+256 }, { "75", 184+256 }, { "75", 184+256 }, { "75", 192+256 } } },
2328 { { { "100", 235+256 }, { "100", 240+256 }, { "100", 240+256 }, { "100", 256+256 } } },
2329 { { { "125", 290+256 }, { "125", 296+256 }, { "125", 296+256 }, { "125", 320+256 } } },
2332 static const GraticuleLines flat_ire9[] = {
2333 { { { "-25", -78+512 }, { "-25", -80+512 }, { "-25", -80+512 }, { "-25",-128+512 } } },
2334 { { { "0", 32+512 }, { "0", 32+512 }, { "0", 32+512 }, { "0", 0+512 } } },
2335 { { { "25", 142+512 }, { "25", 144+512 }, { "25", 144+512 }, { "25", 128+512 } } },
2336 { { { "50", 251+512 }, { "50", 256+512 }, { "50", 256+512 }, { "50", 256+512 } } },
2337 { { { "75", 361+512 }, { "75", 368+512 }, { "75", 368+512 }, { "75", 384+512 } } },
2338 { { { "100", 470+512 }, { "100", 480+512 }, { "100", 480+512 }, { "100", 512+512 } } },
2339 { { { "125", 580+512 }, { "125", 592+512 }, { "125", 592+512 }, { "125", 640+512 } } },
2342 static const GraticuleLines flat_ire10[] = {
2343 { { { "-25",-156+1024 }, { "-25",-160+1024 }, { "-25",-160+1024 }, { "-25", -256+1024 } } },
2344 { { { "0", 64+1024 }, { "0", 64+1024 }, { "0", 64+1024 }, { "0", 0+1024 } } },
2345 { { { "25", 283+1024 }, { "25", 288+1024 }, { "25", 288+1024 }, { "25", 256+1024 } } },
2346 { { { "50", 502+1024 }, { "50", 512+1024 }, { "50", 512+1024 }, { "50", 512+1024 } } },
2347 { { { "75", 721+1024 }, { "75", 736+1024 }, { "75", 736+1024 }, { "75", 768+1024 } } },
2348 { { { "100", 940+1024 }, { "100", 960+1024 }, { "100", 960+1024 }, { "100", 1024+1024 } } },
2349 { { { "125",1160+1024 }, { "125",1184+1024 }, { "125",1184+1024 }, { "125", 1280+1024 } } },
2352 static const GraticuleLines flat_ire12[] = {
2353 { { { "-25", -624+4096 }, { "-25", -640+4096 }, { "-25", -640+4096 }, { "-25",-1024+4096 } } },
2354 { { { "0", 256+4096 }, { "0", 256+4096 }, { "0", 256+4096 }, { "0", 0+4096 } } },
2355 { { { "25", 1132+4096 }, { "25", 1152+4096 }, { "25", 1152+4096 }, { "25", 1024+4096 } } },
2356 { { { "50", 2008+4096 }, { "50", 2048+4096 }, { "50", 2048+4096 }, { "50", 2048+4096 } } },
2357 { { { "75", 2884+4096 }, { "75", 2944+4096 }, { "75", 2944+4096 }, { "75", 3072+4096 } } },
2358 { { { "100", 3760+4096 }, { "100", 3840+4096 }, { "100", 3840+4096 }, { "100", 4096+4096 } } },
2359 { { { "125", 4640+4096 }, { "125", 4736+4096 }, { "125", 4736+4096 }, { "125", 5120+4096 } } },
2362 static const GraticuleLines digital8[] = {
2363 { { { "16", 16 }, { "16", 16 }, { "16", 16 }, { "0", 0 } } },
2364 { { { "128", 128 }, { "128", 128 }, { "128", 128 }, { "128", 128 } } },
2365 { { { "235", 235 }, { "240", 240 }, { "240", 240 }, { "255", 255 } } },
2368 static const GraticuleLines digital9[] = {
2369 { { { "32", 32 }, { "32", 32 }, { "32", 32 }, { "0", 0 } } },
2370 { { { "256", 256 }, { "256", 256 }, { "256", 256 }, { "256", 256 } } },
2371 { { { "470", 470 }, { "480", 480 }, { "480", 480 }, { "511", 511 } } },
2374 static const GraticuleLines digital10[] = {
2375 { { { "64", 64 }, { "64", 64 }, { "64", 64 }, { "0", 0 } } },
2376 { { { "512", 512 }, { "512", 512 }, { "512", 512 }, { "512", 512 } } },
2377 { { { "940", 940 }, { "960", 960 }, { "960", 960 }, { "1023", 1023 } } },
2380 static const GraticuleLines digital12[] = {
2381 { { { "256", 256 }, { "256", 256 }, { "256", 256 }, { "0", 0 } } },
2382 { { { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 }, { "2048", 2048 } } },
2383 { { { "3760", 3760 }, { "3840", 3840 }, { "3840", 3840 }, { "4095", 4095 } } },
2386 static const GraticuleLines millivolts8[] = {
2387 { { { "0", 16 }, { "0", 16 }, { "0", 16 }, { "0", 0 } } },
2388 { { { "175", 71 }, { "175", 72 }, { "175", 72 }, { "175", 64 } } },
2389 { { { "350", 126 }, { "350", 128 }, { "350", 128 }, { "350", 128 } } },
2390 { { { "525", 180 }, { "525", 184 }, { "525", 184 }, { "525", 192 } } },
2391 { { { "700", 235 }, { "700", 240 }, { "700", 240 }, { "700", 255 } } },
2394 static const GraticuleLines millivolts9[] = {
2395 { { { "0", 32 }, { "0", 32 }, { "0", 32 }, { "0", 0 } } },
2396 { { { "175", 142 }, { "175", 144 }, { "175", 144 }, { "175", 128 } } },
2397 { { { "350", 251 }, { "350", 256 }, { "350", 256 }, { "350", 256 } } },
2398 { { { "525", 361 }, { "525", 368 }, { "525", 368 }, { "525", 384 } } },
2399 { { { "700", 470 }, { "700", 480 }, { "700", 480 }, { "700", 511 } } },
2402 static const GraticuleLines millivolts10[] = {
2403 { { { "0", 64 }, { "0", 64 }, { "0", 64 }, { "0", 0 } } },
2404 { { { "175", 283 }, { "175", 288 }, { "175", 288 }, { "175", 256 } } },
2405 { { { "350", 502 }, { "350", 512 }, { "350", 512 }, { "350", 512 } } },
2406 { { { "525", 721 }, { "525", 736 }, { "525", 736 }, { "525", 768 } } },
2407 { { { "700", 940 }, { "700", 960 }, { "700", 960 }, { "700", 1023 } } },
2410 static const GraticuleLines millivolts12[] = {
2411 { { { "0", 256 }, { "0", 256 }, { "0", 256 }, { "0", 0 } } },
2412 { { { "175", 1132 }, { "175", 1152 }, { "175", 1152 }, { "175", 1024 } } },
2413 { { { "350", 2008 }, { "350", 2048 }, { "350", 2048 }, { "350", 2048 } } },
2414 { { { "525", 2884 }, { "525", 2944 }, { "525", 2944 }, { "525", 3072 } } },
2415 { { { "700", 3760 }, { "700", 3840 }, { "700", 3840 }, { "700", 4095 } } },
2418 static const GraticuleLines ire8[] = {
2419 { { { "0", 16 }, { "0", 16 }, { "0", 16 }, { "0", 0 } } },
2420 { { { "25", 71 }, { "25", 72 }, { "25", 72 }, { "25", 64 } } },
2421 { { { "50", 126 }, { "50", 128 }, { "50", 128 }, { "50", 128 } } },
2422 { { { "75", 180 }, { "75", 184 }, { "75", 184 }, { "75", 192 } } },
2423 { { { "100", 235 }, { "100", 240 }, { "100", 240 }, { "100", 255 } } },
2426 static const GraticuleLines ire9[] = {
2427 { { { "0", 32 }, { "0", 32 }, { "0", 32 }, { "0", 0 } } },
2428 { { { "25", 142 }, { "25", 144 }, { "25", 144 }, { "25", 128 } } },
2429 { { { "50", 251 }, { "50", 256 }, { "50", 256 }, { "50", 256 } } },
2430 { { { "75", 361 }, { "75", 368 }, { "75", 368 }, { "75", 384 } } },
2431 { { { "100", 470 }, { "100", 480 }, { "100", 480 }, { "100", 511 } } },
2434 static const GraticuleLines ire10[] = {
2435 { { { "0", 64 }, { "0", 64 }, { "0", 64 }, { "0", 0 } } },
2436 { { { "25", 283 }, { "25", 288 }, { "25", 288 }, { "25", 256 } } },
2437 { { { "50", 502 }, { "50", 512 }, { "50", 512 }, { "50", 512 } } },
2438 { { { "75", 721 }, { "75", 736 }, { "75", 736 }, { "75", 768 } } },
2439 { { { "100", 940 }, { "100", 960 }, { "100", 960 }, { "100", 1023 } } },
2442 static const GraticuleLines ire12[] = {
2443 { { { "0", 256 }, { "0", 256 }, { "0", 256 }, { "0", 0 } } },
2444 { { { "25", 1132 }, { "25", 1152 }, { "25", 1152 }, { "25", 1024 } } },
2445 { { { "50", 2008 }, { "50", 2048 }, { "50", 2048 }, { "50", 2048 } } },
2446 { { { "75", 2884 }, { "75", 2944 }, { "75", 2944 }, { "75", 3072 } } },
2447 { { { "100", 3760 }, { "100", 3840 }, { "100", 3840 }, { "100", 4095 } } },
2450 static const GraticuleLines chroma_digital8[] = {
2451 { { { "50", 50 }, { "50", 50 }, { "50", 50 }, { "50", 50 } } },
2452 { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
2453 { { { "150", 150 }, { "150", 150 }, { "150", 150 }, { "150", 150 } } },
2454 { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2455 { { { "255", 255 }, { "255", 255 }, { "255", 255 }, { "255", 255 } } },
2458 static const GraticuleLines chroma_digital9[] = {
2459 { { { "100", 100 }, { "100", 100 }, { "100", 100 }, { "100", 100 } } },
2460 { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2461 { { { "300", 300 }, { "300", 300 }, { "300", 300 }, { "300", 300 } } },
2462 { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
2463 { { { "500", 500 }, { "500", 500 }, { "500", 500 }, { "500", 500 } } },
2466 static const GraticuleLines chroma_digital10[] = {
2467 { { { "200", 200 }, { "200", 200 }, { "200", 200 }, { "200", 200 } } },
2468 { { { "400", 400 }, { "400", 400 }, { "400", 400 }, { "400", 400 } } },
2469 { { { "600", 600 }, { "600", 600 }, { "600", 600 }, { "600", 600 } } },
2470 { { { "800", 800 }, { "800", 800 }, { "800", 800 }, { "800", 800 } } },
2471 { { {"1000",1000 }, {"1000",1000 }, {"1000",1000 }, {"1000",1000 } } },
2474 static const GraticuleLines chroma_digital12[] = {
2475 { { { "800", 800 }, { "800", 800 }, { "800", 800 }, { "800", 800 } } },
2476 { { { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 }, { "1600", 1600 } } },
2477 { { { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 }, { "2400", 2400 } } },
2478 { { { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 }, { "3200", 3200 } } },
2479 { { { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 }, { "4000", 4000 } } },
2482 static void blend_vline(uint8_t *dst, int height, int linesize, float o1, float o2, int v, int step)
2486 for (y = 0; y < height; y += step) {
2487 dst[0] = v * o1 + dst[0] * o2;
2489 dst += linesize * step;
2493 static void blend_vline16(uint8_t *ddst, int height, int linesize, float o1, float o2, int v, int step)
2495 uint16_t *dst = (uint16_t *)ddst;
2498 for (y = 0; y < height; y += step) {
2499 dst[0] = v * o1 + dst[0] * o2;
2501 dst += (linesize / 2) * step;
2505 static void blend_hline(uint8_t *dst, int width, int unused, float o1, float o2, int v, int step)
2509 for (x = 0; x < width; x += step) {
2510 dst[x] = v * o1 + dst[x] * o2;
2514 static void blend_hline16(uint8_t *ddst, int width, int unused, float o1, float o2, int v, int step)
2516 uint16_t *dst = (uint16_t *)ddst;
2519 for (x = 0; x < width; x += step) {
2520 dst[x] = v * o1 + dst[x] * o2;
2524 static void draw_htext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2526 const uint8_t *font;
2530 font = avpriv_cga_font, font_height = 8;
2532 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2533 for (i = 0; txt[i]; i++) {
2535 int v = color[plane];
2537 uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
2538 for (char_y = 0; char_y < font_height; char_y++) {
2539 for (mask = 0x80; mask; mask >>= 1) {
2540 if (font[txt[i] * font_height + char_y] & mask)
2541 p[0] = p[0] * o2 + v * o1;
2544 p += out->linesize[plane] - 8;
2550 static void draw_htext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2552 const uint8_t *font;
2556 font = avpriv_cga_font, font_height = 8;
2558 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2559 for (i = 0; txt[i]; i++) {
2561 int v = color[plane] * mult;
2563 uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
2564 for (char_y = 0; char_y < font_height; char_y++) {
2565 for (mask = 0x80; mask; mask >>= 1) {
2566 if (font[txt[i] * font_height + char_y] & mask)
2567 p[0] = p[0] * o2 + v * o1;
2570 p += out->linesize[plane] / 2 - 8;
2576 static void draw_vtext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2578 const uint8_t *font;
2582 font = avpriv_cga_font, font_height = 8;
2584 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2585 for (i = 0; txt[i]; i++) {
2587 int v = color[plane];
2589 for (char_y = font_height - 1; char_y >= 0; char_y--) {
2590 uint8_t *p = out->data[plane] + (y + i * 10) * out->linesize[plane] + x;
2591 for (mask = 0x80; mask; mask >>= 1) {
2592 if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2593 p[char_y] = p[char_y] * o2 + v * o1;
2594 p += out->linesize[plane];
2601 static void draw_vtext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2603 const uint8_t *font;
2607 font = avpriv_cga_font, font_height = 8;
2609 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2610 for (i = 0; txt[i]; i++) {
2612 int v = color[plane] * mult;
2614 for (char_y = 0; char_y < font_height; char_y++) {
2615 uint16_t *p = (uint16_t *)(out->data[plane] + (y + i * 10) * out->linesize[plane]) + x;
2616 for (mask = 0x80; mask; mask >>= 1) {
2617 if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2618 p[char_y] = p[char_y] * o2 + v * o1;
2619 p += out->linesize[plane] / 2;
2626 static void iblend_vline(uint8_t *dst, int height, int linesize, float o1, float o2, int v, int step)
2630 for (y = 0; y < height; y += step) {
2631 dst[0] = (v - dst[0]) * o1 + dst[0] * o2;
2633 dst += linesize * step;
2637 static void iblend_vline16(uint8_t *ddst, int height, int linesize, float o1, float o2, int v, int step)
2639 uint16_t *dst = (uint16_t *)ddst;
2642 for (y = 0; y < height; y += step) {
2643 dst[0] = (v - dst[0]) * o1 + dst[0] * o2;
2645 dst += (linesize / 2) * step;
2649 static void iblend_hline(uint8_t *dst, int width, int unused, float o1, float o2, int v, int step)
2653 for (x = 0; x < width; x += step) {
2654 dst[x] = (v - dst[x]) * o1 + dst[x] * o2;
2658 static void iblend_hline16(uint8_t *ddst, int width, int unused, float o1, float o2, int v, int step)
2660 uint16_t *dst = (uint16_t *)ddst;
2663 for (x = 0; x < width; x += step) {
2664 dst[x] = (v - dst[x]) * o1 + dst[x] * o2;
2668 static void idraw_htext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2670 const uint8_t *font;
2674 font = avpriv_cga_font, font_height = 8;
2676 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2677 for (i = 0; txt[i]; i++) {
2679 int v = color[plane];
2681 uint8_t *p = out->data[plane] + y * out->linesize[plane] + (x + i * 8);
2682 for (char_y = 0; char_y < font_height; char_y++) {
2683 for (mask = 0x80; mask; mask >>= 1) {
2684 if (font[txt[i] * font_height + char_y] & mask)
2685 p[0] = p[0] * o2 + (v - p[0]) * o1;
2688 p += out->linesize[plane] - 8;
2694 static void idraw_htext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2696 const uint8_t *font;
2700 font = avpriv_cga_font, font_height = 8;
2702 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2703 for (i = 0; txt[i]; i++) {
2705 int v = color[plane] * mult;
2707 uint16_t *p = (uint16_t *)(out->data[plane] + y * out->linesize[plane]) + (x + i * 8);
2708 for (char_y = 0; char_y < font_height; char_y++) {
2709 for (mask = 0x80; mask; mask >>= 1) {
2710 if (font[txt[i] * font_height + char_y] & mask)
2711 p[0] = p[0] * o2 + (v - p[0]) * o1;
2714 p += out->linesize[plane] / 2 - 8;
2720 static void idraw_vtext(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2722 const uint8_t *font;
2726 font = avpriv_cga_font, font_height = 8;
2728 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2729 for (i = 0; txt[i]; i++) {
2731 int v = color[plane];
2733 for (char_y = font_height - 1; char_y >= 0; char_y--) {
2734 uint8_t *p = out->data[plane] + (y + i * 10) * out->linesize[plane] + x;
2735 for (mask = 0x80; mask; mask >>= 1) {
2736 if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2737 p[char_y] = p[char_y] * o2 + (v - p[char_y]) * o1;
2738 p += out->linesize[plane];
2745 static void idraw_vtext16(AVFrame *out, int x, int y, int mult, float o1, float o2, const char *txt, const uint8_t color[4])
2747 const uint8_t *font;
2751 font = avpriv_cga_font, font_height = 8;
2753 for (plane = 0; plane < 4 && out->data[plane]; plane++) {
2754 for (i = 0; txt[i]; i++) {
2756 int v = color[plane] * mult;
2758 for (char_y = 0; char_y < font_height; char_y++) {
2759 uint16_t *p = (uint16_t *)(out->data[plane] + (y + i * 10) * out->linesize[plane]) + x;
2760 for (mask = 0x80; mask; mask >>= 1) {
2761 if (font[txt[i] * font_height + font_height - 1 - char_y] & mask)
2762 p[char_y] = p[char_y] * o2 + (v - p[char_y]) * o1;
2763 p += out->linesize[plane] / 2;
2770 static void graticule_none(WaveformContext *s, AVFrame *out)
2774 static void graticule_row(WaveformContext *s, AVFrame *out)
2776 const int step = (s->flags & 2) + 1;
2777 const float o1 = s->opacity;
2778 const float o2 = 1. - o1;
2779 const int height = s->display == PARADE ? out->height / s->acomp : out->height;
2780 int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2782 for (c = 0; c < s->ncomp; c++) {
2783 if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
2788 for (p = 0; p < s->ncomp; p++) {
2789 const int v = s->grat_yuva_color[p];
2790 for (l = 0; l < s->nb_glines; l++) {
2791 const uint16_t pos = s->glines[l].line[C].pos;
2792 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
2793 uint8_t *dst = out->data[p] + offset_y * out->linesize[p] + x;
2795 s->blend_line(dst, height, out->linesize[p], o1, o2, v, step);
2799 for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2800 const char *name = s->glines[l].line[C].name;
2801 const uint16_t pos = s->glines[l].line[C].pos;
2802 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
2807 s->draw_text(out, x, offset_y + 2, 1, o1, o2, name, s->grat_yuva_color);
2810 offset_x += s->size * (s->display == STACK);
2811 offset_y += height * (s->display == PARADE);
2815 static void graticule16_row(WaveformContext *s, AVFrame *out)
2817 const int step = (s->flags & 2) + 1;
2818 const float o1 = s->opacity;
2819 const float o2 = 1. - o1;
2820 const int mult = s->max / 256;
2821 const int height = s->display == PARADE ? out->height / s->acomp : out->height;
2822 int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2824 for (c = 0; c < s->ncomp; c++) {
2825 if (!((1 << c) & s->pcomp) || (!s->display && k > 0))
2830 for (p = 0; p < s->ncomp; p++) {
2831 const int v = s->grat_yuva_color[p] * mult;
2832 for (l = 0; l < s->nb_glines ; l++) {
2833 const uint16_t pos = s->glines[l].line[C].pos;
2834 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos);
2835 uint8_t *dst = (uint8_t *)(out->data[p] + offset_y * out->linesize[p]) + x * 2;
2837 s->blend_line(dst, height, out->linesize[p], o1, o2, v, step);
2841 for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2842 const char *name = s->glines[l].line[C].name;
2843 const uint16_t pos = s->glines[l].line[C].pos;
2844 int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10;
2849 s->draw_text(out, x, offset_y + 2, mult, o1, o2, name, s->grat_yuva_color);
2852 offset_x += s->size * (s->display == STACK);
2853 offset_y += height * (s->display == PARADE);
2857 static void graticule_column(WaveformContext *s, AVFrame *out)
2859 const int step = (s->flags & 2) + 1;
2860 const float o1 = s->opacity;
2861 const float o2 = 1. - o1;
2862 const int width = s->display == PARADE ? out->width / s->acomp : out->width;
2863 int C, k = 0, c, p, l, offset_y = 0, offset_x = 0;
2865 for (c = 0; c < s->ncomp; c++) {
2866 if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
2871 for (p = 0; p < s->ncomp; p++) {
2872 const int v = s->grat_yuva_color[p];
2873 for (l = 0; l < s->nb_glines ; l++) {
2874 const uint16_t pos = s->glines[l].line[C].pos;
2875 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
2876 uint8_t *dst = out->data[p] + y * out->linesize[p] + offset_x;
2878 s->blend_line(dst, width, 1, o1, o2, v, step);
2882 for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2883 const char *name = s->glines[l].line[C].name;
2884 const uint16_t pos = s->glines[l].line[C].pos;
2885 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos) - 10;
2890 s->draw_text(out, 2 + offset_x, y, 1, o1, o2, name, s->grat_yuva_color);
2893 offset_y += s->size * (s->display == STACK);
2894 offset_x += width * (s->display == PARADE);
2898 static void graticule16_column(WaveformContext *s, AVFrame *out)
2900 const int step = (s->flags & 2) + 1;
2901 const float o1 = s->opacity;
2902 const float o2 = 1. - o1;
2903 const int mult = s->max / 256;
2904 const int width = s->display == PARADE ? out->width / s->acomp : out->width;
2905 int C, k = 0, c, p, l, offset_x = 0, offset_y = 0;
2907 for (c = 0; c < s->ncomp; c++) {
2908 if ((!((1 << c) & s->pcomp) || (!s->display && k > 0)))
2913 for (p = 0; p < s->ncomp; p++) {
2914 const int v = s->grat_yuva_color[p] * mult;
2915 for (l = 0; l < s->nb_glines ; l++) {
2916 const uint16_t pos = s->glines[l].line[C].pos;
2917 int y = offset_y + (s->mirror ? s->size - 1 - pos : pos);
2918 uint8_t *dst = (uint8_t *)(out->data[p] + y * out->linesize[p]) + offset_x * 2;
2920 s->blend_line(dst, width, 1, o1, o2, v, step);
2924 for (l = 0; l < s->nb_glines && (s->flags & 1); l++) {
2925 const char *name = s->glines[l].line[C].name;
2926 const uint16_t pos = s->glines[l].line[C].pos;
2927 int y = offset_y + (s->mirror ? s->size - 1 - pos: pos) - 10;
2932 s->draw_text(out, 2 + offset_x, y, mult, o1, o2, name, s->grat_yuva_color);
2935 offset_y += s->size * (s->display == STACK);
2936 offset_x += width * (s->display == PARADE);
2940 static int config_input(AVFilterLink *inlink)
2942 AVFilterContext *ctx = inlink->dst;
2943 WaveformContext *s = ctx->priv;
2945 s->desc = av_pix_fmt_desc_get(inlink->format);
2946 s->ncomp = s->desc->nb_components;
2947 s->bits = s->desc->comp[0].depth;
2948 s->max = 1 << s->bits;
2949 s->intensity = s->fintensity * (s->max - 1);
2951 s->shift_w[0] = s->shift_w[3] = 0;
2952 s->shift_h[0] = s->shift_h[3] = 0;
2953 s->shift_w[1] = s->shift_w[2] = s->desc->log2_chroma_w;
2954 s->shift_h[1] = s->shift_h[2] = s->desc->log2_chroma_h;
2956 s->graticulef = graticule_none;
2958 switch (s->filter) {
2960 case AFLAT: s->size = 256 * 2; break;
2961 case FLAT: s->size = 256 * 3; break;
2962 default: s->size = 256; break;
2965 switch (s->filter | ((s->bits > 8) << 4) |
2966 (s->mode << 8) | (s->mirror << 12)) {
2967 case 0x1100: s->waveform_slice = lowpass_column_mirror; break;
2968 case 0x1000: s->waveform_slice = lowpass_row_mirror; break;
2969 case 0x0100: s->waveform_slice = lowpass_column; break;
2970 case 0x0000: s->waveform_slice = lowpass_row; break;
2971 case 0x1110: s->waveform_slice = lowpass16_column_mirror; break;
2972 case 0x1010: s->waveform_slice = lowpass16_row_mirror; break;
2973 case 0x0110: s->waveform_slice = lowpass16_column; break;
2974 case 0x0010: s->waveform_slice = lowpass16_row; break;
2975 case 0x1101: s->waveform_slice = flat_column_mirror; break;
2976 case 0x1001: s->waveform_slice = flat_row_mirror; break;
2977 case 0x0101: s->waveform_slice = flat_column; break;
2978 case 0x0001: s->waveform_slice = flat_row; break;
2979 case 0x1111: s->waveform_slice = flat16_column_mirror; break;
2980 case 0x1011: s->waveform_slice = flat16_row_mirror; break;
2981 case 0x0111: s->waveform_slice = flat16_column; break;
2982 case 0x0011: s->waveform_slice = flat16_row; break;
2983 case 0x1102: s->waveform_slice = aflat_column_mirror; break;
2984 case 0x1002: s->waveform_slice = aflat_row_mirror; break;
2985 case 0x0102: s->waveform_slice = aflat_column; break;
2986 case 0x0002: s->waveform_slice = aflat_row; break;
2987 case 0x1112: s->waveform_slice = aflat16_column_mirror; break;
2988 case 0x1012: s->waveform_slice = aflat16_row_mirror; break;
2989 case 0x0112: s->waveform_slice = aflat16_column; break;
2990 case 0x0012: s->waveform_slice = aflat16_row; break;
2991 case 0x1103: s->waveform_slice = chroma_column_mirror; break;
2992 case 0x1003: s->waveform_slice = chroma_row_mirror; break;
2993 case 0x0103: s->waveform_slice = chroma_column; break;
2994 case 0x0003: s->waveform_slice = chroma_row; break;
2995 case 0x1113: s->waveform_slice = chroma16_column_mirror; break;
2996 case 0x1013: s->waveform_slice = chroma16_row_mirror; break;
2997 case 0x0113: s->waveform_slice = chroma16_column; break;
2998 case 0x0013: s->waveform_slice = chroma16_row; break;
2999 case 0x1104: s->waveform_slice = color_column_mirror; break;
3000 case 0x1004: s->waveform_slice = color_row_mirror; break;
3001 case 0x0104: s->waveform_slice = color_column; break;
3002 case 0x0004: s->waveform_slice = color_row; break;
3003 case 0x1114: s->waveform_slice = color16_column_mirror; break;
3004 case 0x1014: s->waveform_slice = color16_row_mirror; break;
3005 case 0x0114: s->waveform_slice = color16_column; break;
3006 case 0x0014: s->waveform_slice = color16_row; break;
3007 case 0x1105: s->waveform_slice = acolor_column_mirror; break;
3008 case 0x1005: s->waveform_slice = acolor_row_mirror; break;
3009 case 0x0105: s->waveform_slice = acolor_column; break;
3010 case 0x0005: s->waveform_slice = acolor_row; break;
3011 case 0x1115: s->waveform_slice = acolor16_column_mirror; break;
3012 case 0x1015: s->waveform_slice = acolor16_row_mirror; break;
3013 case 0x0115: s->waveform_slice = acolor16_column; break;
3014 case 0x0015: s->waveform_slice = acolor16_row; break;
3015 case 0x1106: s->waveform_slice = xflat_column_mirror; break;
3016 case 0x1006: s->waveform_slice = xflat_row_mirror; break;
3017 case 0x0106: s->waveform_slice = xflat_column; break;
3018 case 0x0006: s->waveform_slice = xflat_row; break;
3019 case 0x1116: s->waveform_slice = xflat16_column_mirror; break;
3020 case 0x1016: s->waveform_slice = xflat16_row_mirror; break;
3021 case 0x0116: s->waveform_slice = xflat16_column; break;
3022 case 0x0016: s->waveform_slice = xflat16_row; break;
3025 s->grat_yuva_color[0] = 255;
3026 s->grat_yuva_color[1] = s->graticule == GRAT_INVERT ? 255 : 0;
3027 s->grat_yuva_color[2] = s->graticule == GRAT_ORANGE || s->graticule == GRAT_INVERT ? 255 : 0;
3028 s->grat_yuva_color[3] = 255;
3030 if (s->mode == 0 && s->graticule != GRAT_INVERT) {
3031 s->blend_line = s->bits <= 8 ? blend_vline : blend_vline16;
3032 s->draw_text = s->bits <= 8 ? draw_vtext : draw_vtext16;
3033 } else if (s->graticule != GRAT_INVERT) {
3034 s->blend_line = s->bits <= 8 ? blend_hline : blend_hline16;
3035 s->draw_text = s->bits <= 8 ? draw_htext : draw_htext16;
3036 } else if (s->mode == 0 && s->graticule == GRAT_INVERT) {
3037 s->blend_line = s->bits <= 8 ? iblend_vline : iblend_vline16;
3038 s->draw_text = s->bits <= 8 ? idraw_vtext : idraw_vtext16;
3039 } else if (s->graticule == GRAT_INVERT) {
3040 s->blend_line = s->bits <= 8 ? iblend_hline : iblend_hline16;
3041 s->draw_text = s->bits <= 8 ? idraw_htext : idraw_htext16;
3044 switch (s->filter) {
3052 if (s->graticule > GRAT_NONE && s->mode == 1)
3053 s->graticulef = s->bits > 8 ? graticule16_column : graticule_column;
3054 else if (s->graticule > GRAT_NONE && s->mode == 0)
3055 s->graticulef = s->bits > 8 ? graticule16_row : graticule_row;
3059 switch (s->filter) {
3066 case 8: s->glines = (GraticuleLines *)digital8; s->nb_glines = FF_ARRAY_ELEMS(digital8); break;
3067 case 9: s->glines = (GraticuleLines *)digital9; s->nb_glines = FF_ARRAY_ELEMS(digital9); break;
3068 case 10: s->glines = (GraticuleLines *)digital10; s->nb_glines = FF_ARRAY_ELEMS(digital10); break;
3069 case 12: s->glines = (GraticuleLines *)digital12; s->nb_glines = FF_ARRAY_ELEMS(digital12); break;
3074 case 8: s->glines = (GraticuleLines *)millivolts8; s->nb_glines = FF_ARRAY_ELEMS(millivolts8); break;
3075 case 9: s->glines = (GraticuleLines *)millivolts9; s->nb_glines = FF_ARRAY_ELEMS(millivolts9); break;
3076 case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
3077 case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
3082 case 8: s->glines = (GraticuleLines *)ire8; s->nb_glines = FF_ARRAY_ELEMS(ire8); break;
3083 case 9: s->glines = (GraticuleLines *)ire9; s->nb_glines = FF_ARRAY_ELEMS(ire9); break;
3084 case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
3085 case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
3094 case 8: s->glines = (GraticuleLines *)chroma_digital8; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital8); break;
3095 case 9: s->glines = (GraticuleLines *)chroma_digital9; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital9); break;
3096 case 10: s->glines = (GraticuleLines *)chroma_digital10; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital10); break;
3097 case 12: s->glines = (GraticuleLines *)chroma_digital12; s->nb_glines = FF_ARRAY_ELEMS(chroma_digital12); break;
3102 case 8: s->glines = (GraticuleLines *)millivolts8; s->nb_glines = FF_ARRAY_ELEMS(millivolts8); break;
3103 case 9: s->glines = (GraticuleLines *)millivolts9; s->nb_glines = FF_ARRAY_ELEMS(millivolts9); break;
3104 case 10: s->glines = (GraticuleLines *)millivolts10; s->nb_glines = FF_ARRAY_ELEMS(millivolts10); break;
3105 case 12: s->glines = (GraticuleLines *)millivolts12; s->nb_glines = FF_ARRAY_ELEMS(millivolts12); break;
3110 case 8: s->glines = (GraticuleLines *)ire8; s->nb_glines = FF_ARRAY_ELEMS(ire8); break;
3111 case 9: s->glines = (GraticuleLines *)ire9; s->nb_glines = FF_ARRAY_ELEMS(ire9); break;
3112 case 10: s->glines = (GraticuleLines *)ire10; s->nb_glines = FF_ARRAY_ELEMS(ire10); break;
3113 case 12: s->glines = (GraticuleLines *)ire12; s->nb_glines = FF_ARRAY_ELEMS(ire12); break;
3123 case 8: s->glines = (GraticuleLines *)aflat_digital8; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital8); break;
3124 case 9: s->glines = (GraticuleLines *)aflat_digital9; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital9); break;
3125 case 10: s->glines = (GraticuleLines *)aflat_digital10; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital10); break;
3126 case 12: s->glines = (GraticuleLines *)aflat_digital12; s->nb_glines = FF_ARRAY_ELEMS(aflat_digital12); break;
3131 case 8: s->glines = (GraticuleLines *)aflat_millivolts8; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts8); break;
3132 case 9: s->glines = (GraticuleLines *)aflat_millivolts9; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts9); break;
3133 case 10: s->glines = (GraticuleLines *)aflat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts10); break;
3134 case 12: s->glines = (GraticuleLines *)aflat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(aflat_millivolts12); break;
3139 case 8: s->glines = (GraticuleLines *)aflat_ire8; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire8); break;
3140 case 9: s->glines = (GraticuleLines *)aflat_ire9; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire9); break;
3141 case 10: s->glines = (GraticuleLines *)aflat_ire10; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire10); break;
3142 case 12: s->glines = (GraticuleLines *)aflat_ire12; s->nb_glines = FF_ARRAY_ELEMS(aflat_ire12); break;
3151 case 8: s->glines = (GraticuleLines *)flat_digital8; s->nb_glines = FF_ARRAY_ELEMS(flat_digital8); break;
3152 case 9: s->glines = (GraticuleLines *)flat_digital9; s->nb_glines = FF_ARRAY_ELEMS(flat_digital9); break;
3153 case 10: s->glines = (GraticuleLines *)flat_digital10; s->nb_glines = FF_ARRAY_ELEMS(flat_digital10); break;
3154 case 12: s->glines = (GraticuleLines *)flat_digital12; s->nb_glines = FF_ARRAY_ELEMS(flat_digital12); break;
3159 case 8: s->glines = (GraticuleLines *)flat_millivolts8; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts8); break;
3160 case 9: s->glines = (GraticuleLines *)flat_millivolts9; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts9); break;
3161 case 10: s->glines = (GraticuleLines *)flat_millivolts10; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts10); break;
3162 case 12: s->glines = (GraticuleLines *)flat_millivolts12; s->nb_glines = FF_ARRAY_ELEMS(flat_millivolts12); break;
3167 case 8: s->glines = (GraticuleLines *)flat_ire8; s->nb_glines = FF_ARRAY_ELEMS(flat_ire8); break;
3168 case 9: s->glines = (GraticuleLines *)flat_ire9; s->nb_glines = FF_ARRAY_ELEMS(flat_ire9); break;
3169 case 10: s->glines = (GraticuleLines *)flat_ire10; s->nb_glines = FF_ARRAY_ELEMS(flat_ire10); break;
3170 case 12: s->glines = (GraticuleLines *)flat_ire12; s->nb_glines = FF_ARRAY_ELEMS(flat_ire12); break;
3177 s->size = s->size << (s->bits - 8);
3179 switch (inlink->format) {
3180 case AV_PIX_FMT_GBRAP:
3181 case AV_PIX_FMT_GBRP:
3182 case AV_PIX_FMT_GBRP9:
3183 case AV_PIX_FMT_GBRP10:
3184 case AV_PIX_FMT_GBRP12:
3186 memcpy(s->bg_color, black_gbrp_color, sizeof(s->bg_color));
3189 memcpy(s->bg_color, black_yuva_color, sizeof(s->bg_color));
3192 s->bg_color[3] *= s->bgopacity;
3197 static int config_output(AVFilterLink *outlink)
3199 AVFilterContext *ctx = outlink->src;
3200 AVFilterLink *inlink = ctx->inputs[0];
3201 WaveformContext *s = ctx->priv;
3202 int comp = 0, i, j = 0, k, p, size;
3204 for (i = 0; i < s->ncomp; i++) {
3205 if ((1 << i) & s->pcomp)
3210 return AVERROR(EINVAL);
3212 s->odesc = av_pix_fmt_desc_get(outlink->format);
3213 s->dcomp = s->odesc->nb_components;
3218 outlink->h = s->size * FFMAX(comp * (s->display == STACK), 1);
3219 outlink->w = inlink->w * FFMAX(comp * (s->display == PARADE), 1);
3222 outlink->w = s->size * FFMAX(comp * (s->display == STACK), 1);
3223 outlink->h = inlink->h * FFMAX(comp * (s->display == PARADE), 1);
3227 s->peak = av_malloc_array(size, 32 * sizeof(*s->peak));
3229 return AVERROR(ENOMEM);
3231 for (p = 0; p < s->ncomp; p++) {
3232 const int plane = s->desc->comp[p].plane;
3235 if (!((1 << p) & s->pcomp))
3238 for (k = 0; k < 4; k++) {
3239 s->emax[plane][k] = s->peak + size * (plane * 4 + k + 0);
3240 s->emin[plane][k] = s->peak + size * (plane * 4 + k + 16);
3243 offset = j++ * s->size * (s->display == STACK);
3244 s->estart[plane] = offset;
3245 s->eend[plane] = (offset + s->size - 1);
3246 for (i = 0; i < size; i++) {
3247 for (k = 0; k < 4; k++) {
3248 s->emax[plane][k][i] = s->estart[plane];
3249 s->emin[plane][k][i] = s->eend[plane];
3254 outlink->sample_aspect_ratio = (AVRational){1,1};
3259 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
3261 AVFilterContext *ctx = inlink->dst;
3262 WaveformContext *s = ctx->priv;
3263 AVFilterLink *outlink = ctx->outputs[0];
3267 out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
3270 return AVERROR(ENOMEM);
3273 out->color_range = AVCOL_RANGE_JPEG;
3275 for (k = 0; k < s->dcomp; k++) {
3277 for (i = 0; i < outlink->h ; i++)
3278 memset(out->data[s->odesc->comp[k].plane] +
3279 i * out->linesize[s->odesc->comp[k].plane],
3280 s->bg_color[k], outlink->w);
3282 const int mult = s->max / 256;
3283 uint16_t *dst = (uint16_t *)out->data[s->odesc->comp[k].plane];
3285 for (i = 0; i < outlink->h ; i++) {
3286 for (j = 0; j < outlink->w; j++)
3287 dst[j] = s->bg_color[k] * mult;
3288 dst += out->linesize[s->odesc->comp[k].plane] / 2;
3293 for (k = 0, i = 0; k < s->ncomp; k++) {
3294 if ((1 << k) & s->pcomp) {
3295 const int plane = s->desc->comp[k].plane;
3300 if (s->display == PARADE) {
3301 offset_x = s->mode ? i++ * inlink->w : 0;
3302 offset_y = s->mode ? 0 : i++ * inlink->h;
3304 offset_y = s->mode ? i++ * s->size * !!s->display : 0;
3305 offset_x = s->mode ? 0 : i++ * s->size * !!s->display;
3311 td.offset_y = offset_y;
3312 td.offset_x = offset_x;
3313 ctx->internal->execute(ctx, s->waveform_slice, &td, NULL, ff_filter_get_nb_threads(ctx));
3314 switch (s->filter) {
3320 envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
3322 envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
3326 envelope(s, out, plane, plane, s->mode ? offset_x : offset_y);
3327 envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3329 envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y);
3330 envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3336 envelope(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
3337 envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3338 envelope(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
3340 envelope16(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y);
3341 envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y);
3342 envelope16(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y);
3348 s->graticulef(s, out);
3351 return ff_filter_frame(outlink, out);
3354 static av_cold void uninit(AVFilterContext *ctx)
3356 WaveformContext *s = ctx->priv;
3361 static const AVFilterPad inputs[] = {
3364 .type = AVMEDIA_TYPE_VIDEO,
3365 .filter_frame = filter_frame,
3366 .config_props = config_input,
3371 static const AVFilterPad outputs[] = {
3374 .type = AVMEDIA_TYPE_VIDEO,
3375 .config_props = config_output,
3380 AVFilter ff_vf_waveform = {
3382 .description = NULL_IF_CONFIG_SMALL("Video waveform monitor."),
3383 .priv_size = sizeof(WaveformContext),
3384 .priv_class = &waveform_class,
3385 .query_formats = query_formats,
3389 .flags = AVFILTER_FLAG_SLICE_THREADS,