FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops.c
Date: 2026-04-19 20:43:40
Exec Total Coverage
Lines: 593 682 87.0%
Functions: 36 38 94.7%
Branches: 373 447 83.4%

Line Branch Exec Source
1 /**
2 * Copyright (C) 2025 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/avassert.h"
22 #include "libavutil/avstring.h"
23 #include "libavutil/bprint.h"
24 #include "libavutil/bswap.h"
25 #include "libavutil/mem.h"
26 #include "libavutil/rational.h"
27 #include "libavutil/refstruct.h"
28
29 #include "format.h"
30 #include "ops.h"
31 #include "ops_internal.h"
32
33 extern const SwsOpBackend backend_c;
34 extern const SwsOpBackend backend_murder;
35 extern const SwsOpBackend backend_aarch64;
36 extern const SwsOpBackend backend_x86;
37 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
38 extern const SwsOpBackend backend_spirv;
39 #endif
40 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
41 extern const SwsOpBackend backend_glsl;
42 #endif
43
44 const SwsOpBackend * const ff_sws_op_backends[] = {
45 &backend_murder,
46 #if ARCH_AARCH64 && HAVE_NEON
47 &backend_aarch64,
48 #elif ARCH_X86_64 && HAVE_X86ASM
49 &backend_x86,
50 #endif
51 &backend_c,
52 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
53 &backend_spirv,
54 #endif
55 #if CONFIG_LIBSHADERC || CONFIG_LIBGLSLANG
56 &backend_glsl,
57 #endif
58 NULL
59 };
60
61 796304 const char *ff_sws_pixel_type_name(SwsPixelType type)
62 {
63
4/7
✓ Branch 0 taken 109197 times.
✓ Branch 1 taken 303029 times.
✓ Branch 2 taken 21944 times.
✓ Branch 3 taken 362134 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
796304 switch (type) {
64 109197 case SWS_PIXEL_U8: return "u8";
65 303029 case SWS_PIXEL_U16: return "u16";
66 21944 case SWS_PIXEL_U32: return "u32";
67 362134 case SWS_PIXEL_F32: return "f32";
68 case SWS_PIXEL_NONE: return "none";
69 case SWS_PIXEL_TYPE_NB: break;
70 }
71
72 av_unreachable("Invalid pixel type!");
73 return "ERR";
74 }
75
76 6631077 int ff_sws_pixel_type_size(SwsPixelType type)
77 {
78
4/7
✓ Branch 0 taken 2568332 times.
✓ Branch 1 taken 1927895 times.
✓ Branch 2 taken 762299 times.
✓ Branch 3 taken 1372551 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
6631077 switch (type) {
79 2568332 case SWS_PIXEL_U8: return sizeof(uint8_t);
80 1927895 case SWS_PIXEL_U16: return sizeof(uint16_t);
81 762299 case SWS_PIXEL_U32: return sizeof(uint32_t);
82 1372551 case SWS_PIXEL_F32: return sizeof(float);
83 case SWS_PIXEL_NONE: break;
84 case SWS_PIXEL_TYPE_NB: break;
85 }
86
87 av_unreachable("Invalid pixel type!");
88 return 0;
89 }
90
91 7093436 bool ff_sws_pixel_type_is_int(SwsPixelType type)
92 {
93
2/4
✓ Branch 0 taken 3242753 times.
✓ Branch 1 taken 3850683 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7093436 switch (type) {
94 3242753 case SWS_PIXEL_U8:
95 case SWS_PIXEL_U16:
96 case SWS_PIXEL_U32:
97 3242753 return true;
98 3850683 case SWS_PIXEL_F32:
99 3850683 return false;
100 case SWS_PIXEL_NONE:
101 case SWS_PIXEL_TYPE_NB: break;
102 }
103
104 av_unreachable("Invalid pixel type!");
105 return false;
106 }
107
108 574122 const char *ff_sws_op_type_name(SwsOpType op)
109 {
110
15/20
✓ Branch 0 taken 60136 times.
✓ Branch 1 taken 60136 times.
✓ Branch 2 taken 44308 times.
✓ Branch 3 taken 59599 times.
✓ Branch 4 taken 10514 times.
✓ Branch 5 taken 10514 times.
✓ Branch 6 taken 6032 times.
✓ Branch 7 taken 4890 times.
✓ Branch 8 taken 30947 times.
✓ Branch 9 taken 110748 times.
✓ Branch 10 taken 37033 times.
✓ Branch 11 taken 25415 times.
✓ Branch 12 taken 12952 times.
✓ Branch 13 taken 70280 times.
✓ Branch 14 taken 30618 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
574122 switch (op) {
111 60136 case SWS_OP_READ: return "SWS_OP_READ";
112 60136 case SWS_OP_WRITE: return "SWS_OP_WRITE";
113 44308 case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
114 59599 case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
115 10514 case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
116 10514 case SWS_OP_PACK: return "SWS_OP_PACK";
117 6032 case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
118 4890 case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
119 30947 case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
120 110748 case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
121 37033 case SWS_OP_MIN: return "SWS_OP_MIN";
122 25415 case SWS_OP_MAX: return "SWS_OP_MAX";
123 12952 case SWS_OP_SCALE: return "SWS_OP_SCALE";
124 70280 case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
125 30618 case SWS_OP_DITHER: return "SWS_OP_DITHER";
126 case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
127 case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
128 case SWS_OP_INVALID: return "SWS_OP_INVALID";
129 case SWS_OP_TYPE_NB: break;
130 }
131
132 av_unreachable("Invalid operation type!");
133 return "ERR";
134 }
135
136 1211084 SwsCompMask ff_sws_comp_mask_q4(const AVRational q[4])
137 {
138 1211084 SwsCompMask mask = 0;
139
2/2
✓ Branch 0 taken 4844336 times.
✓ Branch 1 taken 1211084 times.
6055420 for (int i = 0; i < 4; i++) {
140
2/2
✓ Branch 0 taken 2434953 times.
✓ Branch 1 taken 2409383 times.
4844336 if (q[i].den)
141 2434953 mask |= SWS_COMP(i);
142 }
143 1211084 return mask;
144 }
145
146 6532 SwsCompMask ff_sws_comp_mask_swizzle(const SwsCompMask mask, const SwsSwizzleOp swiz)
147 {
148 6532 SwsCompMask res = 0;
149
2/2
✓ Branch 0 taken 26128 times.
✓ Branch 1 taken 6532 times.
32660 for (int i = 0; i < 4; i++) {
150 26128 const int src = swiz.in[i];
151
2/2
✓ Branch 0 taken 7496 times.
✓ Branch 1 taken 18632 times.
26128 if (SWS_COMP_TEST(mask, src))
152 7496 res |= SWS_COMP(i);
153 }
154
155 6532 return res;
156 }
157
158 3044928 SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
159 {
160 3044928 SwsCompMask mask = 0;
161
2/2
✓ Branch 0 taken 12179712 times.
✓ Branch 1 taken 3044928 times.
15224640 for (int i = 0; i < 4; i++) {
162
2/2
✓ Branch 0 taken 8035382 times.
✓ Branch 1 taken 4144330 times.
12179712 if (SWS_OP_NEEDED(op, i))
163 8035382 mask |= SWS_COMP(i);
164 }
165 3044928 return mask;
166 }
167
168 /* biased towards `a` */
169 2744080 static AVRational av_min_q(AVRational a, AVRational b)
170 {
171
2/2
✓ Branch 1 taken 586324 times.
✓ Branch 2 taken 2157756 times.
2744080 return av_cmp_q(a, b) == 1 ? b : a;
172 }
173
174 2231768 static AVRational av_max_q(AVRational a, AVRational b)
175 {
176
2/2
✓ Branch 1 taken 253674 times.
✓ Branch 2 taken 1978094 times.
2231768 return av_cmp_q(a, b) == -1 ? b : a;
177 }
178
179 6353786 void ff_sws_apply_op_q(const SwsOp *op, AVRational x[4])
180 {
181 uint64_t mask[4];
182 int shift[4];
183
184
12/16
✓ Branch 0 taken 969610 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 157504 times.
✓ Branch 3 taken 2920 times.
✓ Branch 4 taken 503046 times.
✓ Branch 5 taken 84740 times.
✓ Branch 6 taken 76426 times.
✓ Branch 7 taken 1220954 times.
✓ Branch 8 taken 1896204 times.
✓ Branch 9 taken 3742 times.
✓ Branch 10 taken 686020 times.
✓ Branch 11 taken 557942 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 194678 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
6353786 switch (op->op) {
185 969610 case SWS_OP_READ:
186 case SWS_OP_WRITE:
187 969610 return;
188 case SWS_OP_UNPACK: {
189 av_assert1(ff_sws_pixel_type_is_int(op->type));
190 ff_sws_pack_op_decode(op, mask, shift);
191 unsigned val = x[0].num;
192 for (int i = 0; i < 4; i++)
193 x[i] = Q((val >> shift[i]) & mask[i]);
194 return;
195 }
196 157504 case SWS_OP_PACK: {
197 av_assert1(ff_sws_pixel_type_is_int(op->type));
198 157504 ff_sws_pack_op_decode(op, mask, shift);
199 157504 unsigned val = 0;
200
2/2
✓ Branch 0 taken 630016 times.
✓ Branch 1 taken 157504 times.
787520 for (int i = 0; i < 4; i++)
201 630016 val |= (x[i].num & mask[i]) << shift[i];
202 157504 x[0] = Q(val);
203 157504 return;
204 }
205 2920 case SWS_OP_SWAP_BYTES:
206 av_assert1(ff_sws_pixel_type_is_int(op->type));
207
1/3
✓ Branch 0 taken 2920 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
2920 switch (ff_sws_pixel_type_size(op->type)) {
208 2920 case 2:
209
2/2
✓ Branch 0 taken 11680 times.
✓ Branch 1 taken 2920 times.
14600 for (int i = 0; i < 4; i++)
210 11680 x[i].num = av_bswap16(x[i].num);
211 2920 break;
212 case 4:
213 for (int i = 0; i < 4; i++)
214 x[i].num = av_bswap32(x[i].num);
215 break;
216 }
217 2920 return;
218 503046 case SWS_OP_CLEAR:
219
2/2
✓ Branch 0 taken 2012184 times.
✓ Branch 1 taken 503046 times.
2515230 for (int i = 0; i < 4; i++) {
220
2/2
✓ Branch 0 taken 607444 times.
✓ Branch 1 taken 1404740 times.
2012184 if (SWS_COMP_TEST(op->clear.mask, i))
221 607444 x[i] = op->clear.value[i];
222 }
223 503046 return;
224 84740 case SWS_OP_LSHIFT: {
225 av_assert1(ff_sws_pixel_type_is_int(op->type));
226 84740 AVRational mult = Q(1 << op->shift.amount);
227
2/2
✓ Branch 0 taken 338960 times.
✓ Branch 1 taken 84740 times.
423700 for (int i = 0; i < 4; i++)
228
2/2
✓ Branch 0 taken 286386 times.
✓ Branch 1 taken 52574 times.
338960 x[i] = x[i].den ? av_mul_q(x[i], mult) : x[i];
229 84740 return;
230 }
231 76426 case SWS_OP_RSHIFT: {
232 av_assert1(ff_sws_pixel_type_is_int(op->type));
233
2/2
✓ Branch 0 taken 305704 times.
✓ Branch 1 taken 76426 times.
382130 for (int i = 0; i < 4; i++)
234
2/2
✓ Branch 0 taken 222878 times.
✓ Branch 1 taken 82826 times.
305704 x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
235 76426 return;
236 }
237 1220954 case SWS_OP_SWIZZLE: {
238 1220954 const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
239
2/2
✓ Branch 0 taken 4883816 times.
✓ Branch 1 taken 1220954 times.
6104770 for (int i = 0; i < 4; i++)
240 4883816 x[i] = orig[op->swizzle.in[i]];
241 1220954 return;
242 }
243 1896204 case SWS_OP_CONVERT:
244
2/2
✓ Branch 0 taken 1048098 times.
✓ Branch 1 taken 848106 times.
1896204 if (ff_sws_pixel_type_is_int(op->convert.to)) {
245 1048098 const AVRational scale = ff_sws_pixel_expand(op->type, op->convert.to);
246
2/2
✓ Branch 0 taken 4192392 times.
✓ Branch 1 taken 1048098 times.
5240490 for (int i = 0; i < 4; i++) {
247
2/2
✓ Branch 0 taken 3700161 times.
✓ Branch 1 taken 492231 times.
4192392 x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
248
2/2
✓ Branch 0 taken 10208 times.
✓ Branch 1 taken 4182184 times.
4192392 if (op->convert.expand)
249 10208 x[i] = av_mul_q(x[i], scale);
250 }
251 }
252 1896204 return;
253 3742 case SWS_OP_DITHER:
254 av_assert1(!ff_sws_pixel_type_is_int(op->type));
255
2/2
✓ Branch 0 taken 14968 times.
✓ Branch 1 taken 3742 times.
18710 for (int i = 0; i < 4; i++) {
256
3/4
✓ Branch 0 taken 9428 times.
✓ Branch 1 taken 5540 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9428 times.
14968 if (op->dither.y_offset[i] >= 0 && x[i].den)
257 x[i] = av_add_q(x[i], av_make_q(1, 2));
258 }
259 3742 return;
260 686020 case SWS_OP_MIN:
261
2/2
✓ Branch 0 taken 2744080 times.
✓ Branch 1 taken 686020 times.
3430100 for (int i = 0; i < 4; i++)
262 2744080 x[i] = av_min_q(x[i], op->clamp.limit[i]);
263 686020 return;
264 557942 case SWS_OP_MAX:
265
2/2
✓ Branch 0 taken 2231768 times.
✓ Branch 1 taken 557942 times.
2789710 for (int i = 0; i < 4; i++)
266 2231768 x[i] = av_max_q(x[i], op->clamp.limit[i]);
267 557942 return;
268 case SWS_OP_LINEAR: {
269 av_assert1(!ff_sws_pixel_type_is_int(op->type));
270 const AVRational orig[4] = { x[0], x[1], x[2], x[3] };
271 for (int i = 0; i < 4; i++) {
272 AVRational sum = op->lin.m[i][4];
273 for (int j = 0; j < 4; j++)
274 sum = av_add_q(sum, av_mul_q(orig[j], op->lin.m[i][j]));
275 x[i] = sum;
276 }
277 return;
278 }
279 194678 case SWS_OP_SCALE:
280
2/2
✓ Branch 0 taken 778712 times.
✓ Branch 1 taken 194678 times.
973390 for (int i = 0; i < 4; i++)
281
2/2
✓ Branch 0 taken 529640 times.
✓ Branch 1 taken 249072 times.
778712 x[i] = x[i].den ? av_mul_q(x[i], op->scale.factor) : x[i];
282 194678 return;
283 case SWS_OP_FILTER_H:
284 case SWS_OP_FILTER_V:
285 /* Filters have normalized energy by definition, so they don't
286 * conceptually modify individual components */
287 return;
288 }
289
290 av_unreachable("Invalid operation type!");
291 }
292
293 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
294 enum {
295 SWS_COMP_IDENTITY = SWS_COMP_ZERO | SWS_COMP_EXACT,
296 };
297
298 3444426 static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
299 {
300 3444426 const SwsCompFlags flags_or = SWS_COMP_GARBAGE;
301 3444426 const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
302 3444426 return ((a & b) & flags_and) | ((a | b) & flags_or);
303 }
304
305 /* Linearly propagate flags per component */
306 1184851 static void propagate_flags(SwsOp *op, const SwsComps *prev)
307 {
308
2/2
✓ Branch 0 taken 4739404 times.
✓ Branch 1 taken 1184851 times.
5924255 for (int i = 0; i < 4; i++)
309 4739404 op->comps.flags[i] = prev->flags[i];
310 1184851 }
311
312 /* Clear undefined values in dst with src */
313 619577 static void clear_undefined_values(AVRational dst[4], const AVRational src[4])
314 {
315
2/2
✓ Branch 0 taken 2478308 times.
✓ Branch 1 taken 619577 times.
3097885 for (int i = 0; i < 4; i++) {
316
2/2
✓ Branch 0 taken 547245 times.
✓ Branch 1 taken 1931063 times.
2478308 if (dst[i].den == 0)
317 547245 dst[i] = src[i];
318 }
319 619577 }
320
321 16128 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
322 const SwsFilterWeights *weights)
323 {
324 16128 const AVRational posw = { weights->sum_positive, SWS_FILTER_SCALE };
325 16128 const AVRational negw = { weights->sum_negative, SWS_FILTER_SCALE };
326
2/2
✓ Branch 0 taken 64512 times.
✓ Branch 1 taken 16128 times.
80640 for (int i = 0; i < 4; i++) {
327 64512 comps->flags[i] = prev->flags[i];
328 /* Only point sampling preserves exactness */
329
2/2
✓ Branch 0 taken 26880 times.
✓ Branch 1 taken 37632 times.
64512 if (weights->filter_size != 1)
330 26880 comps->flags[i] &= ~SWS_COMP_EXACT;
331 /* Update min/max assuming extremes */
332 64512 comps->min[i] = av_add_q(av_mul_q(prev->min[i], posw),
333 av_mul_q(prev->max[i], negw));
334 64512 comps->max[i] = av_add_q(av_mul_q(prev->min[i], negw),
335 av_mul_q(prev->max[i], posw));
336 }
337 16128 }
338
339 /* Infer + propagate known information about components */
340 484805 void ff_sws_op_list_update_comps(SwsOpList *ops)
341 {
342 484805 SwsComps prev = { .flags = {
343 SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE,
344 }};
345
346 /* Forwards pass, propagates knowledge about the incoming pixel values */
347
2/2
✓ Branch 0 taken 4841896 times.
✓ Branch 1 taken 484805 times.
5326701 for (int n = 0; n < ops->num_ops; n++) {
348 4841896 SwsOp *op = &ops->ops[n];
349
350
2/2
✓ Branch 0 taken 1678678 times.
✓ Branch 1 taken 3163218 times.
4841896 switch (op->op) {
351 1678678 case SWS_OP_READ:
352 case SWS_OP_LINEAR:
353 case SWS_OP_DITHER:
354 case SWS_OP_SWAP_BYTES:
355 case SWS_OP_UNPACK:
356 case SWS_OP_FILTER_H:
357 case SWS_OP_FILTER_V:
358 1678678 break; /* special cases, handled below */
359 3163218 default:
360 3163218 memcpy(op->comps.min, prev.min, sizeof(prev.min));
361 3163218 memcpy(op->comps.max, prev.max, sizeof(prev.max));
362 3163218 ff_sws_apply_op_q(op, op->comps.min);
363 3163218 ff_sws_apply_op_q(op, op->comps.max);
364 3163218 break;
365 }
366
367
14/16
✓ Branch 0 taken 484805 times.
✓ Branch 1 taken 337163 times.
✓ Branch 2 taken 484805 times.
✓ Branch 3 taken 80469 times.
✓ Branch 4 taken 341465 times.
✓ Branch 5 taken 278112 times.
✓ Branch 6 taken 239899 times.
✓ Branch 7 taken 83464 times.
✓ Branch 8 taken 78752 times.
✓ Branch 9 taken 251523 times.
✓ Branch 10 taken 607211 times.
✓ Branch 11 taken 943542 times.
✓ Branch 12 taken 533347 times.
✓ Branch 13 taken 97339 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4841896 switch (op->op) {
368 484805 case SWS_OP_READ:
369 /* Active components are taken from the user-provided values,
370 * other components are explicitly stripped */
371
2/2
✓ Branch 0 taken 1218257 times.
✓ Branch 1 taken 484805 times.
1703062 for (int i = 0; i < op->rw.elems; i++) {
372
2/2
✓ Branch 0 taken 491024 times.
✓ Branch 1 taken 727233 times.
1218257 const int idx = op->rw.packed ? i : ops->plane_src[i];
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1218257 times.
1218257 av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
374 1218257 op->comps.flags[i] = ops->comps_src.flags[idx];
375 1218257 op->comps.min[i] = ops->comps_src.min[idx];
376 1218257 op->comps.max[i] = ops->comps_src.max[idx];
377 }
378
2/2
✓ Branch 0 taken 720963 times.
✓ Branch 1 taken 484805 times.
1205768 for (int i = op->rw.elems; i < 4; i++) {
379 720963 op->comps.flags[i] = prev.flags[i];
380 720963 op->comps.min[i] = prev.min[i];
381 720963 op->comps.max[i] = prev.max[i];
382 }
383
384
2/2
✓ Branch 0 taken 16128 times.
✓ Branch 1 taken 468677 times.
484805 if (op->rw.filter) {
385 16128 const SwsComps prev = op->comps;
386 16128 apply_filter_weights(&op->comps, &prev, op->rw.kernel);
387 }
388 484805 break;
389 337163 case SWS_OP_SWAP_BYTES:
390
2/2
✓ Branch 0 taken 1348652 times.
✓ Branch 1 taken 337163 times.
1685815 for (int i = 0; i < 4; i++) {
391 1348652 op->comps.flags[i] = prev.flags[i] ^ SWS_COMP_SWAPPED;
392 1348652 op->comps.min[i] = prev.min[i];
393 1348652 op->comps.max[i] = prev.max[i];
394 }
395 337163 break;
396 484805 case SWS_OP_WRITE:
397
2/2
✓ Branch 0 taken 1342195 times.
✓ Branch 1 taken 484805 times.
1827000 for (int i = 0; i < op->rw.elems; i++)
398 av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
399 /* fall through */
400 case SWS_OP_LSHIFT:
401 case SWS_OP_RSHIFT:
402 565274 propagate_flags(op, &prev);
403 565274 break;
404 341465 case SWS_OP_MIN:
405 341465 propagate_flags(op, &prev);
406 341465 clear_undefined_values(op->comps.max, op->clamp.limit);
407 341465 break;
408 278112 case SWS_OP_MAX:
409 278112 propagate_flags(op, &prev);
410 278112 clear_undefined_values(op->comps.min, op->clamp.limit);
411 278112 break;
412 239899 case SWS_OP_DITHER:
413
2/2
✓ Branch 0 taken 959596 times.
✓ Branch 1 taken 239899 times.
1199495 for (int i = 0; i < 4; i++) {
414 959596 op->comps.min[i] = prev.min[i];
415 959596 op->comps.max[i] = prev.max[i];
416
2/2
✓ Branch 0 taken 162421 times.
✓ Branch 1 taken 797175 times.
959596 if (op->dither.y_offset[i] < 0)
417 162421 continue;
418 /* Strip zero flag because of the nonzero dithering offset */
419 797175 op->comps.flags[i] = prev.flags[i] & ~SWS_COMP_ZERO;
420 797175 op->comps.min[i] = av_add_q(op->comps.min[i], op->dither.min);
421 797175 op->comps.max[i] = av_add_q(op->comps.max[i], op->dither.max);
422 }
423 239899 break;
424 83464 case SWS_OP_UNPACK:
425
2/2
✓ Branch 0 taken 333856 times.
✓ Branch 1 taken 83464 times.
417320 for (int i = 0; i < 4; i++) {
426 333856 const int pattern = op->pack.pattern[i];
427
2/2
✓ Branch 0 taken 273516 times.
✓ Branch 1 taken 60340 times.
333856 if (pattern) {
428 av_assert1(pattern < 32);
429 273516 op->comps.flags[i] = prev.flags[0];
430 273516 op->comps.min[i] = Q(0);
431 273516 op->comps.max[i] = Q((1ULL << pattern) - 1);
432 } else
433 60340 op->comps.flags[i] = SWS_COMP_GARBAGE;
434 }
435 83464 break;
436 78752 case SWS_OP_PACK: {
437 78752 SwsCompFlags flags = SWS_COMP_IDENTITY;
438
2/2
✓ Branch 0 taken 315008 times.
✓ Branch 1 taken 78752 times.
393760 for (int i = 0; i < 4; i++) {
439
2/2
✓ Branch 0 taken 261916 times.
✓ Branch 1 taken 53092 times.
315008 if (op->pack.pattern[i])
440 261916 flags = merge_comp_flags(flags, prev.flags[i]);
441
2/2
✓ Branch 0 taken 236256 times.
✓ Branch 1 taken 78752 times.
315008 if (i > 0) /* clear remaining comps for sanity */
442 236256 op->comps.flags[i] = SWS_COMP_GARBAGE;
443 }
444 78752 op->comps.flags[0] = flags;
445 78752 break;
446 }
447 251523 case SWS_OP_CLEAR:
448
2/2
✓ Branch 0 taken 1006092 times.
✓ Branch 1 taken 251523 times.
1257615 for (int i = 0; i < 4; i++) {
449
2/2
✓ Branch 0 taken 303722 times.
✓ Branch 1 taken 702370 times.
1006092 if (SWS_COMP_TEST(op->clear.mask, i)) {
450 303722 op->comps.flags[i] = 0;
451
2/2
✓ Branch 0 taken 181324 times.
✓ Branch 1 taken 122398 times.
303722 if (op->clear.value[i].num == 0)
452 181324 op->comps.flags[i] |= SWS_COMP_ZERO;
453
1/2
✓ Branch 0 taken 303722 times.
✗ Branch 1 not taken.
303722 if (op->clear.value[i].den == 1)
454 303722 op->comps.flags[i] |= SWS_COMP_EXACT;
455 } else {
456 702370 op->comps.flags[i] = prev.flags[i];
457 }
458 }
459 251523 break;
460 607211 case SWS_OP_SWIZZLE:
461
2/2
✓ Branch 0 taken 2428844 times.
✓ Branch 1 taken 607211 times.
3036055 for (int i = 0; i < 4; i++)
462 2428844 op->comps.flags[i] = prev.flags[op->swizzle.in[i]];
463 607211 break;
464 943542 case SWS_OP_CONVERT:
465
2/2
✓ Branch 0 taken 3774168 times.
✓ Branch 1 taken 943542 times.
4717710 for (int i = 0; i < 4; i++) {
466 3774168 op->comps.flags[i] = prev.flags[i];
467
2/2
✓ Branch 0 taken 2077956 times.
✓ Branch 1 taken 1696212 times.
3774168 if (ff_sws_pixel_type_is_int(op->convert.to))
468 2077956 op->comps.flags[i] |= SWS_COMP_EXACT;
469 }
470 943542 break;
471 533347 case SWS_OP_LINEAR:
472
2/2
✓ Branch 0 taken 2133388 times.
✓ Branch 1 taken 533347 times.
2666735 for (int i = 0; i < 4; i++) {
473 2133388 SwsCompFlags flags = SWS_COMP_IDENTITY;
474 2133388 AVRational min = Q(0), max = Q(0);
475
2/2
✓ Branch 0 taken 8533552 times.
✓ Branch 1 taken 2133388 times.
10666940 for (int j = 0; j < 4; j++) {
476 8533552 const AVRational k = op->lin.m[i][j];
477 8533552 AVRational mink = av_mul_q(prev.min[j], k);
478 8533552 AVRational maxk = av_mul_q(prev.max[j], k);
479
2/2
✓ Branch 0 taken 3182510 times.
✓ Branch 1 taken 5351042 times.
8533552 if (k.num) {
480 3182510 flags = merge_comp_flags(flags, prev.flags[j]);
481
2/2
✓ Branch 0 taken 1962957 times.
✓ Branch 1 taken 1219553 times.
3182510 if (k.den != 1) /* fractional coefficient */
482 1962957 flags &= ~SWS_COMP_EXACT;
483
2/2
✓ Branch 0 taken 615729 times.
✓ Branch 1 taken 2566781 times.
3182510 if (k.num < 0)
484 615729 FFSWAP(AVRational, mink, maxk);
485 3182510 min = av_add_q(min, mink);
486 3182510 max = av_add_q(max, maxk);
487 }
488 }
489
2/2
✓ Branch 0 taken 674866 times.
✓ Branch 1 taken 1458522 times.
2133388 if (op->lin.m[i][4].num) { /* nonzero offset */
490 674866 flags &= ~SWS_COMP_ZERO;
491
2/2
✓ Branch 0 taken 262783 times.
✓ Branch 1 taken 412083 times.
674866 if (op->lin.m[i][4].den != 1) /* fractional offset */
492 262783 flags &= ~SWS_COMP_EXACT;
493 674866 min = av_add_q(min, op->lin.m[i][4]);
494 674866 max = av_add_q(max, op->lin.m[i][4]);
495 }
496 2133388 op->comps.flags[i] = flags;
497 2133388 op->comps.min[i] = min;
498 2133388 op->comps.max[i] = max;
499 }
500 533347 break;
501 97339 case SWS_OP_SCALE:
502
2/2
✓ Branch 0 taken 389356 times.
✓ Branch 1 taken 97339 times.
486695 for (int i = 0; i < 4; i++) {
503 389356 op->comps.flags[i] = prev.flags[i];
504
2/2
✓ Branch 0 taken 277008 times.
✓ Branch 1 taken 112348 times.
389356 if (op->scale.factor.den != 1) /* fractional scale */
505 277008 op->comps.flags[i] &= ~SWS_COMP_EXACT;
506
2/2
✓ Branch 0 taken 1044 times.
✓ Branch 1 taken 388312 times.
389356 if (op->scale.factor.num < 0)
507 1044 FFSWAP(AVRational, op->comps.min[i], op->comps.max[i]);
508 }
509 97339 break;
510 case SWS_OP_FILTER_H:
511 case SWS_OP_FILTER_V: {
512 apply_filter_weights(&op->comps, &prev, op->filter.kernel);
513 break;
514 }
515
516 case SWS_OP_INVALID:
517 case SWS_OP_TYPE_NB:
518 av_unreachable("Invalid operation type!");
519 }
520
521 4841896 prev = op->comps;
522 }
523
524 /* Backwards pass, solves for component dependencies */
525 484805 bool need_out[4] = { false, false, false, false };
526
2/2
✓ Branch 0 taken 4841896 times.
✓ Branch 1 taken 484805 times.
5326701 for (int n = ops->num_ops - 1; n >= 0; n--) {
527 4841896 SwsOp *op = &ops->ops[n];
528 4841896 bool need_in[4] = { false, false, false, false };
529
530
2/2
✓ Branch 0 taken 19367584 times.
✓ Branch 1 taken 4841896 times.
24209480 for (int i = 0; i < 4; i++) {
531
2/2
✓ Branch 0 taken 6997023 times.
✓ Branch 1 taken 12370561 times.
19367584 if (!need_out[i])
532 6997023 op->comps.flags[i] = SWS_COMP_GARBAGE;
533 }
534
535
7/8
✓ Branch 0 taken 969610 times.
✓ Branch 1 taken 2317989 times.
✓ Branch 2 taken 83464 times.
✓ Branch 3 taken 78752 times.
✓ Branch 4 taken 251523 times.
✓ Branch 5 taken 607211 times.
✓ Branch 6 taken 533347 times.
✗ Branch 7 not taken.
4841896 switch (op->op) {
536 969610 case SWS_OP_READ:
537 case SWS_OP_WRITE:
538
2/2
✓ Branch 0 taken 2560452 times.
✓ Branch 1 taken 969610 times.
3530062 for (int i = 0; i < op->rw.elems; i++)
539 2560452 need_in[i] = op->op == SWS_OP_WRITE;
540
2/2
✓ Branch 0 taken 1317988 times.
✓ Branch 1 taken 969610 times.
2287598 for (int i = op->rw.elems; i < 4; i++)
541 1317988 need_in[i] = need_out[i];
542 969610 break;
543 2317989 case SWS_OP_SWAP_BYTES:
544 case SWS_OP_LSHIFT:
545 case SWS_OP_RSHIFT:
546 case SWS_OP_CONVERT:
547 case SWS_OP_DITHER:
548 case SWS_OP_MIN:
549 case SWS_OP_MAX:
550 case SWS_OP_SCALE:
551 case SWS_OP_FILTER_H:
552 case SWS_OP_FILTER_V:
553
2/2
✓ Branch 0 taken 9271956 times.
✓ Branch 1 taken 2317989 times.
11589945 for (int i = 0; i < 4; i++)
554 9271956 need_in[i] = need_out[i];
555 2317989 break;
556 83464 case SWS_OP_UNPACK:
557
4/4
✓ Branch 0 taken 333856 times.
✓ Branch 1 taken 23124 times.
✓ Branch 2 taken 273516 times.
✓ Branch 3 taken 60340 times.
356980 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
558 273516 need_in[0] |= need_out[i];
559 83464 break;
560 78752 case SWS_OP_PACK:
561
4/4
✓ Branch 0 taken 315008 times.
✓ Branch 1 taken 25660 times.
✓ Branch 2 taken 261916 times.
✓ Branch 3 taken 53092 times.
340668 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
562 261916 need_in[i] = need_out[0];
563 78752 break;
564 251523 case SWS_OP_CLEAR:
565
2/2
✓ Branch 0 taken 1006092 times.
✓ Branch 1 taken 251523 times.
1257615 for (int i = 0; i < 4; i++) {
566
2/2
✓ Branch 0 taken 702370 times.
✓ Branch 1 taken 303722 times.
1006092 if (!SWS_COMP_TEST(op->clear.mask, i))
567 702370 need_in[i] = need_out[i];
568 }
569 251523 break;
570 607211 case SWS_OP_SWIZZLE:
571
2/2
✓ Branch 0 taken 2428844 times.
✓ Branch 1 taken 607211 times.
3036055 for (int i = 0; i < 4; i++)
572 2428844 need_in[op->swizzle.in[i]] |= need_out[i];
573 607211 break;
574 533347 case SWS_OP_LINEAR:
575
2/2
✓ Branch 0 taken 2133388 times.
✓ Branch 1 taken 533347 times.
2666735 for (int i = 0; i < 4; i++) {
576
2/2
✓ Branch 0 taken 8533552 times.
✓ Branch 1 taken 2133388 times.
10666940 for (int j = 0; j < 4; j++) {
577
2/2
✓ Branch 0 taken 3182510 times.
✓ Branch 1 taken 5351042 times.
8533552 if (op->lin.m[i][j].num)
578 3182510 need_in[j] |= need_out[i];
579 }
580 }
581 533347 break;
582 }
583
584 4841896 memcpy(need_out, need_in, sizeof(need_in));
585 }
586 484805 }
587
588 995614 static void op_uninit(SwsOp *op)
589 {
590
3/4
✓ Branch 0 taken 117409 times.
✓ Branch 1 taken 42284 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 835921 times.
995614 switch (op->op) {
591 117409 case SWS_OP_READ:
592 117409 av_refstruct_unref(&op->rw.kernel);
593 117409 break;
594 42284 case SWS_OP_DITHER:
595 42284 av_refstruct_unref(&op->dither.matrix);
596 42284 break;
597 case SWS_OP_FILTER_H:
598 case SWS_OP_FILTER_V:
599 av_refstruct_unref(&op->filter.kernel);
600 break;
601 }
602
603 995614 *op = (SwsOp) {0};
604 995614 }
605
606 88059 SwsOpList *ff_sws_op_list_alloc(void)
607 {
608 88059 SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 88059 times.
88059 if (!ops)
610 return NULL;
611
612
2/2
✓ Branch 0 taken 352236 times.
✓ Branch 1 taken 88059 times.
440295 for (int i = 0; i < 4; i++)
613 352236 ops->plane_src[i] = ops->plane_dst[i] = i;
614 88059 ff_fmt_clear(&ops->src);
615 88059 ff_fmt_clear(&ops->dst);
616 88059 return ops;
617 }
618
619 192300 void ff_sws_op_list_free(SwsOpList **p_ops)
620 {
621 192300 SwsOpList *ops = *p_ops;
622
2/2
✓ Branch 0 taken 37556 times.
✓ Branch 1 taken 154744 times.
192300 if (!ops)
623 37556 return;
624
625
2/2
✓ Branch 0 taken 793060 times.
✓ Branch 1 taken 154744 times.
947804 for (int i = 0; i < ops->num_ops; i++)
626 793060 op_uninit(&ops->ops[i]);
627
628 154744 av_freep(&ops->ops);
629 154744 av_free(ops);
630 154744 *p_ops = NULL;
631 }
632
633 66685 SwsOpList *ff_sws_op_list_duplicate(const SwsOpList *ops)
634 {
635 66685 SwsOpList *copy = av_malloc(sizeof(*copy));
636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66685 times.
66685 if (!copy)
637 return NULL;
638
639 66685 int num = ops->num_ops;
640
1/2
✓ Branch 0 taken 66685 times.
✗ Branch 1 not taken.
66685 if (num)
641 66685 num = 1 << av_ceil_log2(num);
642
643 66685 *copy = *ops;
644 66685 copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66685 times.
66685 if (!copy->ops) {
646 av_free(copy);
647 return NULL;
648 }
649
650
2/2
✓ Branch 0 taken 336798 times.
✓ Branch 1 taken 66685 times.
403483 for (int i = 0; i < copy->num_ops; i++) {
651 336798 const SwsOp *op = &copy->ops[i];
652
3/4
✓ Branch 0 taken 66685 times.
✓ Branch 1 taken 16394 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 253719 times.
336798 switch (op->op) {
653 66685 case SWS_OP_READ:
654
2/2
✓ Branch 0 taken 16128 times.
✓ Branch 1 taken 50557 times.
66685 if (op->rw.kernel)
655 16128 av_refstruct_ref(op->rw.kernel);
656 66685 break;
657 16394 case SWS_OP_DITHER:
658 16394 av_refstruct_ref(op->dither.matrix);
659 16394 break;
660 case SWS_OP_FILTER_H:
661 case SWS_OP_FILTER_V:
662 av_refstruct_ref(op->filter.kernel);
663 break;
664 }
665 }
666
667 66685 return copy;
668 }
669
670 95327 const SwsOp *ff_sws_op_list_input(const SwsOpList *ops)
671 {
672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95327 times.
95327 if (!ops->num_ops)
673 return NULL;
674
675 95327 const SwsOp *read = &ops->ops[0];
676
1/2
✓ Branch 0 taken 95327 times.
✗ Branch 1 not taken.
95327 return read->op == SWS_OP_READ ? read : NULL;
677 }
678
679 74887 const SwsOp *ff_sws_op_list_output(const SwsOpList *ops)
680 {
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74887 times.
74887 if (!ops->num_ops)
682 return NULL;
683
684 74887 const SwsOp *write = &ops->ops[ops->num_ops - 1];
685
1/2
✓ Branch 0 taken 74887 times.
✗ Branch 1 not taken.
74887 return write->op == SWS_OP_WRITE ? write : NULL;
686 }
687
688 202299 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
689 {
690 202299 const int end = ops->num_ops - count;
691 av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
692
2/2
✓ Branch 0 taken 202554 times.
✓ Branch 1 taken 202299 times.
404853 for (int i = 0; i < count; i++)
693 202554 op_uninit(&ops->ops[index + i]);
694
2/2
✓ Branch 0 taken 1326409 times.
✓ Branch 1 taken 202299 times.
1528708 for (int i = index; i < end; i++)
695 1326409 ops->ops[i] = ops->ops[i + count];
696 202299 ops->num_ops = end;
697 202299 }
698
699 658816 int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
700 {
701 658816 void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
702
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 658816 times.
658816 if (!ret) {
703 op_uninit(op);
704 return AVERROR(ENOMEM);
705 }
706
707
2/2
✓ Branch 0 taken 123435 times.
✓ Branch 1 taken 658816 times.
782251 for (int i = ops->num_ops - 1; i > index; i--)
708 123435 ops->ops[i] = ops->ops[i - 1];
709 658816 ops->ops[index] = *op;
710 658816 return 0;
711 }
712
713 643248 int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
714 {
715 643248 return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
716 }
717
718 31704 bool ff_sws_op_list_is_noop(const SwsOpList *ops)
719 {
720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31704 times.
31704 if (!ops->num_ops)
721 return true;
722
723 31704 const SwsOp *read = ff_sws_op_list_input(ops);
724 31704 const SwsOp *write = ff_sws_op_list_output(ops);
725
4/6
✓ Branch 0 taken 31704 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31704 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 219 times.
✓ Branch 5 taken 31485 times.
31704 if (!read || !write || ops->num_ops > 2 ||
726
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 read->type != write->type ||
727
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 77 times.
219 read->rw.packed != write->rw.packed ||
728
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 10 times.
142 read->rw.elems != write->rw.elems ||
729
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 128 times.
132 read->rw.frac != write->rw.frac)
730 31576 return false;
731
732 /**
733 * Note that this check is unlikely to ever be hit in practice, since it
734 * would imply the existence of planar formats with different plane orders
735 * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
736 * However, the check is cheap and lets me sleep at night.
737 */
738
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 81 times.
128 const int num_planes = read->rw.packed ? 1 : read->rw.elems;
739
2/2
✓ Branch 0 taken 278 times.
✓ Branch 1 taken 128 times.
406 for (int i = 0; i < num_planes; i++) {
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
278 if (ops->plane_src[i] != ops->plane_dst[i])
741 return false;
742 }
743
744 128 return true;
745 }
746
747 20137 int ff_sws_op_list_max_size(const SwsOpList *ops)
748 {
749 20137 int max_size = 0;
750
2/2
✓ Branch 0 taken 130758 times.
✓ Branch 1 taken 20137 times.
150895 for (int i = 0; i < ops->num_ops; i++) {
751 130758 const int size = ff_sws_pixel_type_size(ops->ops[i].type);
752 130758 max_size = FFMAX(max_size, size);
753 }
754
755 20137 return max_size;
756 }
757
758 253838 uint32_t ff_sws_linear_mask(const SwsLinearOp c)
759 {
760 253838 uint32_t mask = 0;
761
2/2
✓ Branch 0 taken 1015352 times.
✓ Branch 1 taken 253838 times.
1269190 for (int i = 0; i < 4; i++) {
762
2/2
✓ Branch 0 taken 5076760 times.
✓ Branch 1 taken 1015352 times.
6092112 for (int j = 0; j < 5; j++) {
763
2/2
✓ Branch 1 taken 1536944 times.
✓ Branch 2 taken 3539816 times.
5076760 if (av_cmp_q(c.m[i][j], Q(i == j)))
764 1536944 mask |= SWS_MASK(i, j);
765 }
766 }
767 253838 return mask;
768 }
769
770 70280 static const char *describe_lin_mask(uint32_t mask)
771 {
772 /* Try to be fairly descriptive without assuming too much */
773 static const struct {
774 char name[24];
775 uint32_t mask;
776 } patterns[] = {
777 { "noop", 0 },
778 { "luma", SWS_MASK_LUMA },
779 { "alpha", SWS_MASK_ALPHA },
780 { "luma+alpha", SWS_MASK_LUMA | SWS_MASK_ALPHA },
781 { "dot3", 0x7 },
782 { "dot4", 0xF },
783 { "row0", SWS_MASK_ROW(0) },
784 { "row0+alpha", SWS_MASK_ROW(0) | SWS_MASK_ALPHA },
785 { "col0", SWS_MASK_COL(0) },
786 { "col0+off3", SWS_MASK_COL(0) | SWS_MASK_OFF3 },
787 { "off3", SWS_MASK_OFF3 },
788 { "off3+alpha", SWS_MASK_OFF3 | SWS_MASK_ALPHA },
789 { "diag3", SWS_MASK_DIAG3 },
790 { "diag4", SWS_MASK_DIAG4 },
791 { "diag3+alpha", SWS_MASK_DIAG3 | SWS_MASK_ALPHA },
792 { "diag3+off3", SWS_MASK_DIAG3 | SWS_MASK_OFF3 },
793 { "diag3+off3+alpha", SWS_MASK_DIAG3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
794 { "diag4+off4", SWS_MASK_DIAG4 | SWS_MASK_OFF4 },
795 { "matrix3", SWS_MASK_MAT3 },
796 { "matrix3+off3", SWS_MASK_MAT3 | SWS_MASK_OFF3 },
797 { "matrix3+off3+alpha", SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA },
798 { "matrix4", SWS_MASK_MAT4 },
799 { "matrix4+off4", SWS_MASK_MAT4 | SWS_MASK_OFF4 },
800 };
801
802
1/2
✓ Branch 0 taken 1069954 times.
✗ Branch 1 not taken.
1069954 for (int i = 0; i < FF_ARRAY_ELEMS(patterns); i++) {
803
2/2
✓ Branch 0 taken 70280 times.
✓ Branch 1 taken 999674 times.
1069954 if (!(mask & ~patterns[i].mask))
804 70280 return patterns[i].name;
805 }
806
807 av_unreachable("Invalid linear mask!");
808 return "ERR";
809 }
810
811 2296488 static char describe_comp_flags(SwsCompFlags flags)
812 {
813
2/2
✓ Branch 0 taken 635878 times.
✓ Branch 1 taken 1660610 times.
2296488 if (flags & SWS_COMP_GARBAGE)
814 635878 return 'X';
815
2/2
✓ Branch 0 taken 3330 times.
✓ Branch 1 taken 1657280 times.
1660610 else if (flags & SWS_COMP_ZERO)
816 3330 return '0';
817
2/2
✓ Branch 0 taken 101852 times.
✓ Branch 1 taken 1555428 times.
1657280 else if (flags & SWS_COMP_SWAPPED)
818 101852 return 'z';
819
2/2
✓ Branch 0 taken 490381 times.
✓ Branch 1 taken 1065047 times.
1555428 else if (flags & SWS_COMP_EXACT)
820 490381 return '+';
821 else
822 1065047 return '.';
823 }
824
825 3276900 static void print_q(AVBPrint *bp, const AVRational q)
826 {
827
2/2
✓ Branch 0 taken 7328 times.
✓ Branch 1 taken 3269572 times.
3276900 if (!q.den) {
828
2/4
✓ Branch 0 taken 7328 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7328 times.
7328 av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
829
2/2
✓ Branch 0 taken 2727299 times.
✓ Branch 1 taken 542273 times.
3269572 } else if (q.den == 1) {
830 2727299 av_bprintf(bp, "%d", q.num);
831
4/4
✓ Branch 0 taken 211423 times.
✓ Branch 1 taken 330850 times.
✓ Branch 2 taken 61640 times.
✓ Branch 3 taken 149783 times.
542273 } else if (abs(q.num) > 1000 || abs(q.den) > 1000) {
832 392490 av_bprintf(bp, "%f", av_q2d(q));
833 } else {
834 149783 av_bprintf(bp, "%d/%d", q.num, q.den);
835 }
836 3276900 }
837
838 708137 static void print_q4(AVBPrint *bp, const AVRational q4[4], SwsCompMask mask)
839 {
840 708137 av_bprintf(bp, "{");
841
2/2
✓ Branch 0 taken 2832548 times.
✓ Branch 1 taken 708137 times.
3540685 for (int i = 0; i < 4; i++) {
842
2/2
✓ Branch 0 taken 2124411 times.
✓ Branch 1 taken 708137 times.
2832548 if (i)
843 2124411 av_bprintf(bp, " ");
844
2/2
✓ Branch 0 taken 961248 times.
✓ Branch 1 taken 1871300 times.
2832548 if (!SWS_COMP_TEST(mask, i)) {
845 961248 av_bprintf(bp, "_");
846 } else {
847 1871300 print_q(bp, q4[i]);
848 }
849 }
850 708137 av_bprintf(bp, "}");
851 708137 }
852
853 574122 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
854 {
855 574122 const char *name = ff_sws_op_type_name(op->op);
856 574122 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
857
858
13/16
✓ Branch 0 taken 44308 times.
✓ Branch 1 taken 120272 times.
✓ Branch 2 taken 6032 times.
✓ Branch 3 taken 4890 times.
✓ Branch 4 taken 21028 times.
✓ Branch 5 taken 30947 times.
✓ Branch 6 taken 59599 times.
✓ Branch 7 taken 110748 times.
✓ Branch 8 taken 30618 times.
✓ Branch 9 taken 37033 times.
✓ Branch 10 taken 25415 times.
✓ Branch 11 taken 70280 times.
✓ Branch 12 taken 12952 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
574122 switch (op->op) {
859 44308 case SWS_OP_INVALID:
860 case SWS_OP_SWAP_BYTES:
861 44308 av_bprintf(bp, "%s", name);
862 44308 break;
863 120272 case SWS_OP_READ:
864 case SWS_OP_WRITE:
865 120272 av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
866 120272 op->rw.elems, op->rw.packed ? "packed" : "planar",
867
2/2
✓ Branch 0 taken 53930 times.
✓ Branch 1 taken 66342 times.
120272 op->rw.frac);
868
1/2
✓ Branch 0 taken 120272 times.
✗ Branch 1 not taken.
120272 if (!op->rw.filter)
869 120272 break;
870 const SwsFilterWeights *kernel = op->rw.kernel;
871 av_bprintf(bp, " + %d tap %s filter (%c)",
872 kernel->filter_size, kernel->name,
873 op->rw.filter == SWS_OP_FILTER_H ? 'H' : 'V');
874 break;
875 6032 case SWS_OP_LSHIFT:
876 6032 av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
877 6032 break;
878 4890 case SWS_OP_RSHIFT:
879 4890 av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
880 4890 break;
881 21028 case SWS_OP_PACK:
882 case SWS_OP_UNPACK:
883 21028 av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
884 21028 op->pack.pattern[0], op->pack.pattern[1],
885 21028 op->pack.pattern[2], op->pack.pattern[3]);
886 21028 break;
887 30947 case SWS_OP_CLEAR:
888 30947 av_bprintf(bp, "%-20s: ", name);
889 30947 print_q4(bp, op->clear.value, mask & op->clear.mask);
890 30947 break;
891 59599 case SWS_OP_SWIZZLE:
892 59599 av_bprintf(bp, "%-20s: %d%d%d%d", name,
893 59599 op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
894 59599 break;
895 110748 case SWS_OP_CONVERT:
896 221496 av_bprintf(bp, "%-20s: %s -> %s%s", name,
897 110748 ff_sws_pixel_type_name(op->type),
898 110748 ff_sws_pixel_type_name(op->convert.to),
899
2/2
✓ Branch 0 taken 540 times.
✓ Branch 1 taken 110208 times.
110748 op->convert.expand ? " (expand)" : "");
900 110748 break;
901 30618 case SWS_OP_DITHER:
902 30618 av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
903 30618 1 << op->dither.size_log2, 1 << op->dither.size_log2,
904 30618 op->dither.y_offset[0], op->dither.y_offset[1],
905 30618 op->dither.y_offset[2], op->dither.y_offset[3]);
906 30618 break;
907 37033 case SWS_OP_MIN:
908 37033 av_bprintf(bp, "%-20s: x <= ", name);
909 37033 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
910 37033 break;
911 25415 case SWS_OP_MAX:
912 25415 av_bprintf(bp, "%-20s: ", name);
913 25415 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
914 25415 av_bprintf(bp, " <= x");
915 25415 break;
916 70280 case SWS_OP_LINEAR:
917 70280 av_bprintf(bp, "%-20s: %s [", name, describe_lin_mask(op->lin.mask));
918
2/2
✓ Branch 0 taken 281120 times.
✓ Branch 1 taken 70280 times.
351400 for (int i = 0; i < 4; i++) {
919
2/2
✓ Branch 0 taken 210840 times.
✓ Branch 1 taken 70280 times.
281120 av_bprintf(bp, "%s[", i ? " " : "");
920
2/2
✓ Branch 0 taken 1405600 times.
✓ Branch 1 taken 281120 times.
1686720 for (int j = 0; j < 5; j++) {
921
2/2
✓ Branch 0 taken 1124480 times.
✓ Branch 1 taken 281120 times.
1405600 av_bprintf(bp, j ? " " : "");
922 1405600 print_q(bp, op->lin.m[i][j]);
923 }
924 281120 av_bprintf(bp, "]");
925 }
926 70280 av_bprintf(bp, "]");
927 70280 break;
928 12952 case SWS_OP_SCALE:
929 12952 av_bprintf(bp, "%-20s: * %d", name, op->scale.factor.num);
930
2/2
✓ Branch 0 taken 10925 times.
✓ Branch 1 taken 2027 times.
12952 if (op->scale.factor.den != 1)
931 10925 av_bprintf(bp, "/%d", op->scale.factor.den);
932 12952 break;
933 case SWS_OP_FILTER_H:
934 case SWS_OP_FILTER_V: {
935 const SwsFilterWeights *kernel = op->filter.kernel;
936 av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
937 kernel->src_size, kernel->dst_size,
938 kernel->name, kernel->filter_size);
939 break;
940 }
941 case SWS_OP_TYPE_NB:
942 break;
943 }
944 574122 }
945
946 120272 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
947 {
948 120272 bool inorder = true;
949
2/2
✓ Branch 0 taken 235520 times.
✓ Branch 1 taken 120272 times.
355792 for (int i = 0; i < nb_planes; i++)
950 235520 inorder &= order[i] == i;
951
2/2
✓ Branch 0 taken 106305 times.
✓ Branch 1 taken 13967 times.
120272 if (inorder)
952 106305 return;
953
954 13967 av_bprintf(bp, ", via {");
955
2/2
✓ Branch 0 taken 45120 times.
✓ Branch 1 taken 13967 times.
59087 for (int i = 0; i < nb_planes; i++)
956
2/2
✓ Branch 0 taken 31153 times.
✓ Branch 1 taken 13967 times.
45120 av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
957 13967 av_bprintf(bp, "}");
958 }
959
960 60136 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
961 const SwsOpList *ops)
962 {
963 AVBPrint bp;
964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60136 times.
60136 if (!ops->num_ops) {
965 av_log(log, lev, " (empty)\n");
966 return;
967 }
968
969 60136 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
970
971
2/2
✓ Branch 0 taken 574122 times.
✓ Branch 1 taken 60136 times.
634258 for (int i = 0; i < ops->num_ops; i++) {
972 574122 const SwsOp *op = &ops->ops[i];
973 574122 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
974 574122 av_bprint_clear(&bp);
975 574122 av_bprintf(&bp, " [%3s %c%c%c%c] ",
976 574122 ff_sws_pixel_type_name(op->type),
977 574122 describe_comp_flags(op->comps.flags[0]),
978 574122 describe_comp_flags(op->comps.flags[1]),
979 574122 describe_comp_flags(op->comps.flags[2]),
980 574122 describe_comp_flags(op->comps.flags[3]));
981
982 574122 ff_sws_op_desc(&bp, op);
983
984
4/4
✓ Branch 0 taken 513986 times.
✓ Branch 1 taken 60136 times.
✓ Branch 2 taken 60136 times.
✓ Branch 3 taken 453850 times.
574122 if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
985
2/2
✓ Branch 0 taken 53930 times.
✓ Branch 1 taken 66342 times.
120272 const int planes = op->rw.packed ? 1 : op->rw.elems;
986 120272 desc_plane_order(&bp, planes,
987
2/2
✓ Branch 0 taken 60136 times.
✓ Branch 1 taken 60136 times.
120272 op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
988 }
989
990
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 574122 times.
574122 av_assert0(av_bprint_is_complete(&bp));
991 574122 av_log(log, lev, "%s\n", bp.str);
992
993 /* Only print value ranges if any are relevant */
994 574122 SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
995 574122 ff_sws_comp_mask_q4(op->comps.max);
996
2/2
✓ Branch 0 taken 307371 times.
✓ Branch 1 taken 266751 times.
574122 if (range_mask & mask) {
997 307371 av_bprint_clear(&bp);
998 307371 av_bprintf(&bp, " min: ");
999 307371 print_q4(&bp, op->comps.min, mask);
1000 307371 av_bprintf(&bp, ", max: ");
1001 307371 print_q4(&bp, op->comps.max, mask);
1002
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 307371 times.
307371 av_assert0(av_bprint_is_complete(&bp));
1003 307371 av_log(log, lev_extra, "%s\n", bp.str);
1004 }
1005
1006 }
1007
1008 60136 av_log(log, lev, " (X = unused, z = byteswapped, + = exact, 0 = zero)\n");
1009 }
1010
1011 71289 static int enum_ops_fmt(SwsContext *ctx, void *opaque,
1012 enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1013 int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1014 {
1015 int ret;
1016 71289 const SwsPixelType type = SWS_PIXEL_F32;
1017 71289 SwsOpList *ops = ff_sws_op_list_alloc();
1018
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71289 times.
71289 if (!ops)
1019 return AVERROR(ENOMEM);
1020
1021 71289 ff_fmt_from_pixfmt(src_fmt, &ops->src);
1022 71289 ff_fmt_from_pixfmt(dst_fmt, &ops->dst);
1023 71289 ops->src.width = ops->dst.width = 16;
1024 71289 ops->src.height = ops->dst.height = 16;
1025
1026 71289 bool incomplete = ff_infer_colors(&ops->src.color, &ops->dst.color);
1027
3/4
✓ Branch 1 taken 35244 times.
✓ Branch 2 taken 36045 times.
✓ Branch 3 taken 35244 times.
✗ Branch 4 not taken.
106533 if (ff_sws_decode_pixfmt(ops, src_fmt) < 0 ||
1028
2/2
✓ Branch 1 taken 30492 times.
✓ Branch 2 taken 4752 times.
70488 ff_sws_decode_colors(ctx, type, ops, &ops->src, &incomplete) < 0 ||
1029
2/2
✓ Branch 1 taken 13068 times.
✓ Branch 2 taken 17424 times.
65736 ff_sws_encode_colors(ctx, type, ops, &ops->src, &ops->dst, &incomplete) < 0 ||
1030 30492 ff_sws_encode_pixfmt(ops, dst_fmt) < 0)
1031 {
1032 53865 ret = 0; /* silently skip unsupported formats */
1033 53865 goto fail;
1034 }
1035
1036 17424 ret = ff_sws_op_list_optimize(ops);
1037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17424 times.
17424 if (ret < 0)
1038 goto fail;
1039
1040 17424 ret = cb(ctx, opaque, ops);
1041
1/2
✓ Branch 0 taken 17424 times.
✗ Branch 1 not taken.
17424 if (ret < 0)
1042 goto fail;
1043
1044 17424 fail:
1045 71289 ff_sws_op_list_free(&ops);
1046 71289 return ret;
1047 }
1048
1049 1 int ff_sws_enum_op_lists(SwsContext *ctx, void *opaque,
1050 enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1051 int (*cb)(SwsContext *ctx, void *opaque, SwsOpList *ops))
1052 {
1053 1 const AVPixFmtDescriptor *src_start = av_pix_fmt_desc_next(NULL);
1054 1 const AVPixFmtDescriptor *dst_start = src_start;
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (src_fmt != AV_PIX_FMT_NONE)
1056 src_start = av_pix_fmt_desc_get(src_fmt);
1057
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (dst_fmt != AV_PIX_FMT_NONE)
1058 dst_start = av_pix_fmt_desc_get(dst_fmt);
1059
1060 const AVPixFmtDescriptor *src, *dst;
1061
2/2
✓ Branch 1 taken 267 times.
✓ Branch 2 taken 1 times.
268 for (src = src_start; src; src = av_pix_fmt_desc_next(src)) {
1062 267 const enum AVPixelFormat src_f = av_pix_fmt_desc_get_id(src);
1063
2/2
✓ Branch 1 taken 71289 times.
✓ Branch 2 taken 267 times.
71556 for (dst = dst_start; dst; dst = av_pix_fmt_desc_next(dst)) {
1064 71289 const enum AVPixelFormat dst_f = av_pix_fmt_desc_get_id(dst);
1065 71289 int ret = enum_ops_fmt(ctx, opaque, src_f, dst_f, cb);
1066
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71289 times.
71289 if (ret < 0)
1067 return ret;
1068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71289 times.
71289 if (dst_fmt != AV_PIX_FMT_NONE)
1069 break;
1070 }
1071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
267 if (src_fmt != AV_PIX_FMT_NONE)
1072 break;
1073 }
1074
1075 1 return 0;
1076 }
1077
1078 struct EnumOpaque {
1079 void *opaque;
1080 int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op);
1081 };
1082
1083 static int enum_ops(SwsContext *ctx, void *opaque, SwsOpList *ops)
1084 {
1085 struct EnumOpaque *priv = opaque;
1086 for (int i = 0; i < ops->num_ops; i++) {
1087 int ret = priv->cb(ctx, priv->opaque, &ops->ops[i]);
1088 if (ret < 0)
1089 return ret;
1090 }
1091 return 0;
1092 }
1093
1094 int ff_sws_enum_ops(SwsContext *ctx, void *opaque,
1095 enum AVPixelFormat src_fmt, enum AVPixelFormat dst_fmt,
1096 int (*cb)(SwsContext *ctx, void *opaque, SwsOp *op))
1097 {
1098 struct EnumOpaque priv = { opaque, cb };
1099 return ff_sws_enum_op_lists(ctx, &priv, src_fmt, dst_fmt, enum_ops);
1100 }
1101