FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/vf_waveform.c
Date: 2024-12-12 01:08:13
Exec Total Coverage
Lines: 298 1659 18.0%
Functions: 13 110 11.8%
Branches: 168 1715 9.8%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2012-2016 Paul B Mahol
3 * Copyright (c) 2013 Marton Balint
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "libavutil/mem.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/pixdesc.h"
25 #include "libavutil/xga_font_data.h"
26 #include "avfilter.h"
27 #include "filters.h"
28 #include "formats.h"
29 #include "video.h"
30
31 typedef struct ThreadData {
32 AVFrame *in;
33 AVFrame *out;
34 int component;
35 int offset_y;
36 int offset_x;
37 } ThreadData;
38
39 enum FitMode {
40 FM_NONE,
41 FM_SIZE,
42 NB_FITMODES
43 };
44
45 enum FilterType {
46 LOWPASS,
47 FLAT,
48 AFLAT,
49 CHROMA,
50 COLOR,
51 ACOLOR,
52 XFLAT,
53 YFLAT,
54 NB_FILTERS
55 };
56
57 enum DisplayType {
58 OVERLAY,
59 STACK,
60 PARADE,
61 NB_DISPLAYS
62 };
63
64 enum ScaleType {
65 DIGITAL,
66 MILLIVOLTS,
67 IRE,
68 NB_SCALES
69 };
70
71 enum GraticuleType {
72 GRAT_NONE,
73 GRAT_GREEN,
74 GRAT_ORANGE,
75 GRAT_INVERT,
76 NB_GRATICULES
77 };
78
79 typedef struct GraticuleLine {
80 const char *name;
81 uint16_t pos;
82 } GraticuleLine;
83
84 typedef struct GraticuleLines {
85 struct GraticuleLine line[4];
86 } GraticuleLines;
87
88 typedef struct WaveformContext {
89 const AVClass *class;
90 int mode;
91 int acomp;
92 int dcomp;
93 int ncomp;
94 int pcomp;
95 uint8_t bg_color[4];
96 float fintensity;
97 int intensity;
98 int mirror;
99 int display;
100 int envelope;
101 int graticule;
102 float opacity;
103 float bgopacity;
104 int estart[4];
105 int eend[4];
106 int *emax[4][4];
107 int *emin[4][4];
108 int *peak;
109 int filter;
110 int flags;
111 int bits;
112 int max;
113 int size;
114 int scale;
115 uint8_t grat_yuva_color[4];
116 int shift_w[4], shift_h[4];
117 GraticuleLines *glines;
118 int nb_glines;
119 int rgb;
120 float ftint[2];
121 int tint[2];
122 int fitmode;
123 int input;
124
125 int (*waveform_slice)(AVFilterContext *ctx, void *arg,
126 int jobnr, int nb_jobs);
127 void (*graticulef)(struct WaveformContext *s, AVFrame *out);
128 void (*blend_line)(uint8_t *dst, int size, int linesize, float o1, float o2,
129 int v, int step);
130 void (*draw_text)(AVFrame *out, int x, int y, int mult,
131 float o1, float o2, const char *txt,
132 const uint8_t color[4]);
133 const AVPixFmtDescriptor *desc;
134 const AVPixFmtDescriptor *odesc;
135 } WaveformContext;
136
137 #define OFFSET(x) offsetof(WaveformContext, x)
138 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
139 #define TFLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
140
141 static const AVOption waveform_options[] = {
142 { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, .unit = "mode" },
143 { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, .unit = "mode" },
144 { "row", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, .unit = "mode" },
145 { "column", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, .unit = "mode" },
146 { "intensity", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, TFLAGS },
147 { "i", "set intensity", OFFSET(fintensity), AV_OPT_TYPE_FLOAT, {.dbl=0.04}, 0, 1, TFLAGS },
148 { "mirror", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
149 { "r", "set mirroring", OFFSET(mirror), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
150 { "display", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, .unit = "display" },
151 { "d", "set display mode", OFFSET(display), AV_OPT_TYPE_INT, {.i64=STACK}, 0, NB_DISPLAYS-1, FLAGS, .unit = "display" },
152 { "overlay", NULL, 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY}, 0, 0, FLAGS, .unit = "display" },
153 { "stack", NULL, 0, AV_OPT_TYPE_CONST, {.i64=STACK}, 0, 0, FLAGS, .unit = "display" },
154 { "parade", NULL, 0, AV_OPT_TYPE_CONST, {.i64=PARADE}, 0, 0, FLAGS, .unit = "display" },
155 { "components", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
156 { "c", "set components to display", OFFSET(pcomp), AV_OPT_TYPE_INT, {.i64=1}, 1, 15, FLAGS },
157 { "envelope", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, TFLAGS, .unit = "envelope" },
158 { "e", "set envelope to display", OFFSET(envelope), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, TFLAGS, .unit = "envelope" },
159 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, TFLAGS, .unit = "envelope" },
160 { "instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, TFLAGS, .unit = "envelope" },
161 { "peak", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, TFLAGS, .unit = "envelope" },
162 { "peak+instant", NULL, 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, TFLAGS, .unit = "envelope" },
163 { "filter", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, .unit = "filter" },
164 { "f", "set filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FILTERS-1, FLAGS, .unit = "filter" },
165 { "lowpass", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LOWPASS}, 0, 0, FLAGS, .unit = "filter" },
166 { "flat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=FLAT}, 0, 0, FLAGS, .unit = "filter" },
167 { "aflat" , NULL, 0, AV_OPT_TYPE_CONST, {.i64=AFLAT}, 0, 0, FLAGS, .unit = "filter" },
168 { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA}, 0, 0, FLAGS, .unit = "filter" },
169 { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR}, 0, 0, FLAGS, .unit = "filter" },
170 { "acolor", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACOLOR}, 0, 0, FLAGS, .unit = "filter" },
171 { "xflat", NULL, 0, AV_OPT_TYPE_CONST, {.i64=XFLAT}, 0, 0, FLAGS, .unit = "filter" },
172 { "yflat", NULL, 0, AV_OPT_TYPE_CONST, {.i64=YFLAT}, 0, 0, FLAGS, .unit = "filter" },
173 { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, .unit = "graticule" },
174 { "g", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_GRATICULES-1, FLAGS, .unit = "graticule" },
175 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_NONE}, 0, 0, FLAGS, .unit = "graticule" },
176 { "green", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_GREEN}, 0, 0, FLAGS, .unit = "graticule" },
177 { "orange", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_ORANGE}, 0, 0, FLAGS, .unit = "graticule" },
178 { "invert", NULL, 0, AV_OPT_TYPE_CONST, {.i64=GRAT_INVERT}, 0, 0, FLAGS, .unit = "graticule" },
179 { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, TFLAGS },
180 { "o", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, TFLAGS },
181 { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, TFLAGS, .unit = "flags" },
182 { "fl", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, TFLAGS, .unit = "flags" },
183 { "numbers", "draw numbers", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, TFLAGS, .unit = "flags" },
184 { "dots", "draw dots instead of lines", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, TFLAGS, .unit = "flags" },
185 { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, .unit = "scale" },
186 { "s", "set scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_SCALES-1, FLAGS, .unit = "scale" },
187 { "digital", NULL, 0, AV_OPT_TYPE_CONST, {.i64=DIGITAL}, 0, 0, FLAGS, .unit = "scale" },
188 { "millivolts", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MILLIVOLTS}, 0, 0, FLAGS, .unit = "scale" },
189 { "ire", NULL, 0, AV_OPT_TYPE_CONST, {.i64=IRE}, 0, 0, FLAGS, .unit = "scale" },
190 { "bgopacity", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, TFLAGS },
191 { "b", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, TFLAGS },
192 { "tint0", "set 1st tint", OFFSET(ftint[0]), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, TFLAGS},
193 { "t0", "set 1st tint", OFFSET(ftint[0]), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, TFLAGS},
194 { "tint1", "set 2nd tint", OFFSET(ftint[1]), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, TFLAGS},
195 { "t1", "set 2nd tint", OFFSET(ftint[1]), AV_OPT_TYPE_FLOAT, {.dbl=0}, -1, 1, TFLAGS},
196 { "fitmode", "set fit mode", OFFSET(fitmode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FITMODES-1, FLAGS, .unit = "fitmode" },
197 { "fm", "set fit mode", OFFSET(fitmode), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_FITMODES-1, FLAGS, .unit = "fitmode" },
198 { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_NONE}, 0, 0, FLAGS, .unit = "fitmode" },
199 { "size", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_SIZE}, 0, 0, FLAGS, .unit = "fitmode" },
200 { "input", "set input formats selection", OFFSET(input), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, .unit = "input" },
201 { "all", "try to select from all available formats", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, .unit = "input" },
202 { "first", "pick first available format", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, .unit = "input" },
203 { NULL }
204 };
205
206 AVFILTER_DEFINE_CLASS(waveform);
207
208 static const enum AVPixelFormat in_lowpass_pix_fmts[] = {
209 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
210 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
211 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
212 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
213 AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P,
214 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
215 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
216 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
217 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12,
218 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
219 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
220 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
221 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
222 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
223 AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA422P12,
224 AV_PIX_FMT_NONE
225 };
226
227 static const enum AVPixelFormat in_color_pix_fmts[] = {
228 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
229 AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12,
230 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
231 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
232 AV_PIX_FMT_YUV411P,
233 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
234 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
235 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
236 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
237 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
238 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
239 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
240 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
241 AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA422P12,
242 AV_PIX_FMT_NONE
243 };
244
245 static const enum AVPixelFormat in_flat_pix_fmts[] = {
246 AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
247 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P,
248 AV_PIX_FMT_YUV411P,
249 AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P,
250 AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P,
251 AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P,
252 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9,
253 AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9,
254 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10,
255 AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10,
256 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV440P12,
257 AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA422P12,
258 AV_PIX_FMT_NONE
259 };
260
261 static const enum AVPixelFormat out_rgb8_lowpass_pix_fmts[] = {
262 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
263 AV_PIX_FMT_NONE
264 };
265
266 static const enum AVPixelFormat out_rgb9_lowpass_pix_fmts[] = {
267 AV_PIX_FMT_GBRP9,
268 AV_PIX_FMT_NONE
269 };
270
271 static const enum AVPixelFormat out_rgb10_lowpass_pix_fmts[] = {
272 AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10,
273 AV_PIX_FMT_NONE
274 };
275
276 static const enum AVPixelFormat out_rgb12_lowpass_pix_fmts[] = {
277 AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12,
278 AV_PIX_FMT_NONE
279 };
280
281 static const enum AVPixelFormat out_yuv8_lowpass_pix_fmts[] = {
282 AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P,
283 AV_PIX_FMT_NONE
284 };
285
286 static const enum AVPixelFormat out_yuv9_lowpass_pix_fmts[] = {
287 AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUVA444P9,
288 AV_PIX_FMT_NONE
289 };
290
291 static const enum AVPixelFormat out_yuv10_lowpass_pix_fmts[] = {
292 AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10,
293 AV_PIX_FMT_NONE
294 };
295
296 static const enum AVPixelFormat out_yuv12_lowpass_pix_fmts[] = {
297 AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUVA444P12,
298 AV_PIX_FMT_NONE
299 };
300
301 static const enum AVPixelFormat out_gray8_lowpass_pix_fmts[] = {
302 AV_PIX_FMT_GRAY8,
303 AV_PIX_FMT_NONE
304 };
305
306 static const enum AVPixelFormat out_gray9_lowpass_pix_fmts[] = {
307 AV_PIX_FMT_GRAY9,
308 AV_PIX_FMT_NONE
309 };
310
311 static const enum AVPixelFormat out_gray10_lowpass_pix_fmts[] = {
312 AV_PIX_FMT_GRAY10,
313 AV_PIX_FMT_NONE
314 };
315
316 static const enum AVPixelFormat out_gray12_lowpass_pix_fmts[] = {
317 AV_PIX_FMT_GRAY12,
318 AV_PIX_FMT_NONE
319 };
320
321 8 static int query_formats(AVFilterContext *ctx)
322 {
323 8 WaveformContext *s = ctx->priv;
324 const enum AVPixelFormat *out_pix_fmts;
325 const enum AVPixelFormat *in_pix_fmts;
326 const AVPixFmtDescriptor *desc, *desc2;
327 AVFilterFormats *avff, *avff2;
328 int depth, depth2, rgb, i, ret, ncomp, ncomp2;
329
330
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (!ctx->inputs[0]->incfg.formats ||
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 !ctx->inputs[0]->incfg.formats->nb_formats) {
332 4 return AVERROR(EAGAIN);
333 }
334
335
1/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 switch (s->filter) {
336 4 case LOWPASS: in_pix_fmts = in_lowpass_pix_fmts; break;
337 case CHROMA:
338 case XFLAT:
339 case YFLAT:
340 case AFLAT:
341 case FLAT: in_pix_fmts = in_flat_pix_fmts; break;
342 case ACOLOR:
343 case COLOR: in_pix_fmts = in_color_pix_fmts; break;
344 default: return AVERROR_BUG;
345 }
346
347
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!ctx->inputs[0]->outcfg.formats) {
348
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if ((ret = ff_formats_ref(ff_make_format_list(in_pix_fmts), &ctx->inputs[0]->outcfg.formats)) < 0)
349 return ret;
350 }
351
352 4 avff = ctx->inputs[0]->incfg.formats;
353 4 avff2 = ctx->inputs[0]->outcfg.formats;
354 4 desc = av_pix_fmt_desc_get(avff->formats[0]);
355 4 desc2 = av_pix_fmt_desc_get(avff2->formats[0]);
356 4 ncomp = desc->nb_components;
357 4 ncomp2 = desc2->nb_components;
358 4 rgb = desc->flags & AV_PIX_FMT_FLAG_RGB;
359 4 depth = desc->comp[0].depth;
360 4 depth2 = desc2->comp[0].depth;
361
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (ncomp != ncomp2 || depth != depth2)
362 return AVERROR(EAGAIN);
363
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 for (i = 1; i < avff->nb_formats && !s->input; i++) {
364 desc = av_pix_fmt_desc_get(avff->formats[i]);
365 if (rgb != (desc->flags & AV_PIX_FMT_FLAG_RGB) ||
366 depth != desc->comp[0].depth)
367 return AVERROR(EAGAIN);
368 }
369
370
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (s->filter == LOWPASS && ncomp == 1 && depth == 8)
371 out_pix_fmts = out_gray8_lowpass_pix_fmts;
372
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (s->filter == LOWPASS && ncomp == 1 && depth == 9)
373 out_pix_fmts = out_gray9_lowpass_pix_fmts;
374
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (s->filter == LOWPASS && ncomp == 1 && depth == 10)
375 out_pix_fmts = out_gray10_lowpass_pix_fmts;
376
2/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (s->filter == LOWPASS && ncomp == 1 && depth == 12)
377 out_pix_fmts = out_gray12_lowpass_pix_fmts;
378
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (rgb && depth == 8 && ncomp > 2)
379 out_pix_fmts = out_rgb8_lowpass_pix_fmts;
380
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (rgb && depth == 9 && ncomp > 2)
381 out_pix_fmts = out_rgb9_lowpass_pix_fmts;
382
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (rgb && depth == 10 && ncomp > 2)
383 out_pix_fmts = out_rgb10_lowpass_pix_fmts;
384
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 else if (rgb && depth == 12 && ncomp > 2)
385 out_pix_fmts = out_rgb12_lowpass_pix_fmts;
386
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 else if (depth == 8 && ncomp > 2)
387 4 out_pix_fmts = out_yuv8_lowpass_pix_fmts;
388 else if (depth == 9 && ncomp > 2)
389 out_pix_fmts = out_yuv9_lowpass_pix_fmts;
390 else if (depth == 10 && ncomp > 2)
391 out_pix_fmts = out_yuv10_lowpass_pix_fmts;
392 else if (depth == 12 && ncomp > 2)
393 out_pix_fmts = out_yuv12_lowpass_pix_fmts;
394 else
395 return AVERROR(EAGAIN);
396
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if ((ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->incfg.formats)) < 0)
397 return ret;
398
399 4 return 0;
400 }
401
402 static void envelope_instant16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
403 {
404 const int dst_linesize = out->linesize[component] / 2;
405 const int bg = s->bg_color[component] * (s->max / 256);
406 const int limit = s->max - 1;
407 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
408 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
409 const int start = s->estart[plane];
410 const int end = s->eend[plane];
411 uint16_t *dst;
412 int x, y;
413
414 if (s->mode) {
415 for (x = offset; x < offset + dst_w; x++) {
416 for (y = start; y < end; y++) {
417 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
418 if (dst[0] != bg) {
419 dst[0] = limit;
420 break;
421 }
422 }
423 for (y = end - 1; y >= start; y--) {
424 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
425 if (dst[0] != bg) {
426 dst[0] = limit;
427 break;
428 }
429 }
430 }
431 } else {
432 for (y = offset; y < offset + dst_h; y++) {
433 dst = (uint16_t *)out->data[component] + y * dst_linesize;
434 for (x = start; x < end; x++) {
435 if (dst[x] != bg) {
436 dst[x] = limit;
437 break;
438 }
439 }
440 for (x = end - 1; x >= start; x--) {
441 if (dst[x] != bg) {
442 dst[x] = limit;
443 break;
444 }
445 }
446 }
447 }
448 }
449
450 50 static void envelope_instant(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
451 {
452 50 const int dst_linesize = out->linesize[component];
453 50 const uint8_t bg = s->bg_color[component];
454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
456 50 const int start = s->estart[plane];
457 50 const int end = s->eend[plane];
458 uint8_t *dst;
459 int x, y;
460
461
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (s->mode) {
462
2/2
✓ Branch 0 taken 17600 times.
✓ Branch 1 taken 50 times.
17650 for (x = offset; x < offset + dst_w; x++) {
463
1/2
✓ Branch 0 taken 375540 times.
✗ Branch 1 not taken.
375540 for (y = start; y < end; y++) {
464 375540 dst = out->data[component] + y * dst_linesize + x;
465
2/2
✓ Branch 0 taken 17600 times.
✓ Branch 1 taken 357940 times.
375540 if (dst[0] != bg) {
466 17600 dst[0] = 255;
467 17600 break;
468 }
469 }
470
1/2
✓ Branch 0 taken 385656 times.
✗ Branch 1 not taken.
385656 for (y = end - 1; y >= start; y--) {
471 385656 dst = out->data[component] + y * dst_linesize + x;
472
2/2
✓ Branch 0 taken 17600 times.
✓ Branch 1 taken 368056 times.
385656 if (dst[0] != bg) {
473 17600 dst[0] = 255;
474 17600 break;
475 }
476 }
477 }
478 } else {
479 for (y = offset; y < offset + dst_h; y++) {
480 dst = out->data[component] + y * dst_linesize;
481 for (x = start; x < end; x++) {
482 if (dst[x] != bg) {
483 dst[x] = 255;
484 break;
485 }
486 }
487 for (x = end - 1; x >= start; x--) {
488 if (dst[x] != bg) {
489 dst[x] = 255;
490 break;
491 }
492 }
493 }
494 }
495 50 }
496
497 static void envelope_peak16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
498 {
499 const int dst_linesize = out->linesize[component] / 2;
500 const int bg = s->bg_color[component] * (s->max / 256);
501 const int limit = s->max - 1;
502 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
503 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
504 const int start = s->estart[plane];
505 const int end = s->eend[plane];
506 int *emax = s->emax[plane][component];
507 int *emin = s->emin[plane][component];
508 uint16_t *dst;
509 int x, y;
510
511 if (s->mode) {
512 for (x = offset; x < offset + dst_w; x++) {
513 for (y = start; y < end && y < emin[x - offset]; y++) {
514 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
515 if (dst[0] != bg) {
516 emin[x - offset] = y;
517 break;
518 }
519 }
520 for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
521 dst = (uint16_t *)out->data[component] + y * dst_linesize + x;
522 if (dst[0] != bg) {
523 emax[x - offset] = y;
524 break;
525 }
526 }
527 }
528
529 if (s->envelope == 3)
530 envelope_instant16(s, out, plane, component, offset);
531
532 for (x = offset; x < offset + dst_w; x++) {
533 dst = (uint16_t *)out->data[component] + emin[x - offset] * dst_linesize + x;
534 dst[0] = limit;
535 dst = (uint16_t *)out->data[component] + emax[x - offset] * dst_linesize + x;
536 dst[0] = limit;
537 }
538 } else {
539 for (y = offset; y < offset + dst_h; y++) {
540 dst = (uint16_t *)out->data[component] + y * dst_linesize;
541 for (x = start; x < end && x < emin[y - offset]; x++) {
542 if (dst[x] != bg) {
543 emin[y - offset] = x;
544 break;
545 }
546 }
547 for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
548 if (dst[x] != bg) {
549 emax[y - offset] = x;
550 break;
551 }
552 }
553 }
554
555 if (s->envelope == 3)
556 envelope_instant16(s, out, plane, component, offset);
557
558 for (y = offset; y < offset + dst_h; y++) {
559 dst = (uint16_t *)out->data[component] + y * dst_linesize + emin[y - offset];
560 dst[0] = limit;
561 dst = (uint16_t *)out->data[component] + y * dst_linesize + emax[y - offset];
562 dst[0] = limit;
563 }
564 }
565 }
566
567 50 static void envelope_peak(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
568 {
569 50 const int dst_linesize = out->linesize[component];
570 50 const int bg = s->bg_color[component];
571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height;
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width;
573 50 const int start = s->estart[plane];
574 50 const int end = s->eend[plane];
575 50 int *emax = s->emax[plane][component];
576 50 int *emin = s->emin[plane][component];
577 uint8_t *dst;
578 int x, y;
579
580
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (s->mode) {
581
2/2
✓ Branch 0 taken 17600 times.
✓ Branch 1 taken 50 times.
17650 for (x = offset; x < offset + dst_w; x++) {
582
3/4
✓ Branch 0 taken 152559 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 136288 times.
✓ Branch 3 taken 16271 times.
152559 for (y = start; y < end && y < emin[x - offset]; y++) {
583 136288 dst = out->data[component] + y * dst_linesize + x;
584
2/2
✓ Branch 0 taken 1329 times.
✓ Branch 1 taken 134959 times.
136288 if (dst[0] != bg) {
585 1329 emin[x - offset] = y;
586 1329 break;
587 }
588 }
589
3/4
✓ Branch 0 taken 159188 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 144269 times.
✓ Branch 3 taken 14919 times.
159188 for (y = end - 1; y >= start && y >= emax[x - offset]; y--) {
590 144269 dst = out->data[component] + y * dst_linesize + x;
591
2/2
✓ Branch 0 taken 2681 times.
✓ Branch 1 taken 141588 times.
144269 if (dst[0] != bg) {
592 2681 emax[x - offset] = y;
593 2681 break;
594 }
595 }
596 }
597
598
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if (s->envelope == 3)
599 50 envelope_instant(s, out, plane, component, offset);
600
601
2/2
✓ Branch 0 taken 17600 times.
✓ Branch 1 taken 50 times.
17650 for (x = offset; x < offset + dst_w; x++) {
602 17600 dst = out->data[component] + emin[x - offset] * dst_linesize + x;
603 17600 dst[0] = 255;
604 17600 dst = out->data[component] + emax[x - offset] * dst_linesize + x;
605 17600 dst[0] = 255;
606 }
607 } else {
608 for (y = offset; y < offset + dst_h; y++) {
609 dst = out->data[component] + y * dst_linesize;
610 for (x = start; x < end && x < emin[y - offset]; x++) {
611 if (dst[x] != bg) {
612 emin[y - offset] = x;
613 break;
614 }
615 }
616 for (x = end - 1; x >= start && x >= emax[y - offset]; x--) {
617 if (dst[x] != bg) {
618 emax[y - offset] = x;
619 break;
620 }
621 }
622 }
623
624 if (s->envelope == 3)
625 envelope_instant(s, out, plane, component, offset);
626
627 for (y = offset; y < offset + dst_h; y++) {
628 dst = out->data[component] + y * dst_linesize + emin[y - offset];
629 dst[0] = 255;
630 dst = out->data[component] + y * dst_linesize + emax[y - offset];
631 dst[0] = 255;
632 }
633 }
634 50 }
635
636 static void envelope16(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
637 {
638 if (s->envelope == 0) {
639 return;
640 } else if (s->envelope == 1) {
641 envelope_instant16(s, out, plane, component, offset);
642 } else {
643 envelope_peak16(s, out, plane, component, offset);
644 }
645 }
646
647 250 static void envelope(WaveformContext *s, AVFrame *out, int plane, int component, int offset)
648 {
649
2/2
✓ Branch 0 taken 200 times.
✓ Branch 1 taken 50 times.
250 if (s->envelope == 0) {
650 200 return;
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 } else if (s->envelope == 1) {
652 envelope_instant(s, out, plane, component, offset);
653 } else {
654 50 envelope_peak(s, out, plane, component, offset);
655 }
656 }
657
658 static void update16(uint16_t *target, int max, int intensity, int limit)
659 {
660 if (*target <= max)
661 *target += intensity;
662 else
663 *target = limit;
664 }
665
666 20275200 static void update(uint8_t *target, int max, int intensity)
667 {
668
1/2
✓ Branch 0 taken 20275200 times.
✗ Branch 1 not taken.
20275200 if (*target <= max)
669 20275200 *target += intensity;
670 else
671 *target = 255;
672 20275200 }
673
674 static void update_cr(uint8_t *target, int unused, int intensity)
675 {
676 if (*target - intensity > 0)
677 *target -= intensity;
678 else
679 *target = 0;
680 }
681
682 static void update16_cr(uint16_t *target, int unused, int intensity, int limit)
683 {
684 if (*target - intensity > 0)
685 *target -= intensity;
686 else
687 *target = 0;
688 }
689
690 static av_always_inline void lowpass16(WaveformContext *s,
691 AVFrame *in, AVFrame *out,
692 int component, int intensity,
693 int offset_y, int offset_x,
694 int column, int mirror,
695 int jobnr, int nb_jobs)
696 {
697 const int plane = s->desc->comp[component].plane;
698 const int dplane = (s->rgb || s->display == OVERLAY) ? plane : 0;
699 const int shift_w = s->shift_w[component];
700 const int shift_h = s->shift_h[component];
701 const int src_linesize = in->linesize[plane] / 2;
702 const int dst_linesize = out->linesize[dplane] / 2;
703 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
704 const int limit = s->max - 1;
705 const int max = limit - intensity;
706 const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
707 const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
708 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
709 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
710 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
711 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
712 const int step = column ? 1 << shift_w : 1 << shift_h;
713 const uint16_t *src_data = (const uint16_t *)in->data[plane] + sliceh_start * src_linesize;
714 uint16_t *dst_data = (uint16_t *)out->data[dplane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
715 uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
716 uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
717 const uint16_t *p;
718 int y;
719
720 if (!column && mirror)
721 dst_data += s->size;
722
723 for (y = sliceh_start; y < sliceh_end; y++) {
724 const uint16_t *src_data_end = src_data + slicew_end;
725 uint16_t *dst = dst_line + slicew_start * step;
726
727 for (p = src_data + slicew_start; p < src_data_end; p++) {
728 uint16_t *target;
729 int i = 0, v = FFMIN(*p, limit);
730
731 if (column) {
732 do {
733 target = dst++ + dst_signed_linesize * v;
734 update16(target, max, intensity, limit);
735 } while (++i < step);
736 } else {
737 uint16_t *row = dst_data;
738 do {
739 if (mirror)
740 target = row - v - 1;
741 else
742 target = row + v;
743 update16(target, max, intensity, limit);
744 row += dst_linesize;
745 } while (++i < step);
746 }
747 }
748 src_data += src_linesize;
749 dst_data += dst_linesize * step;
750 }
751
752 if (s->display != OVERLAY && column && !s->rgb && out->data[1] && out->data[2]) {
753 const int mult = s->max / 256;
754 const int bg = s->bg_color[0] * mult;
755 const int t0 = s->tint[0];
756 const int t1 = s->tint[1];
757 uint16_t *dst0, *dst1;
758 const uint16_t *src;
759 int x;
760
761 src = (const uint16_t *)(out->data[0]) + offset_y * dst_linesize + offset_x;
762 dst0 = (uint16_t *)(out->data[1]) + offset_y * dst_linesize + offset_x;
763 dst1 = (uint16_t *)(out->data[2]) + offset_y * dst_linesize + offset_x;
764 for (y = 0; y < s->max; y++) {
765 for (x = slicew_start * step; x < slicew_end * step; x++) {
766 if (src[x] != bg) {
767 dst0[x] = t0;
768 dst1[x] = t1;
769 }
770 }
771
772 src += dst_linesize;
773 dst0 += dst_linesize;
774 dst1 += dst_linesize;
775 }
776 } else if (s->display != OVERLAY && !s->rgb && out->data[1] && out->data[2]) {
777 const int mult = s->max / 256;
778 const int bg = s->bg_color[0] * mult;
779 const int t0 = s->tint[0];
780 const int t1 = s->tint[1];
781 uint16_t *dst0, *dst1;
782 const uint16_t *src;
783 int x;
784
785 src = (const uint16_t *)out->data[0] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
786 dst0 = (uint16_t *)(out->data[1]) + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
787 dst1 = (uint16_t *)(out->data[2]) + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
788 for (y = sliceh_start * step; y < sliceh_end * step; y++) {
789 for (x = 0; x < s->max; x++) {
790 if (src[x] != bg) {
791 dst0[x] = t0;
792 dst1[x] = t1;
793 }
794 }
795
796 src += dst_linesize;
797 dst0 += dst_linesize;
798 dst1 += dst_linesize;
799 }
800 }
801 }
802
803 #define LOWPASS16_FUNC(name, column, mirror) \
804 static int lowpass16_##name(AVFilterContext *ctx, \
805 void *arg, int jobnr, \
806 int nb_jobs) \
807 { \
808 WaveformContext *s = ctx->priv; \
809 ThreadData *td = arg; \
810 AVFrame *in = td->in; \
811 AVFrame *out = td->out; \
812 int component = td->component; \
813 int offset_y = td->offset_y; \
814 int offset_x = td->offset_x; \
815 \
816 lowpass16(s, in, out, component, s->intensity, \
817 offset_y, offset_x, column, mirror, \
818 jobnr, nb_jobs); \
819 \
820 return 0; \
821 }
822
823 LOWPASS16_FUNC(column_mirror, 1, 1)
824 LOWPASS16_FUNC(column, 1, 0)
825 LOWPASS16_FUNC(row_mirror, 0, 1)
826 LOWPASS16_FUNC(row, 0, 0)
827
828 2250 static av_always_inline void lowpass(WaveformContext *s,
829 AVFrame *in, AVFrame *out,
830 int component, int intensity,
831 int offset_y, int offset_x,
832 int column, int mirror,
833 int jobnr, int nb_jobs)
834 {
835 2250 const int plane = s->desc->comp[component].plane;
836
2/4
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2250 times.
2250 const int dplane = (s->rgb || s->display == OVERLAY) ? plane : 0;
837 2250 const int shift_w = s->shift_w[component];
838 2250 const int shift_h = s->shift_h[component];
839 2250 const int src_linesize = in->linesize[plane];
840 2250 const int dst_linesize = out->linesize[dplane];
841
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
842 2250 const int max = 255 - intensity;
843 2250 const int src_h = AV_CEIL_RSHIFT(in->height, shift_h);
844 2250 const int src_w = AV_CEIL_RSHIFT(in->width, shift_w);
845
2/2
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 1800 times.
2250 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
846
2/2
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 1800 times.
2250 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
847
2/2
✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 450 times.
2250 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
848
2/2
✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 450 times.
2250 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
849
2/2
✓ Branch 0 taken 1800 times.
✓ Branch 1 taken 450 times.
2250 const int step = column ? 1 << shift_w : 1 << shift_h;
850 2250 const uint8_t *src_data = in->data[plane] + sliceh_start * src_linesize;
851 2250 uint8_t *dst_data = out->data[dplane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
852 2250 uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
853
1/2
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
2250 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
854 const uint8_t *p;
855 int y;
856
857
3/4
✓ Branch 0 taken 450 times.
✓ Branch 1 taken 1800 times.
✓ Branch 2 taken 450 times.
✗ Branch 3 not taken.
2250 if (!column && mirror)
858 450 dst_data += s->size;
859
860
2/2
✓ Branch 0 taken 403200 times.
✓ Branch 1 taken 2250 times.
405450 for (y = sliceh_start; y < sliceh_end; y++) {
861 403200 const uint8_t *src_data_end = src_data + slicew_end;
862 403200 uint8_t *dst = dst_line + slicew_start * step;
863
864
2/2
✓ Branch 0 taken 17740800 times.
✓ Branch 1 taken 403200 times.
18144000 for (p = src_data + slicew_start; p < src_data_end; p++) {
865 uint8_t *target;
866 17740800 int i = 0;
867
868
2/2
✓ Branch 0 taken 12672000 times.
✓ Branch 1 taken 5068800 times.
17740800 if (column) {
869 do {
870 15206400 target = dst++ + dst_signed_linesize * *p;
871 15206400 update(target, max, intensity);
872
2/2
✓ Branch 0 taken 2534400 times.
✓ Branch 1 taken 12672000 times.
15206400 } while (++i < step);
873 } else {
874 5068800 uint8_t *row = dst_data;
875 do {
876
1/2
✓ Branch 0 taken 5068800 times.
✗ Branch 1 not taken.
5068800 if (mirror)
877 5068800 target = row - *p - 1;
878 else
879 target = row + *p;
880 5068800 update(target, max, intensity);
881 5068800 row += dst_linesize;
882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5068800 times.
5068800 } while (++i < step);
883 }
884 }
885 403200 src_data += src_linesize;
886 403200 dst_data += dst_linesize * step;
887 }
888
889
6/10
✓ Branch 0 taken 2250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1800 times.
✓ Branch 3 taken 450 times.
✓ Branch 4 taken 1800 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1800 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1800 times.
✗ Branch 9 not taken.
4050 if (s->display != OVERLAY && column && !s->rgb && out->data[1] && out->data[2]) {
890 1800 const int bg = s->bg_color[0];
891 1800 const int dst_h = 256;
892 1800 const int t0 = s->tint[0];
893 1800 const int t1 = s->tint[1];
894 uint8_t *dst0, *dst1;
895 const uint8_t *src;
896 int x;
897
898 1800 src = out->data[0] + offset_y * dst_linesize + offset_x;
899 1800 dst0 = out->data[1] + offset_y * dst_linesize + offset_x;
900 1800 dst1 = out->data[2] + offset_y * dst_linesize + offset_x;
901
2/2
✓ Branch 0 taken 460800 times.
✓ Branch 1 taken 1800 times.
462600 for (y = 0; y < dst_h; y++) {
902
2/2
✓ Branch 0 taken 18022400 times.
✓ Branch 1 taken 460800 times.
18483200 for (x = slicew_start * step; x < slicew_end * step; x++) {
903
2/2
✓ Branch 0 taken 8505880 times.
✓ Branch 1 taken 9516520 times.
18022400 if (src[x] != bg) {
904 8505880 dst0[x] = t0;
905 8505880 dst1[x] = t1;
906 }
907 }
908
909 460800 src += dst_linesize;
910 460800 dst0 += dst_linesize;
911 460800 dst1 += dst_linesize;
912 }
913
4/8
✓ Branch 0 taken 450 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 450 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 450 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 450 times.
✗ Branch 7 not taken.
450 } else if (s->display != OVERLAY && !s->rgb && out->data[1] && out->data[2]) {
914 450 const int bg = s->bg_color[0];
915 450 const int dst_w = 256;
916 450 const int t0 = s->tint[0];
917 450 const int t1 = s->tint[1];
918 uint8_t *dst0, *dst1;
919 const uint8_t *src;
920 int x;
921
922 450 src = out->data[0] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
923 450 dst0 = out->data[1] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
924 450 dst1 = out->data[2] + (offset_y + sliceh_start * step) * dst_linesize + offset_x;
925
2/2
✓ Branch 0 taken 14400 times.
✓ Branch 1 taken 450 times.
14850 for (y = sliceh_start * step; y < sliceh_end * step; y++) {
926
2/2
✓ Branch 0 taken 3686400 times.
✓ Branch 1 taken 14400 times.
3700800 for (x = 0; x < dst_w; x++) {
927
2/2
✓ Branch 0 taken 1616988 times.
✓ Branch 1 taken 2069412 times.
3686400 if (src[x] != bg) {
928 1616988 dst0[x] = t0;
929 1616988 dst1[x] = t1;
930 }
931 }
932
933 14400 src += dst_linesize;
934 14400 dst0 += dst_linesize;
935 14400 dst1 += dst_linesize;
936 }
937 }
938 2250 }
939
940 #define LOWPASS_FUNC(name, column, mirror) \
941 static int lowpass_##name(AVFilterContext *ctx, \
942 void *arg, int jobnr, \
943 int nb_jobs) \
944 { \
945 WaveformContext *s = ctx->priv; \
946 ThreadData *td = arg; \
947 AVFrame *in = td->in; \
948 AVFrame *out = td->out; \
949 int component = td->component; \
950 int offset_y = td->offset_y; \
951 int offset_x = td->offset_x; \
952 \
953 lowpass(s, in, out, component, s->intensity, \
954 offset_y, offset_x, column, mirror, \
955 jobnr, nb_jobs); \
956 \
957 return 0; \
958 }
959
960 1800 LOWPASS_FUNC(column_mirror, 1, 1)
961 LOWPASS_FUNC(column, 1, 0)
962 450 LOWPASS_FUNC(row_mirror, 0, 1)
963 LOWPASS_FUNC(row, 0, 0)
964
965 static av_always_inline void flat16(WaveformContext *s,
966 AVFrame *in, AVFrame *out,
967 int component, int intensity,
968 int offset_y, int offset_x,
969 int column, int mirror,
970 int jobnr, int nb_jobs)
971 {
972 const int plane = s->desc->comp[component].plane;
973 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
974 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
975 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
976 const int c0_shift_w = s->shift_w[ component + 0 ];
977 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
978 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
979 const int c0_shift_h = s->shift_h[ component + 0 ];
980 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
981 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
982 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
983 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
984 const int limit = s->max - 1;
985 const int max = limit - intensity;
986 const int mid = s->max / 2;
987 const int src_h = in->height;
988 const int src_w = in->width;
989 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
990 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
991 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
992 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
993 int x, y;
994
995 if (column) {
996 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
997 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
998
999 for (x = slicew_start; x < slicew_end; x++) {
1000 const uint16_t *c0_data = (uint16_t *)in->data[plane + 0];
1001 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
1002 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
1003 uint16_t *d0_data = (uint16_t *)(out->data[plane]) + offset_y * d0_linesize + offset_x;
1004 uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + offset_y * d1_linesize + offset_x;
1005 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1006 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1007 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1008 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1009
1010 for (y = 0; y < src_h; y++) {
1011 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
1012 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
1013 uint16_t *target;
1014
1015 target = d0 + x + d0_signed_linesize * c0;
1016 update16(target, max, intensity, limit);
1017 target = d1 + x + d1_signed_linesize * (c0 - c1);
1018 update16(target, max, intensity, limit);
1019 target = d1 + x + d1_signed_linesize * (c0 + c1);
1020 update16(target, max, intensity, limit);
1021
1022 if (!c0_shift_h || (y & c0_shift_h))
1023 c0_data += c0_linesize;
1024 if (!c1_shift_h || (y & c1_shift_h))
1025 c1_data += c1_linesize;
1026 if (!c2_shift_h || (y & c2_shift_h))
1027 c2_data += c2_linesize;
1028 d0_data += d0_linesize;
1029 d1_data += d1_linesize;
1030 }
1031 }
1032 } else {
1033 const uint16_t *c0_data = (uint16_t *)(in->data[plane]) + (sliceh_start >> c0_shift_h) * c0_linesize;
1034 const uint16_t *c1_data = (uint16_t *)(in->data[(plane + 1) % s->ncomp]) + (sliceh_start >> c1_shift_h) * c1_linesize;
1035 const uint16_t *c2_data = (uint16_t *)(in->data[(plane + 2) % s->ncomp]) + (sliceh_start >> c2_shift_h) * c2_linesize;
1036 uint16_t *d0_data = (uint16_t *)(out->data[plane]) + (offset_y + sliceh_start) * d0_linesize + offset_x;
1037 uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + (offset_y + sliceh_start) * d1_linesize + offset_x;
1038
1039 if (mirror) {
1040 d0_data += s->size - 1;
1041 d1_data += s->size - 1;
1042 }
1043
1044 for (y = sliceh_start; y < sliceh_end; y++) {
1045 for (x = 0; x < src_w; x++) {
1046 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max;
1047 const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit);
1048 uint16_t *target;
1049
1050 if (mirror) {
1051 target = d0_data - c0;
1052 update16(target, max, intensity, limit);
1053 target = d1_data - (c0 - c1);
1054 update16(target, max, intensity, limit);
1055 target = d1_data - (c0 + c1);
1056 update16(target, max, intensity, limit);
1057 } else {
1058 target = d0_data + c0;
1059 update16(target, max, intensity, limit);
1060 target = d1_data + (c0 - c1);
1061 update16(target, max, intensity, limit);
1062 target = d1_data + (c0 + c1);
1063 update16(target, max, intensity, limit);
1064 }
1065 }
1066
1067 if (!c0_shift_h || (y & c0_shift_h))
1068 c0_data += c0_linesize;
1069 if (!c1_shift_h || (y & c1_shift_h))
1070 c1_data += c1_linesize;
1071 if (!c2_shift_h || (y & c2_shift_h))
1072 c2_data += c2_linesize;
1073 d0_data += d0_linesize;
1074 d1_data += d1_linesize;
1075 }
1076 }
1077 }
1078
1079 #define FLAT16_FUNC(name, column, mirror) \
1080 static int flat16_##name(AVFilterContext *ctx, \
1081 void *arg, int jobnr, \
1082 int nb_jobs) \
1083 { \
1084 WaveformContext *s = ctx->priv; \
1085 ThreadData *td = arg; \
1086 AVFrame *in = td->in; \
1087 AVFrame *out = td->out; \
1088 int component = td->component; \
1089 int offset_y = td->offset_y; \
1090 int offset_x = td->offset_x; \
1091 \
1092 flat16(s, in, out, component, s->intensity, \
1093 offset_y, offset_x, column, mirror, \
1094 jobnr, nb_jobs); \
1095 \
1096 return 0; \
1097 }
1098
1099 FLAT16_FUNC(column_mirror, 1, 1)
1100 FLAT16_FUNC(column, 1, 0)
1101 FLAT16_FUNC(row_mirror, 0, 1)
1102 FLAT16_FUNC(row, 0, 0)
1103
1104 static av_always_inline void flat(WaveformContext *s,
1105 AVFrame *in, AVFrame *out,
1106 int component, int intensity,
1107 int offset_y, int offset_x,
1108 int column, int mirror,
1109 int jobnr, int nb_jobs)
1110 {
1111 const int plane = s->desc->comp[component].plane;
1112 const int c0_linesize = in->linesize[ plane + 0 ];
1113 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1114 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1115 const int c0_shift_w = s->shift_w[ component + 0 ];
1116 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1117 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1118 const int c0_shift_h = s->shift_h[ component + 0 ];
1119 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1120 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1121 const int d0_linesize = out->linesize[ plane + 0 ];
1122 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1123 const int max = 255 - intensity;
1124 const int src_h = in->height;
1125 const int src_w = in->width;
1126 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1127 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1128 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1129 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1130 int x, y;
1131
1132 if (column) {
1133 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1134 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1135
1136 for (x = slicew_start; x < slicew_end; x++) {
1137 const uint8_t *c0_data = in->data[plane + 0];
1138 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp];
1139 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp];
1140 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1141 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1142 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1143 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1144 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1145 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1146
1147 for (y = 0; y < src_h; y++) {
1148 const int c0 = c0_data[x >> c0_shift_w] + 256;
1149 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1150 uint8_t *target;
1151
1152 target = d0 + x + d0_signed_linesize * c0;
1153 update(target, max, intensity);
1154 target = d1 + x + d1_signed_linesize * (c0 - c1);
1155 update(target, max, intensity);
1156 target = d1 + x + d1_signed_linesize * (c0 + c1);
1157 update(target, max, intensity);
1158
1159 if (!c0_shift_h || (y & c0_shift_h))
1160 c0_data += c0_linesize;
1161 if (!c1_shift_h || (y & c1_shift_h))
1162 c1_data += c1_linesize;
1163 if (!c2_shift_h || (y & c2_shift_h))
1164 c2_data += c2_linesize;
1165 d0_data += d0_linesize;
1166 d1_data += d1_linesize;
1167 }
1168 }
1169 } else {
1170 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;
1171 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1172 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1173 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1174 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1175
1176 if (mirror) {
1177 d0_data += s->size - 1;
1178 d1_data += s->size - 1;
1179 }
1180
1181 for (y = sliceh_start; y < sliceh_end; y++) {
1182 for (x = 0; x < src_w; x++) {
1183 const int c0 = c0_data[x >> c0_shift_w] + 256;
1184 const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128);
1185 uint8_t *target;
1186
1187 if (mirror) {
1188 target = d0_data - c0;
1189 update(target, max, intensity);
1190 target = d1_data - (c0 - c1);
1191 update(target, max, intensity);
1192 target = d1_data - (c0 + c1);
1193 update(target, max, intensity);
1194 } else {
1195 target = d0_data + c0;
1196 update(target, max, intensity);
1197 target = d1_data + (c0 - c1);
1198 update(target, max, intensity);
1199 target = d1_data + (c0 + c1);
1200 update(target, max, intensity);
1201 }
1202 }
1203
1204 if (!c0_shift_h || (y & c0_shift_h))
1205 c0_data += c0_linesize;
1206 if (!c1_shift_h || (y & c1_shift_h))
1207 c1_data += c1_linesize;
1208 if (!c2_shift_h || (y & c2_shift_h))
1209 c2_data += c2_linesize;
1210 d0_data += d0_linesize;
1211 d1_data += d1_linesize;
1212 }
1213 }
1214 }
1215
1216 #define FLAT_FUNC(name, column, mirror) \
1217 static int flat_##name(AVFilterContext *ctx, \
1218 void *arg, int jobnr, \
1219 int nb_jobs) \
1220 { \
1221 WaveformContext *s = ctx->priv; \
1222 ThreadData *td = arg; \
1223 AVFrame *in = td->in; \
1224 AVFrame *out = td->out; \
1225 int component = td->component; \
1226 int offset_y = td->offset_y; \
1227 int offset_x = td->offset_x; \
1228 \
1229 flat(s, in, out, component, s->intensity, \
1230 offset_y, offset_x, column, mirror, \
1231 jobnr, nb_jobs); \
1232 \
1233 return 0; \
1234 }
1235
1236 FLAT_FUNC(column_mirror, 1, 1)
1237 FLAT_FUNC(column, 1, 0)
1238 FLAT_FUNC(row_mirror, 0, 1)
1239 FLAT_FUNC(row, 0, 0)
1240
1241 #define AFLAT16(name, update_cb, update_cr, column, mirror) \
1242 static int name(AVFilterContext *ctx, \
1243 void *arg, int jobnr, \
1244 int nb_jobs) \
1245 { \
1246 WaveformContext *s = ctx->priv; \
1247 ThreadData *td = arg; \
1248 AVFrame *in = td->in; \
1249 AVFrame *out = td->out; \
1250 int component = td->component; \
1251 int offset_y = td->offset_y; \
1252 int offset_x = td->offset_x; \
1253 const int intensity = s->intensity; \
1254 const int plane = s->desc->comp[component].plane; \
1255 const int c0_linesize = in->linesize[ plane + 0 ] / 2; \
1256 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; \
1257 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; \
1258 const int c0_shift_w = s->shift_w[ component + 0 ]; \
1259 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \
1260 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \
1261 const int c0_shift_h = s->shift_h[ component + 0 ]; \
1262 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \
1263 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \
1264 const int d0_linesize = out->linesize[ plane + 0 ] / 2; \
1265 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; \
1266 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; \
1267 const int limit = s->max - 1; \
1268 const int max = limit - intensity; \
1269 const int mid = s->max / 2; \
1270 const int src_h = in->height; \
1271 const int src_w = in->width; \
1272 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \
1273 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \
1274 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \
1275 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \
1276 int x, y; \
1277 \
1278 if (column) { \
1279 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \
1280 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \
1281 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \
1282 \
1283 for (x = slicew_start; x < slicew_end; x++) { \
1284 const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; \
1285 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \
1286 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \
1287 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; \
1288 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1289 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1290 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \
1291 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data); \
1292 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \
1293 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data); \
1294 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \
1295 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); \
1296 \
1297 for (y = 0; y < src_h; y++) { \
1298 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \
1299 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \
1300 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \
1301 uint16_t *target; \
1302 \
1303 target = d0 + x + d0_signed_linesize * c0; \
1304 update16(target, max, intensity, limit); \
1305 \
1306 target = d1 + x + d1_signed_linesize * (c0 + c1); \
1307 update_cb(target, max, intensity, limit); \
1308 \
1309 target = d2 + x + d2_signed_linesize * (c0 + c2); \
1310 update_cr(target, max, intensity, limit); \
1311 \
1312 if (!c0_shift_h || (y & c0_shift_h)) \
1313 c0_data += c0_linesize; \
1314 if (!c1_shift_h || (y & c1_shift_h)) \
1315 c1_data += c1_linesize; \
1316 if (!c2_shift_h || (y & c2_shift_h)) \
1317 c2_data += c2_linesize; \
1318 d0_data += d0_linesize; \
1319 d1_data += d1_linesize; \
1320 d2_data += d2_linesize; \
1321 } \
1322 } \
1323 } else { \
1324 const uint16_t *c0_data = (uint16_t *)in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \
1325 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1326 const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1327 uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \
1328 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
1329 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
1330 \
1331 if (mirror) { \
1332 d0_data += s->size - 1; \
1333 d1_data += s->size - 1; \
1334 d2_data += s->size - 1; \
1335 } \
1336 \
1337 for (y = sliceh_start; y < sliceh_end; y++) { \
1338 for (x = 0; x < src_w; x++) { \
1339 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \
1340 const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \
1341 const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \
1342 uint16_t *target; \
1343 \
1344 if (mirror) { \
1345 target = d0_data - c0; \
1346 update16(target, max, intensity, limit); \
1347 target = d1_data - (c0 + c1); \
1348 update_cb(target, max, intensity, limit); \
1349 target = d2_data - (c0 + c2); \
1350 update_cr(target, max, intensity, limit); \
1351 } else { \
1352 target = d0_data + c0; \
1353 update16(target, max, intensity, limit); \
1354 target = d1_data + (c0 + c1); \
1355 update_cb(target, max, intensity, limit); \
1356 target = d2_data + (c0 + c2); \
1357 update_cr(target, max, intensity, limit); \
1358 } \
1359 } \
1360 \
1361 if (!c0_shift_h || (y & c0_shift_h)) \
1362 c0_data += c0_linesize; \
1363 if (!c1_shift_h || (y & c1_shift_h)) \
1364 c1_data += c1_linesize; \
1365 if (!c2_shift_h || (y & c2_shift_h)) \
1366 c2_data += c2_linesize; \
1367 d0_data += d0_linesize; \
1368 d1_data += d1_linesize; \
1369 d2_data += d2_linesize; \
1370 } \
1371 } \
1372 return 0; \
1373 }
1374
1375 #define AFLAT(name, update_cb, update_cr, column, mirror) \
1376 static int name(AVFilterContext *ctx, \
1377 void *arg, int jobnr, \
1378 int nb_jobs) \
1379 { \
1380 WaveformContext *s = ctx->priv; \
1381 ThreadData *td = arg; \
1382 AVFrame *in = td->in; \
1383 AVFrame *out = td->out; \
1384 int component = td->component; \
1385 int offset_y = td->offset_y; \
1386 int offset_x = td->offset_x; \
1387 const int src_h = in->height; \
1388 const int src_w = in->width; \
1389 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \
1390 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \
1391 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \
1392 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \
1393 const int intensity = s->intensity; \
1394 const int plane = s->desc->comp[component].plane; \
1395 const int c0_linesize = in->linesize[ plane + 0 ]; \
1396 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; \
1397 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; \
1398 const int c0_shift_w = s->shift_w[ component + 0 ]; \
1399 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \
1400 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \
1401 const int c0_shift_h = s->shift_h[ component + 0 ]; \
1402 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \
1403 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \
1404 const int d0_linesize = out->linesize[ plane + 0 ]; \
1405 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; \
1406 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; \
1407 const int max = 255 - intensity; \
1408 int x, y; \
1409 \
1410 if (column) { \
1411 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \
1412 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \
1413 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \
1414 \
1415 for (x = slicew_start; x < slicew_end; x++) { \
1416 const uint8_t *c0_data = in->data[plane + 0]; \
1417 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \
1418 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \
1419 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; \
1420 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \
1421 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \
1422 uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \
1423 uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data); \
1424 uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \
1425 uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data); \
1426 uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \
1427 uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); \
1428 \
1429 for (y = 0; y < src_h; y++) { \
1430 const int c0 = c0_data[x >> c0_shift_w] + 128; \
1431 const int c1 = c1_data[x >> c1_shift_w] - 128; \
1432 const int c2 = c2_data[x >> c2_shift_w] - 128; \
1433 uint8_t *target; \
1434 \
1435 target = d0 + x + d0_signed_linesize * c0; \
1436 update(target, max, intensity); \
1437 \
1438 target = d1 + x + d1_signed_linesize * (c0 + c1); \
1439 update_cb(target, max, intensity); \
1440 \
1441 target = d2 + x + d2_signed_linesize * (c0 + c2); \
1442 update_cr(target, max, intensity); \
1443 \
1444 if (!c0_shift_h || (y & c0_shift_h)) \
1445 c0_data += c0_linesize; \
1446 if (!c1_shift_h || (y & c1_shift_h)) \
1447 c1_data += c1_linesize; \
1448 if (!c2_shift_h || (y & c2_shift_h)) \
1449 c2_data += c2_linesize; \
1450 d0_data += d0_linesize; \
1451 d1_data += d1_linesize; \
1452 d2_data += d2_linesize; \
1453 } \
1454 } \
1455 } else { \
1456 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \
1457 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \
1458 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \
1459 uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \
1460 uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \
1461 uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \
1462 \
1463 if (mirror) { \
1464 d0_data += s->size - 1; \
1465 d1_data += s->size - 1; \
1466 d2_data += s->size - 1; \
1467 } \
1468 \
1469 for (y = sliceh_start; y < sliceh_end; y++) { \
1470 for (x = 0; x < src_w; x++) { \
1471 const int c0 = c0_data[x >> c0_shift_w] + 128; \
1472 const int c1 = c1_data[x >> c1_shift_w] - 128; \
1473 const int c2 = c2_data[x >> c2_shift_w] - 128; \
1474 uint8_t *target; \
1475 \
1476 if (mirror) { \
1477 target = d0_data - c0; \
1478 update(target, max, intensity); \
1479 target = d1_data - (c0 + c1); \
1480 update_cb(target, max, intensity); \
1481 target = d2_data - (c0 + c2); \
1482 update_cr(target, max, intensity); \
1483 } else { \
1484 target = d0_data + c0; \
1485 update(target, max, intensity); \
1486 target = d1_data + (c0 + c1); \
1487 update_cb(target, max, intensity); \
1488 target = d2_data + (c0 + c2); \
1489 update_cr(target, max, intensity); \
1490 } \
1491 } \
1492 \
1493 if (!c0_shift_h || (y & c0_shift_h)) \
1494 c0_data += c0_linesize; \
1495 if (!c1_shift_h || (y & c1_shift_h)) \
1496 c1_data += c1_linesize; \
1497 if (!c2_shift_h || (y & c2_shift_h)) \
1498 c2_data += c2_linesize; \
1499 d0_data += d0_linesize; \
1500 d1_data += d1_linesize; \
1501 d2_data += d2_linesize; \
1502 } \
1503 } \
1504 return 0; \
1505 }
1506
1507 AFLAT16(aflat16_row, update16, update16, 0, 0)
1508 AFLAT16(aflat16_row_mirror, update16, update16, 0, 1)
1509 AFLAT16(aflat16_column, update16, update16, 1, 0)
1510 AFLAT16(aflat16_column_mirror, update16, update16, 1, 1)
1511 AFLAT16(xflat16_row, update16, update16_cr, 0, 0)
1512 AFLAT16(xflat16_row_mirror, update16, update16_cr, 0, 1)
1513 AFLAT16(xflat16_column, update16, update16_cr, 1, 0)
1514 AFLAT16(xflat16_column_mirror, update16, update16_cr, 1, 1)
1515 AFLAT16(yflat16_row, update16_cr, update16_cr, 0, 0)
1516 AFLAT16(yflat16_row_mirror, update16_cr, update16_cr, 0, 1)
1517 AFLAT16(yflat16_column, update16_cr, update16_cr, 1, 0)
1518 AFLAT16(yflat16_column_mirror, update16_cr, update16_cr, 1, 1)
1519
1520 AFLAT(aflat_row, update, update, 0, 0)
1521 AFLAT(aflat_row_mirror, update, update, 0, 1)
1522 AFLAT(aflat_column, update, update, 1, 0)
1523 AFLAT(aflat_column_mirror, update, update, 1, 1)
1524 AFLAT(xflat_row, update, update_cr, 0, 0)
1525 AFLAT(xflat_row_mirror, update, update_cr, 0, 1)
1526 AFLAT(xflat_column, update, update_cr, 1, 0)
1527 AFLAT(xflat_column_mirror, update, update_cr, 1, 1)
1528 AFLAT(yflat_row, update_cr, update_cr, 0, 0)
1529 AFLAT(yflat_row_mirror, update_cr, update_cr, 0, 1)
1530 AFLAT(yflat_column, update_cr, update_cr, 1, 0)
1531 AFLAT(yflat_column_mirror, update_cr, update_cr, 1, 1)
1532
1533 static av_always_inline void chroma16(WaveformContext *s,
1534 AVFrame *in, AVFrame *out,
1535 int component, int intensity,
1536 int offset_y, int offset_x,
1537 int column, int mirror,
1538 int jobnr, int nb_jobs)
1539 {
1540 const int plane = s->desc->comp[component].plane;
1541 const int c0_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1542 const int c1_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1543 const int dst_linesize = out->linesize[plane] / 2;
1544 const int limit = s->max - 1;
1545 const int max = limit - intensity;
1546 const int mid = s->max / 2;
1547 const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1548 const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1549 const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1550 const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1551 const int src_h = in->height;
1552 const int src_w = in->width;
1553 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1554 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1555 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1556 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1557 int x, y;
1558
1559 if (column) {
1560 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1561
1562 for (x = slicew_start; x < slicew_end; x++) {
1563 const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp];
1564 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp];
1565 uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x;
1566 uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1567 uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1568 uint16_t *dst = dst_line;
1569
1570 for (y = 0; y < src_h; y++) {
1571 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1572 uint16_t *target;
1573
1574 target = dst + x + dst_signed_linesize * sum;
1575 update16(target, max, intensity, limit);
1576
1577 if (!c0_shift_h || (y & c0_shift_h))
1578 c0_data += c0_linesize;
1579 if (!c1_shift_h || (y & c1_shift_h))
1580 c1_data += c1_linesize;
1581 dst_data += dst_linesize;
1582 }
1583 }
1584 } else {
1585 const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1586 const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1587 uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1588
1589 if (mirror)
1590 dst_data += s->size - 1;
1591 for (y = sliceh_start; y < sliceh_end; y++) {
1592 for (x = 0; x < src_w; x++) {
1593 const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit);
1594 uint16_t *target;
1595
1596 if (mirror) {
1597 target = dst_data - sum;
1598 update16(target, max, intensity, limit);
1599 } else {
1600 target = dst_data + sum;
1601 update16(target, max, intensity, limit);
1602 }
1603 }
1604
1605 if (!c0_shift_h || (y & c0_shift_h))
1606 c0_data += c0_linesize;
1607 if (!c1_shift_h || (y & c1_shift_h))
1608 c1_data += c1_linesize;
1609 dst_data += dst_linesize;
1610 }
1611 }
1612 }
1613
1614 #define CHROMA16_FUNC(name, column, mirror) \
1615 static int chroma16_##name(AVFilterContext *ctx, \
1616 void *arg, int jobnr, \
1617 int nb_jobs) \
1618 { \
1619 WaveformContext *s = ctx->priv; \
1620 ThreadData *td = arg; \
1621 AVFrame *in = td->in; \
1622 AVFrame *out = td->out; \
1623 int component = td->component; \
1624 int offset_y = td->offset_y; \
1625 int offset_x = td->offset_x; \
1626 \
1627 chroma16(s, in, out, component, s->intensity,\
1628 offset_y, offset_x, column, mirror, \
1629 jobnr, nb_jobs); \
1630 \
1631 return 0; \
1632 }
1633
1634 CHROMA16_FUNC(column_mirror, 1, 1)
1635 CHROMA16_FUNC(column, 1, 0)
1636 CHROMA16_FUNC(row_mirror, 0, 1)
1637 CHROMA16_FUNC(row, 0, 0)
1638
1639 static av_always_inline void chroma(WaveformContext *s,
1640 AVFrame *in, AVFrame *out,
1641 int component, int intensity,
1642 int offset_y, int offset_x,
1643 int column, int mirror,
1644 int jobnr, int nb_jobs)
1645 {
1646 const int plane = s->desc->comp[component].plane;
1647 const int src_h = in->height;
1648 const int src_w = in->width;
1649 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1650 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1651 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1652 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1653 const int c0_linesize = in->linesize[(plane + 1) % s->ncomp];
1654 const int c1_linesize = in->linesize[(plane + 2) % s->ncomp];
1655 const int dst_linesize = out->linesize[plane];
1656 const int max = 255 - intensity;
1657 const int c0_shift_w = s->shift_w[(component + 1) % s->ncomp];
1658 const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp];
1659 const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp];
1660 const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp];
1661 int x, y;
1662
1663 if (column) {
1664 const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1);
1665
1666 for (x = slicew_start; x < slicew_end; x++) {
1667 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp];
1668 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp];
1669 uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x;
1670 uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1);
1671 uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data);
1672 uint8_t *dst = dst_line;
1673
1674 for (y = 0; y < src_h; y++) {
1675 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1676 uint8_t *target;
1677
1678 target = dst + x + dst_signed_linesize * sum;
1679 update(target, max, intensity);
1680
1681 if (!c0_shift_h || (y & c0_shift_h))
1682 c0_data += c0_linesize;
1683 if (!c1_shift_h || (y & c1_shift_h))
1684 c1_data += c1_linesize;
1685 dst_data += dst_linesize;
1686 }
1687 }
1688 } else {
1689 const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize;
1690 const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1691 uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x;
1692
1693 if (mirror)
1694 dst_data += s->size - 1;
1695 for (y = sliceh_start; y < sliceh_end; y++) {
1696 for (x = 0; x < src_w; x++) {
1697 const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127);
1698 uint8_t *target;
1699
1700 if (mirror) {
1701 target = dst_data - sum;
1702 update(target, max, intensity);
1703 } else {
1704 target = dst_data + sum;
1705 update(target, max, intensity);
1706 }
1707 }
1708
1709 if (!c0_shift_h || (y & c0_shift_h))
1710 c0_data += c0_linesize;
1711 if (!c1_shift_h || (y & c1_shift_h))
1712 c1_data += c1_linesize;
1713 dst_data += dst_linesize;
1714 }
1715 }
1716 }
1717
1718 #define CHROMA_FUNC(name, column, mirror) \
1719 static int chroma_##name(AVFilterContext *ctx, \
1720 void *arg, int jobnr, \
1721 int nb_jobs) \
1722 { \
1723 WaveformContext *s = ctx->priv; \
1724 ThreadData *td = arg; \
1725 AVFrame *in = td->in; \
1726 AVFrame *out = td->out; \
1727 int component = td->component; \
1728 int offset_y = td->offset_y; \
1729 int offset_x = td->offset_x; \
1730 \
1731 chroma(s, in, out, component, s->intensity, \
1732 offset_y, offset_x, column, mirror, \
1733 jobnr, nb_jobs); \
1734 \
1735 return 0; \
1736 }
1737
1738 CHROMA_FUNC(column_mirror, 1, 1)
1739 CHROMA_FUNC(column, 1, 0)
1740 CHROMA_FUNC(row_mirror, 0, 1)
1741 CHROMA_FUNC(row, 0, 0)
1742
1743 static av_always_inline void color16(WaveformContext *s,
1744 AVFrame *in, AVFrame *out,
1745 int component, int intensity,
1746 int offset_y, int offset_x,
1747 int column, int mirror,
1748 int jobnr, int nb_jobs)
1749 {
1750 const int plane = s->desc->comp[component].plane;
1751 const int limit = s->max - 1;
1752 const int src_h = in->height;
1753 const int src_w = in->width;
1754 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1755 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1756 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1757 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1758 const int c0_linesize = in->linesize[ plane + 0 ] / 2;
1759 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2;
1760 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2;
1761 const int c0_shift_h = s->shift_h[ component + 0 ];
1762 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1763 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1764 const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize;
1765 const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1766 const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1767 const int d0_linesize = out->linesize[ plane + 0 ] / 2;
1768 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2;
1769 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2;
1770 const int c0_shift_w = s->shift_w[ component + 0 ];
1771 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1772 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1773 int x, y;
1774
1775 if (column) {
1776 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1777 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1778 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1779 uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x;
1780 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x;
1781 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x;
1782 uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1);
1783 uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data);
1784 uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1);
1785 uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data);
1786 uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1);
1787 uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data);
1788
1789 for (y = 0; y < src_h; y++) {
1790 for (x = slicew_start; x < slicew_end; x++) {
1791 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1792 const int c1 = c1_data[x >> c1_shift_w];
1793 const int c2 = c2_data[x >> c2_shift_w];
1794
1795 *(d0 + d0_signed_linesize * c0 + x) = c0;
1796 *(d1 + d1_signed_linesize * c0 + x) = c1;
1797 *(d2 + d2_signed_linesize * c0 + x) = c2;
1798 }
1799
1800 if (!c0_shift_h || (y & c0_shift_h))
1801 c0_data += c0_linesize;
1802 if (!c1_shift_h || (y & c1_shift_h))
1803 c1_data += c1_linesize;
1804 if (!c2_shift_h || (y & c2_shift_h))
1805 c2_data += c2_linesize;
1806 d0_data += d0_linesize;
1807 d1_data += d1_linesize;
1808 d2_data += d2_linesize;
1809 }
1810 } else {
1811 uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x;
1812 uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x;
1813 uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x;
1814
1815 if (mirror) {
1816 d0_data += s->size - 1;
1817 d1_data += s->size - 1;
1818 d2_data += s->size - 1;
1819 }
1820
1821 for (y = sliceh_start; y < sliceh_end; y++) {
1822 for (x = 0; x < src_w; x++) {
1823 const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit);
1824 const int c1 = c1_data[x >> c1_shift_w];
1825 const int c2 = c2_data[x >> c2_shift_w];
1826
1827 if (mirror) {
1828 *(d0_data - c0) = c0;
1829 *(d1_data - c0) = c1;
1830 *(d2_data - c0) = c2;
1831 } else {
1832 *(d0_data + c0) = c0;
1833 *(d1_data + c0) = c1;
1834 *(d2_data + c0) = c2;
1835 }
1836 }
1837
1838 if (!c0_shift_h || (y & c0_shift_h))
1839 c0_data += c0_linesize;
1840 if (!c1_shift_h || (y & c1_shift_h))
1841 c1_data += c1_linesize;
1842 if (!c2_shift_h || (y & c2_shift_h))
1843 c2_data += c2_linesize;
1844 d0_data += d0_linesize;
1845 d1_data += d1_linesize;
1846 d2_data += d2_linesize;
1847 }
1848 }
1849 }
1850
1851 #define COLOR16_FUNC(name, column, mirror) \
1852 static int color16_##name(AVFilterContext *ctx, \
1853 void *arg, int jobnr, \
1854 int nb_jobs) \
1855 { \
1856 WaveformContext *s = ctx->priv; \
1857 ThreadData *td = arg; \
1858 AVFrame *in = td->in; \
1859 AVFrame *out = td->out; \
1860 int component = td->component; \
1861 int offset_y = td->offset_y; \
1862 int offset_x = td->offset_x; \
1863 \
1864 color16(s, in, out, component, s->intensity, \
1865 offset_y, offset_x, column, mirror, \
1866 jobnr, nb_jobs); \
1867 \
1868 return 0; \
1869 }
1870
1871 COLOR16_FUNC(column_mirror, 1, 1)
1872 COLOR16_FUNC(column, 1, 0)
1873 COLOR16_FUNC(row_mirror, 0, 1)
1874 COLOR16_FUNC(row, 0, 0)
1875
1876 static av_always_inline void color(WaveformContext *s,
1877 AVFrame *in, AVFrame *out,
1878 int component, int intensity,
1879 int offset_y, int offset_x,
1880 int column, int mirror,
1881 int jobnr, int nb_jobs)
1882 {
1883 const int plane = s->desc->comp[component].plane;
1884 const int src_h = in->height;
1885 const int src_w = in->width;
1886 const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0;
1887 const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h;
1888 const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0;
1889 const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w;
1890 const int c0_linesize = in->linesize[ plane + 0 ];
1891 const int c1_linesize = in->linesize[(plane + 1) % s->ncomp];
1892 const int c2_linesize = in->linesize[(plane + 2) % s->ncomp];
1893 const int c0_shift_h = s->shift_h[ component + 0 ];
1894 const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp];
1895 const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp];
1896 const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize;
1897 const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize;
1898 const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize;
1899 const int d0_linesize = out->linesize[ plane + 0 ];
1900 const int d1_linesize = out->linesize[(plane + 1) % s->ncomp];
1901 const int d2_linesize = out->linesize[(plane + 2) % s->ncomp];
1902 const int c0_shift_w = s->shift_w[ component + 0 ];
1903 const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp];
1904 const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp];
1905 int x, y;
1906
1907 if (column) {
1908 const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1);
1909 const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1);
1910 const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1);
1911 uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x;
1912