FFmpeg coverage


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