FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops.c
Date: 2026-08-15 14:54:27
Exec Total Coverage
Lines: 625 674 92.7%
Functions: 31 31 100.0%
Branches: 411 464 88.6%

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
42 const SwsOpBackend * const ff_sws_op_backends[] = {
43 &backend_murder,
44 #if ARCH_AARCH64 && HAVE_NEON
45 &backend_aarch64,
46 #elif ARCH_X86_64 && HAVE_X86ASM
47 &backend_x86,
48 #endif
49 &backend_c,
50 #if HAVE_SPIRV_HEADERS_SPIRV_H || HAVE_SPIRV_UNIFIED1_SPIRV_H
51 &backend_spirv,
52 #endif
53 NULL
54 };
55
56 10515543 const char *ff_sws_pixel_type_name(SwsPixelType type)
57 {
58
4/7
✓ Branch 0 taken 1450412 times.
✓ Branch 1 taken 3427774 times.
✓ Branch 2 taken 549896 times.
✓ Branch 3 taken 5087461 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
10515543 switch (type) {
59 1450412 case SWS_PIXEL_U8: return "u8";
60 3427774 case SWS_PIXEL_U16: return "u16";
61 549896 case SWS_PIXEL_U32: return "u32";
62 5087461 case SWS_PIXEL_F32: return "f32";
63 case SWS_PIXEL_NONE: return "none";
64 case SWS_PIXEL_TYPE_NB: break;
65 }
66
67 av_unreachable("Invalid pixel type!");
68 return "ERR";
69 }
70
71 7399718 const char *ff_sws_op_type_name(SwsOpType op)
72 {
73
18/21
✓ Branch 0 taken 1205826 times.
✓ Branch 1 taken 1268117 times.
✓ Branch 2 taken 544458 times.
✓ Branch 3 taken 495143 times.
✓ Branch 4 taken 141318 times.
✓ Branch 5 taken 137217 times.
✓ Branch 6 taken 56707 times.
✓ Branch 7 taken 52701 times.
✓ Branch 8 taken 279431 times.
✓ Branch 9 taken 936955 times.
✓ Branch 10 taken 473186 times.
✓ Branch 11 taken 260839 times.
✓ Branch 12 taken 271060 times.
✓ Branch 13 taken 627184 times.
✓ Branch 14 taken 439196 times.
✓ Branch 15 taken 33753 times.
✓ Branch 16 taken 36179 times.
✓ Branch 17 taken 140448 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
7399718 switch (op) {
74 1205826 case SWS_OP_READ: return "SWS_OP_READ";
75 1268117 case SWS_OP_WRITE: return "SWS_OP_WRITE";
76 544458 case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
77 495143 case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
78 141318 case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
79 137217 case SWS_OP_PACK: return "SWS_OP_PACK";
80 56707 case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
81 52701 case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
82 279431 case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
83 936955 case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
84 473186 case SWS_OP_MIN: return "SWS_OP_MIN";
85 260839 case SWS_OP_MAX: return "SWS_OP_MAX";
86 271060 case SWS_OP_SCALE: return "SWS_OP_SCALE";
87 627184 case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
88 439196 case SWS_OP_DITHER: return "SWS_OP_DITHER";
89 33753 case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
90 36179 case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
91 140448 case SWS_OP_LUT_3D: return "SWS_OP_LUT_3D";
92 case SWS_OP_INVALID: return "SWS_OP_INVALID";
93 case SWS_OP_TYPE_NB: break;
94 }
95
96 av_unreachable("Invalid operation type!");
97 return "ERR";
98 }
99
100 16496219 SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
101 {
102 16496219 SwsCompMask mask = 0;
103
2/2
✓ Branch 0 taken 65984876 times.
✓ Branch 1 taken 16496219 times.
82481095 for (int i = 0; i < 4; i++) {
104
2/2
✓ Branch 0 taken 32615926 times.
✓ Branch 1 taken 33368950 times.
65984876 if (q[i].den)
105 32615926 mask |= SWS_COMP(i);
106 }
107 16496219 return mask;
108 }
109
110 159624 void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
111 {
112 159624 const SwsCompMask orig = *mask;
113 159624 SwsCompMask res = 0;
114
2/2
✓ Branch 0 taken 638496 times.
✓ Branch 1 taken 159624 times.
798120 for (int i = 0; i < 4; i++) {
115 638496 const int src = swiz->in[i];
116
2/2
✓ Branch 0 taken 244135 times.
✓ Branch 1 taken 394361 times.
638496 if (SWS_COMP_TEST(orig, src))
117 244135 res |= SWS_COMP(i);
118 }
119
120 159624 *mask = res;
121 159624 }
122
123 79436075 SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
124 {
125 79436075 SwsCompMask mask = 0;
126
2/2
✓ Branch 0 taken 317744300 times.
✓ Branch 1 taken 79436075 times.
397180375 for (int i = 0; i < 4; i++) {
127
2/2
✓ Branch 0 taken 206838665 times.
✓ Branch 1 taken 110905635 times.
317744300 if (SWS_OP_NEEDED(op, i))
128 206838665 mask |= SWS_COMP(i);
129 }
130 79436075 return mask;
131 }
132
133 6786907 int ff_sws_rw_op_planes(const SwsOp *op)
134 {
135 av_assert2(op->op == SWS_OP_READ || op->op == SWS_OP_WRITE);
136
3/4
✓ Branch 0 taken 4878858 times.
✓ Branch 1 taken 1894057 times.
✓ Branch 2 taken 13992 times.
✗ Branch 3 not taken.
6786907 switch (op->rw.mode) {
137 4878858 case SWS_RW_PLANAR: return op->rw.elems;
138 1894057 case SWS_RW_PACKED: return 1;
139 13992 case SWS_RW_PALETTE: return 2;
140 }
141
142 av_unreachable("Invalid read/write mode!");
143 return 0;
144 }
145
146 /* biased towards `a` */
147 92240804 static AVRational64 av_min_q64(AVRational64 a, AVRational64 b)
148 {
149
2/2
✓ Branch 1 taken 20838516 times.
✓ Branch 2 taken 71402288 times.
92240804 return av_cmp_q64(a, b) == 1 ? b : a;
150 }
151
152 75499860 static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
153 {
154
2/2
✓ Branch 1 taken 10524716 times.
✓ Branch 2 taken 64975144 times.
75499860 return av_cmp_q64(a, b) == -1 ? b : a;
155 }
156
157 196178428 void ff_sws_apply_op_q(const SwsOp *op, AVRational64 x[4])
158 {
159 uint64_t mask[4];
160 int shift[4];
161
162
12/17
✓ Branch 0 taken 53249846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4483714 times.
✓ Branch 3 taken 42486 times.
✓ Branch 4 taken 14445796 times.
✓ Branch 5 taken 1899434 times.
✓ Branch 6 taken 1695920 times.
✓ Branch 7 taken 34674794 times.
✓ Branch 8 taken 37241768 times.
✓ Branch 9 taken 81272 times.
✓ Branch 10 taken 23060201 times.
✓ Branch 11 taken 18874965 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 6428232 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
196178428 switch (op->op) {
163 53249846 case SWS_OP_READ:
164 case SWS_OP_WRITE:
165 53249846 return;
166 case SWS_OP_UNPACK: {
167 av_assert1(ff_sws_pixel_type_is_int(op->type));
168 ff_sws_pack_op_decode(op, mask, shift);
169 unsigned val = x[0].num;
170 for (int i = 0; i < 4; i++)
171 x[i] = Q((val >> shift[i]) & mask[i]);
172 return;
173 }
174 4483714 case SWS_OP_PACK: {
175 av_assert1(ff_sws_pixel_type_is_int(op->type));
176 4483714 ff_sws_pack_op_decode(op, mask, shift);
177 4483714 unsigned val = 0;
178
2/2
✓ Branch 0 taken 17934856 times.
✓ Branch 1 taken 4483714 times.
22418570 for (int i = 0; i < 4; i++)
179 17934856 val |= (x[i].num & mask[i]) << shift[i];
180 4483714 x[0] = Q(val);
181 4483714 return;
182 }
183 42486 case SWS_OP_SWAP_BYTES:
184
1/3
✓ Branch 0 taken 42486 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
42486 switch (op->type) {
185 42486 case SWS_PIXEL_U16:
186
2/2
✓ Branch 0 taken 169944 times.
✓ Branch 1 taken 42486 times.
212430 for (int i = 0; i < 4; i++) {
187 av_assert2(x[i].num >= 0 && x[i].num <= UINT16_MAX);
188 169944 x[i].num = av_bswap16(x[i].num);
189 }
190 42486 return;
191 case SWS_PIXEL_U32:
192 for (int i = 0; i < 4; i++) {
193 av_assert2(x[i].num >= 0 && x[i].num <= UINT32_MAX);
194 x[i].num = av_bswap32(x[i].num);
195 }
196 return;
197 }
198 av_unreachable("Invalid pixel type for SWS_OP_SWAP_BYTES!");
199 return;
200 14445796 case SWS_OP_CLEAR:
201
2/2
✓ Branch 0 taken 57783184 times.
✓ Branch 1 taken 14445796 times.
72228980 for (int i = 0; i < 4; i++) {
202
2/2
✓ Branch 0 taken 17100914 times.
✓ Branch 1 taken 40682270 times.
57783184 if (SWS_COMP_TEST(op->clear.mask, i))
203 17100914 x[i] = op->clear.value[i];
204 }
205 14445796 return;
206 1899434 case SWS_OP_LSHIFT: {
207 av_assert1(ff_sws_pixel_type_is_int(op->type));
208 1899434 AVRational64 mult = Q(1 << op->shift.amount);
209
2/2
✓ Branch 0 taken 7597736 times.
✓ Branch 1 taken 1899434 times.
9497170 for (int i = 0; i < 4; i++)
210
2/2
✓ Branch 0 taken 6472660 times.
✓ Branch 1 taken 1125076 times.
7597736 x[i] = x[i].den ? av_mul_q64(x[i], mult) : x[i];
211 1899434 return;
212 }
213 1695920 case SWS_OP_RSHIFT: {
214 av_assert1(ff_sws_pixel_type_is_int(op->type));
215
2/2
✓ Branch 0 taken 6783680 times.
✓ Branch 1 taken 1695920 times.
8479600 for (int i = 0; i < 4; i++)
216
2/2
✓ Branch 0 taken 4943716 times.
✓ Branch 1 taken 1839964 times.
6783680 x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
217 1695920 return;
218 }
219 34674794 case SWS_OP_SWIZZLE: {
220 34674794 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
221
2/2
✓ Branch 0 taken 138699176 times.
✓ Branch 1 taken 34674794 times.
173373970 for (int i = 0; i < 4; i++)
222 138699176 x[i] = orig[op->swizzle.in[i]];
223 34674794 return;
224 }
225 37241768 case SWS_OP_CONVERT:
226
2/2
✓ Branch 0 taken 29309052 times.
✓ Branch 1 taken 7932716 times.
37241768 if (ff_sws_pixel_type_is_int(op->convert.to)) {
227 29309052 const AVRational64 scale = ff_sws_pixel_expand(op->type, op->convert.to);
228
2/2
✓ Branch 0 taken 117236208 times.
✓ Branch 1 taken 29309052 times.
146545260 for (int i = 0; i < 4; i++) {
229
2/2
✓ Branch 0 taken 102713578 times.
✓ Branch 1 taken 14522630 times.
117236208 x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
230
2/2
✓ Branch 0 taken 35064 times.
✓ Branch 1 taken 117201144 times.
117236208 if (op->convert.expand)
231 35064 x[i] = av_mul_q64(x[i], scale);
232 }
233 }
234 37241768 return;
235 81272 case SWS_OP_DITHER:
236 av_assert1(!ff_sws_pixel_type_is_int(op->type));
237
2/2
✓ Branch 0 taken 325088 times.
✓ Branch 1 taken 81272 times.
406360 for (int i = 0; i < 4; i++) {
238
3/4
✓ Branch 0 taken 207319 times.
✓ Branch 1 taken 117769 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 207319 times.
325088 if (op->dither.y_offset[i] >= 0 && x[i].den)
239 x[i] = av_add_q64(x[i], av_make_q64(1, 2));
240 }
241 81272 return;
242 23060201 case SWS_OP_MIN:
243
2/2
✓ Branch 0 taken 92240804 times.
✓ Branch 1 taken 23060201 times.
115301005 for (int i = 0; i < 4; i++)
244 92240804 x[i] = av_min_q64(x[i], op->clamp.limit[i]);
245 23060201 return;
246 18874965 case SWS_OP_MAX:
247
2/2
✓ Branch 0 taken 75499860 times.
✓ Branch 1 taken 18874965 times.
94374825 for (int i = 0; i < 4; i++)
248 75499860 x[i] = av_max_q64(x[i], op->clamp.limit[i]);
249 18874965 return;
250 case SWS_OP_LINEAR: {
251 av_assert1(!ff_sws_pixel_type_is_int(op->type));
252 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
253 for (int i = 0; i < 4; i++) {
254 AVRational64 sum = op->lin.m[i][4];
255 for (int j = 0; j < 4; j++)
256 sum = av_add_q64(sum, av_mul_q64(orig[j], op->lin.m[i][j]));
257 x[i] = sum;
258 }
259 return;
260 }
261 6428232 case SWS_OP_SCALE:
262
2/2
✓ Branch 0 taken 25712928 times.
✓ Branch 1 taken 6428232 times.
32141160 for (int i = 0; i < 4; i++)
263
2/2
✓ Branch 0 taken 17019948 times.
✓ Branch 1 taken 8692980 times.
25712928 x[i] = x[i].den ? av_mul_q64(x[i], op->scale.factor) : x[i];
264 6428232 return;
265 case SWS_OP_FILTER_H:
266 case SWS_OP_FILTER_V:
267 /* Filters have normalized energy by definition, so they don't
268 * conceptually modify individual components */
269 return;
270 case SWS_OP_LUT_3D:
271 /* 3D LUTs are treated as a black box, so set those values to NaN */
272 for (int i = 0; i < 3; i++)
273 x[i] = (AVRational64) {0};
274 return;
275 }
276
277 av_unreachable("Invalid operation type!");
278 }
279
280 enum {
281 SWS_COMP_IDENTITY = SWS_COMP_ZERO | SWS_COMP_EXACT |
282 SWS_COMP_COPY | SWS_COMP_CONST,
283
284 SWS_COMP_DIRTY = ~(SWS_COMP_COPY | SWS_COMP_CONST),
285 };
286
287 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
288 550142706 static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
289 {
290 550142706 const SwsCompFlags flags_or = SWS_COMP_GARBAGE | SWS_COMP_SWAPPED;
291 550142706 const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
292 550142706 return ((a & b) & flags_and) | ((a | b) & flags_or);
293 }
294
295 13302275 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
296 const SwsFilterWeights *weights)
297 {
298 13302275 const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
299 13302275 const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
300
2/2
✓ Branch 0 taken 53209100 times.
✓ Branch 1 taken 13302275 times.
66511375 for (int i = 0; i < 4; i++) {
301 53209100 comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
302 53209100 comps->dep_in[i] = prev->dep_in[i];
303 /* Only point sampling preserves exactness */
304
2/2
✓ Branch 0 taken 52730704 times.
✓ Branch 1 taken 478396 times.
53209100 if (weights->filter_size != 1)
305 52730704 comps->flags[i] &= ~SWS_COMP_EXACT;
306 /* Update min/max assuming extremes */
307 53209100 comps->min[i] = av_add_q64(av_mul_q64(prev->min[i], posw),
308 av_mul_q64(prev->max[i], negw));
309 53209100 comps->max[i] = av_add_q64(av_mul_q64(prev->min[i], negw),
310 av_mul_q64(prev->max[i], posw));
311 }
312 13302275 }
313
314 /* Infer + propagate known information about components */
315 13595497 void ff_sws_op_list_update_comps(SwsOpList *ops)
316 {
317 13595497 SwsComps prev = { .flags = {
318 SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE,
319 }};
320
321 /* Forwards pass, propagates knowledge about the incoming pixel values */
322
2/2
✓ Branch 0 taken 150847494 times.
✓ Branch 1 taken 13595497 times.
164442991 for (int n = 0; n < ops->num_ops; n++) {
323 150847494 SwsOp *op = &ops->ops[n];
324
325
2/2
✓ Branch 0 taken 53038791 times.
✓ Branch 1 taken 97808703 times.
150847494 switch (op->op) {
326 53038791 case SWS_OP_LINEAR:
327 case SWS_OP_DITHER:
328 case SWS_OP_SWAP_BYTES:
329 case SWS_OP_UNPACK:
330 case SWS_OP_FILTER_H:
331 case SWS_OP_FILTER_V:
332 case SWS_OP_LUT_3D:
333 53038791 break; /* special cases, handled below */
334 97808703 default:
335 97808703 memcpy(op->comps.min, prev.min, sizeof(prev.min));
336 97808703 memcpy(op->comps.max, prev.max, sizeof(prev.max));
337 97808703 ff_sws_apply_op_q(op, op->comps.min);
338 97808703 ff_sws_apply_op_q(op, op->comps.max);
339 97808703 break;
340 }
341
342
2/2
✓ Branch 0 taken 603389976 times.
✓ Branch 1 taken 150847494 times.
754237470 for (int i = 0; i < 4; i++) {
343 603389976 op->comps.flags[i] = SWS_COMP_IDENTITY;
344 603389976 op->comps.dep_in[i] = SWS_COMP_NONE;
345 }
346
347 #define FORWARD(I, J, EXPR) do { \
348 SwsCompFlags flags = prev.flags[J]; \
349 op->comps.flags[I] = merge_comp_flags(op->comps.flags[I], (EXPR)); \
350 op->comps.dep_in[I] |= prev.dep_in[J]; \
351 } while (0)
352
353 #define RESET(I) do { \
354 op->comps.flags[I] = SWS_COMP_GARBAGE; \
355 op->comps.min[I] = op->comps.max[I] = (AVRational64) {0}; \
356 op->comps.dep_in[I] = SWS_COMP_NONE; \
357 } while (0)
358
359
15/16
✓ Branch 0 taken 13029426 times.
✓ Branch 1 taken 9147202 times.
✓ Branch 2 taken 13595497 times.
✓ Branch 3 taken 1796101 times.
✓ Branch 4 taken 20900054 times.
✓ Branch 5 taken 7879957 times.
✓ Branch 6 taken 2190906 times.
✓ Branch 7 taken 2241857 times.
✓ Branch 8 taken 7222898 times.
✓ Branch 9 taken 17257585 times.
✓ Branch 10 taken 18551169 times.
✓ Branch 11 taken 20136294 times.
✓ Branch 12 taken 3214116 times.
✓ Branch 13 taken 10741334 times.
✓ Branch 14 taken 2943098 times.
✗ Branch 15 not taken.
150847494 switch (op->op) {
360 13029426 case SWS_OP_READ:
361 /* Active components are taken from the user-provided values,
362 * other components are explicitly stripped */
363
2/2
✓ Branch 0 taken 32937113 times.
✓ Branch 1 taken 13029426 times.
45966539 for (int i = 0; i < op->rw.elems; i++) {
364 32937113 int idx = 0;
365
3/4
✓ Branch 0 taken 270468 times.
✓ Branch 1 taken 12644591 times.
✓ Branch 2 taken 20022054 times.
✗ Branch 3 not taken.
32937113 switch (op->rw.mode) {
366 270468 case SWS_RW_PALETTE: idx = i; break;
367 12644591 case SWS_RW_PACKED: idx = i; break;
368 20022054 case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
369 }
370
371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32937113 times.
32937113 av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
372 32937113 op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
373 32937113 op->comps.min[i] = ops->comps_src.min[idx];
374 32937113 op->comps.max[i] = ops->comps_src.max[idx];
375 32937113 op->comps.dep_in[i] = SWS_COMP(i);
376
377 /**
378 * Don't mark packed or fractional reads as a copy, because the
379 * read operation implicitly unpacks the data into separate
380 * components. The only case in which op lists involving such
381 * reads can be refcopies is in the case of a true noop, which
382 * is already covered by the no-op check.
383 */
384
4/4
✓ Branch 0 taken 20022054 times.
✓ Branch 1 taken 12915059 times.
✓ Branch 2 taken 19817420 times.
✓ Branch 3 taken 204634 times.
32937113 if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
385 19817420 op->comps.flags[i] |= SWS_COMP_COPY;
386 }
387
388
2/2
✓ Branch 0 taken 2560941 times.
✓ Branch 1 taken 10468485 times.
13029426 if (op->rw.filter.op) {
389 2560941 const SwsComps prev = op->comps;
390 2560941 apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
391 }
392 13029426 break;
393 9147202 case SWS_OP_SWAP_BYTES:
394
2/2
✓ Branch 0 taken 36588808 times.
✓ Branch 1 taken 9147202 times.
45736010 for (int i = 0; i < 4; i++) {
395 36588808 FORWARD(i, i, (flags ^ SWS_COMP_SWAPPED) & SWS_COMP_DIRTY);
396 36588808 op->comps.min[i] = prev.min[i];
397 36588808 op->comps.max[i] = prev.max[i];
398 }
399 9147202 break;
400 13595497 case SWS_OP_WRITE:
401
2/2
✓ Branch 0 taken 35518375 times.
✓ Branch 1 taken 13595497 times.
49113872 for (int i = 0; i < op->rw.elems; i++)
402 av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
403
2/2
✓ Branch 0 taken 54381988 times.
✓ Branch 1 taken 13595497 times.
67977485 for (int i = 0; i < 4; i++)
404 54381988 FORWARD(i, i, flags);
405 13595497 break;
406 1796101 case SWS_OP_LSHIFT:
407 case SWS_OP_RSHIFT:
408
2/2
✓ Branch 0 taken 7184404 times.
✓ Branch 1 taken 1796101 times.
8980505 for (int i = 0; i < 4; i++)
409 7184404 FORWARD(i, i, flags & SWS_COMP_DIRTY);
410 1796101 break;
411 20900054 case SWS_OP_MIN:
412 case SWS_OP_MAX: {
413
2/2
✓ Branch 0 taken 11489428 times.
✓ Branch 1 taken 9410626 times.
20900054 AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
414
2/2
✓ Branch 0 taken 83600216 times.
✓ Branch 1 taken 20900054 times.
104500270 for (int i = 0; i < 4; i++) {
415 83600216 FORWARD(i, i, flags);
416
2/2
✓ Branch 0 taken 68599994 times.
✓ Branch 1 taken 15000222 times.
83600216 if (op->clamp.limit[i].den)
417 68599994 op->comps.flags[i] &= SWS_COMP_DIRTY;
418
2/2
✓ Branch 0 taken 17900057 times.
✓ Branch 1 taken 65700159 times.
83600216 if (!bound[i].den) /* reset undefined bounds to known range */
419 17900057 bound[i] = op->clamp.limit[i];
420 }
421 20900054 break;
422 }
423 7879957 case SWS_OP_DITHER:
424
2/2
✓ Branch 0 taken 31519828 times.
✓ Branch 1 taken 7879957 times.
39399785 for (int i = 0; i < 4; i++) {
425 31519828 FORWARD(i, i, flags);
426 31519828 op->comps.min[i] = prev.min[i];
427 31519828 op->comps.max[i] = prev.max[i];
428
2/2
✓ Branch 0 taken 5095919 times.
✓ Branch 1 taken 26423909 times.
31519828 if (op->dither.y_offset[i] < 0)
429 5095919 continue;
430 /* Strip zero flag because of the nonzero dithering offset */
431 26423909 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
432 26423909 op->comps.min[i] = av_add_q64(op->comps.min[i], op->dither.min);
433 26423909 op->comps.max[i] = av_add_q64(op->comps.max[i], op->dither.max);
434 }
435 7879957 break;
436 2190906 case SWS_OP_UNPACK:
437
2/2
✓ Branch 0 taken 8763624 times.
✓ Branch 1 taken 2190906 times.
10954530 for (int i = 0; i < 4; i++) {
438 8763624 const int pattern = op->pack.pattern[i];
439
2/2
✓ Branch 0 taken 7335248 times.
✓ Branch 1 taken 1428376 times.
8763624 if (pattern) {
440 av_assert1(pattern < 32);
441 7335248 FORWARD(i, 0, flags & SWS_COMP_DIRTY);
442 7335248 op->comps.min[i] = Q(0);
443 7335248 op->comps.max[i] = Q((1ULL << pattern) - 1);
444 } else
445 1428376 RESET(i);
446 }
447 2190906 break;
448 2241857 case SWS_OP_PACK:
449
2/2
✓ Branch 0 taken 8967428 times.
✓ Branch 1 taken 2241857 times.
11209285 for (int i = 0; i < 4; i++) {
450
2/2
✓ Branch 0 taken 7499830 times.
✓ Branch 1 taken 1467598 times.
8967428 if (op->pack.pattern[i])
451 7499830 FORWARD(0, i, flags & SWS_COMP_DIRTY);
452
2/2
✓ Branch 0 taken 6725571 times.
✓ Branch 1 taken 2241857 times.
8967428 if (i > 0) /* clear remaining comps for sanity */
453 6725571 RESET(i);
454 }
455 2241857 break;
456 7222898 case SWS_OP_CLEAR:
457
2/2
✓ Branch 0 taken 28891592 times.
✓ Branch 1 taken 7222898 times.
36114490 for (int i = 0; i < 4; i++) {
458
2/2
✓ Branch 0 taken 8550457 times.
✓ Branch 1 taken 20341135 times.
28891592 if (SWS_COMP_TEST(op->clear.mask, i)) {
459 8550457 op->comps.flags[i] = SWS_COMP_CONST;
460
2/2
✓ Branch 0 taken 4963844 times.
✓ Branch 1 taken 3586613 times.
8550457 if (op->clear.value[i].num == 0)
461 4963844 op->comps.flags[i] |= SWS_COMP_ZERO;
462
1/2
✓ Branch 0 taken 8550457 times.
✗ Branch 1 not taken.
8550457 if (op->clear.value[i].den == 1)
463 8550457 op->comps.flags[i] |= SWS_COMP_EXACT;
464 } else {
465 20341135 FORWARD(i, i, flags);
466 }
467 }
468 7222898 break;
469 17257585 case SWS_OP_SWIZZLE:
470
2/2
✓ Branch 0 taken 69030340 times.
✓ Branch 1 taken 17257585 times.
86287925 for (int i = 0; i < 4; i++)
471 69030340 FORWARD(i, op->swizzle.in[i], flags);
472 17257585 break;
473 18551169 case SWS_OP_CONVERT:
474
2/2
✓ Branch 0 taken 74204676 times.
✓ Branch 1 taken 18551169 times.
92755845 for (int i = 0; i < 4; i++) {
475 74204676 FORWARD(i, i, flags);
476
4/4
✓ Branch 0 taken 28713854 times.
✓ Branch 1 taken 45490822 times.
✓ Branch 2 taken 17084 times.
✓ Branch 3 taken 28696770 times.
74204676 if (!(prev.flags[i] & SWS_COMP_EXACT) || op->convert.expand)
477 45507906 op->comps.flags[i] &= SWS_COMP_DIRTY;
478
2/2
✓ Branch 0 taken 58339244 times.
✓ Branch 1 taken 15865432 times.
74204676 if (ff_sws_pixel_type_is_int(op->convert.to))
479 58339244 op->comps.flags[i] |= SWS_COMP_EXACT;
480 }
481 18551169 break;
482 20136294 case SWS_OP_LINEAR:
483
2/2
✓ Branch 0 taken 80545176 times.
✓ Branch 1 taken 20136294 times.
100681470 for (int i = 0; i < 4; i++) {
484 80545176 AVRational64 min = Q(0), max = Q(0);
485 80545176 bool first = true;
486
2/2
✓ Branch 0 taken 322180704 times.
✓ Branch 1 taken 80545176 times.
402725880 for (int j = 0; j < 4; j++) {
487 322180704 const AVRational64 k = op->lin.m[i][j];
488 322180704 AVRational64 mink = av_mul_q64(prev.min[j], k);
489 322180704 AVRational64 maxk = av_mul_q64(prev.max[j], k);
490
2/2
✓ Branch 0 taken 116168789 times.
✓ Branch 1 taken 206011915 times.
322180704 if (k.num) {
491 116168789 FORWARD(i, j, flags);
492
2/2
✓ Branch 0 taken 70095688 times.
✓ Branch 1 taken 46073101 times.
116168789 if (k.den != 1) /* fractional coefficient */
493 70095688 op->comps.flags[i] &= ~SWS_COMP_EXACT;
494
2/2
✓ Branch 0 taken 20953846 times.
✓ Branch 1 taken 95214943 times.
116168789 if (k.num < 0)
495 20953846 FFSWAP(AVRational64, mink, maxk);
496 116168789 min = av_add_q64(min, mink);
497 116168789 max = av_add_q64(max, maxk);
498
4/4
✓ Branch 0 taken 80545176 times.
✓ Branch 1 taken 35623613 times.
✓ Branch 3 taken 51399392 times.
✓ Branch 4 taken 29145784 times.
116168789 if (!first || av_cmp_q64(k, Q(1)))
499 87023005 op->comps.flags[i] &= SWS_COMP_DIRTY;
500 116168789 first = false;
501 }
502 }
503
2/2
✓ Branch 0 taken 20791557 times.
✓ Branch 1 taken 59753619 times.
80545176 if (op->lin.m[i][4].num) { /* nonzero offset */
504 20791557 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
505
2/2
✓ Branch 0 taken 8355338 times.
✓ Branch 1 taken 12436219 times.
20791557 if (op->lin.m[i][4].den != 1) /* fractional offset */
506 8355338 op->comps.flags[i] &= ~SWS_COMP_EXACT;
507 20791557 min = av_add_q64(min, op->lin.m[i][4]);
508 20791557 max = av_add_q64(max, op->lin.m[i][4]);
509 }
510 80545176 op->comps.min[i] = min;
511 80545176 op->comps.max[i] = max;
512 }
513 20136294 break;
514 3214116 case SWS_OP_SCALE:
515
2/2
✓ Branch 0 taken 12856464 times.
✓ Branch 1 taken 3214116 times.
16070580 for (int i = 0; i < 4; i++) {
516 12856464 FORWARD(i, i, flags & SWS_COMP_DIRTY);
517
2/2
✓ Branch 0 taken 10233164 times.
✓ Branch 1 taken 2623300 times.
12856464 if (op->scale.factor.den != 1) /* fractional scale */
518 10233164 op->comps.flags[i] &= ~SWS_COMP_EXACT;
519
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12856464 times.
12856464 if (op->scale.factor.num < 0)
520 FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
521 }
522 3214116 break;
523 10741334 case SWS_OP_FILTER_H:
524 case SWS_OP_FILTER_V: {
525 10741334 apply_filter_weights(&op->comps, &prev, op->filter.kernel);
526 10741334 break;
527 }
528 2943098 case SWS_OP_LUT_3D:
529
2/2
✓ Branch 0 taken 8829294 times.
✓ Branch 1 taken 2943098 times.
11772392 for (int i = 0; i < 3; i++) {
530 /* 3x3 dependency matrix; strip all information except
531 * SWS_COMP_GARBAGE (for correctness validation) */
532
2/2
✓ Branch 0 taken 26487882 times.
✓ Branch 1 taken 8829294 times.
35317176 for (int j = 0; j < 3; j++)
533 26487882 FORWARD(i, j, flags & SWS_COMP_GARBAGE);
534 /* LUT output domain is always scaled to full 16-bit range */
535 8829294 op->comps.min[i] = Q(0);
536 8829294 op->comps.max[i] = Q(UINT16_MAX);
537 }
538 /* Pass through alpha channel untouched */
539 2943098 FORWARD(3, 3, flags);
540 2943098 op->comps.min[3] = prev.min[3];
541 2943098 op->comps.max[3] = prev.max[3];
542 2943098 break;
543 case SWS_OP_INVALID:
544 case SWS_OP_TYPE_NB:
545 av_unreachable("Invalid operation type!");
546 }
547
548 150847494 prev = op->comps;
549 }
550
551 /* Backwards pass, solves for output component dependencies */
552 13595497 SwsCompMask need_out[4] = {0};
553
554
2/2
✓ Branch 0 taken 150847494 times.
✓ Branch 1 taken 13595497 times.
164442991 for (int n = ops->num_ops - 1; n >= 0; n--) {
555 150847494 SwsOp *op = &ops->ops[n];
556 150847494 SwsCompMask need_in[4] = {0};
557
558
2/2
✓ Branch 0 taken 603389976 times.
✓ Branch 1 taken 150847494 times.
754237470 for (int i = 0; i < 4; i++) {
559 603389976 op->comps.dep_out[i] = need_out[i];
560
2/2
✓ Branch 0 taken 212101994 times.
✓ Branch 1 taken 391287982 times.
603389976 if (!need_out[i])
561 212101994 RESET(i);
562 }
563
564
8/9
✓ Branch 0 taken 26624923 times.
✓ Branch 1 taken 72229933 times.
✓ Branch 2 taken 2190906 times.
✓ Branch 3 taken 2241857 times.
✓ Branch 4 taken 7222898 times.
✓ Branch 5 taken 17257585 times.
✓ Branch 6 taken 20136294 times.
✓ Branch 7 taken 2943098 times.
✗ Branch 8 not taken.
150847494 switch (op->op) {
565 26624923 case SWS_OP_READ:
566 case SWS_OP_WRITE:
567
2/2
✓ Branch 0 taken 68455488 times.
✓ Branch 1 taken 26624923 times.
95080411 for (int i = 0; i < op->rw.elems; i++)
568
2/2
✓ Branch 0 taken 35518375 times.
✓ Branch 1 taken 32937113 times.
68455488 need_in[i] = (op->op == SWS_OP_WRITE) ? SWS_COMP(i) : 0;
569
2/2
✓ Branch 0 taken 38044204 times.
✓ Branch 1 taken 26624923 times.
64669127 for (int i = op->rw.elems; i < 4; i++)
570 38044204 need_in[i] = need_out[i];
571 26624923 break;
572 72229933 case SWS_OP_SWAP_BYTES:
573 case SWS_OP_LSHIFT:
574 case SWS_OP_RSHIFT:
575 case SWS_OP_CONVERT:
576 case SWS_OP_DITHER:
577 case SWS_OP_MIN:
578 case SWS_OP_MAX:
579 case SWS_OP_SCALE:
580 case SWS_OP_FILTER_H:
581 case SWS_OP_FILTER_V:
582
2/2
✓ Branch 0 taken 288919732 times.
✓ Branch 1 taken 72229933 times.
361149665 for (int i = 0; i < 4; i++)
583 288919732 need_in[i] = need_out[i];
584 72229933 break;
585 2190906 case SWS_OP_UNPACK:
586
4/4
✓ Branch 0 taken 8763624 times.
✓ Branch 1 taken 762530 times.
✓ Branch 2 taken 7335248 times.
✓ Branch 3 taken 1428376 times.
9526154 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
587 7335248 need_in[0] |= need_out[i];
588 2190906 break;
589 2241857 case SWS_OP_PACK:
590
4/4
✓ Branch 0 taken 8967428 times.
✓ Branch 1 taken 774259 times.
✓ Branch 2 taken 7499830 times.
✓ Branch 3 taken 1467598 times.
9741687 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
591 7499830 need_in[i] = need_out[0];
592 2241857 break;
593 7222898 case SWS_OP_CLEAR:
594
2/2
✓ Branch 0 taken 28891592 times.
✓ Branch 1 taken 7222898 times.
36114490 for (int i = 0; i < 4; i++) {
595
2/2
✓ Branch 0 taken 20341135 times.
✓ Branch 1 taken 8550457 times.
28891592 if (!SWS_COMP_TEST(op->clear.mask, i))
596 20341135 need_in[i] = need_out[i];
597 }
598 7222898 break;
599 17257585 case SWS_OP_SWIZZLE:
600
2/2
✓ Branch 0 taken 69030340 times.
✓ Branch 1 taken 17257585 times.
86287925 for (int i = 0; i < 4; i++)
601 69030340 need_in[op->swizzle.in[i]] |= need_out[i];
602 17257585 break;
603 20136294 case SWS_OP_LINEAR:
604
2/2
✓ Branch 0 taken 80545176 times.
✓ Branch 1 taken 20136294 times.
100681470 for (int i = 0; i < 4; i++) {
605
2/2
✓ Branch 0 taken 322180704 times.
✓ Branch 1 taken 80545176 times.
402725880 for (int j = 0; j < 4; j++) {
606
2/2
✓ Branch 0 taken 116168789 times.
✓ Branch 1 taken 206011915 times.
322180704 if (op->lin.m[i][j].num)
607 116168789 need_in[j] |= need_out[i];
608 }
609 }
610 20136294 break;
611 2943098 case SWS_OP_LUT_3D:
612
2/2
✓ Branch 0 taken 8829294 times.
✓ Branch 1 taken 2943098 times.
11772392 for (int i = 0; i < 3; i++)
613 8829294 need_in[i] = need_out[0] | need_out[1] | need_out[2];
614 2943098 need_in[3] = need_out[3];
615 2943098 break;
616 }
617
618 150847494 memcpy(need_out, need_in, sizeof(need_in));
619 }
620
621 #undef FORWARD
622 #undef RESET
623 13595497 }
624
625 33373871 static void op_uninit(SwsOp *op)
626 {
627
5/5
✓ Branch 0 taken 3753448 times.
✓ Branch 1 taken 1795480 times.
✓ Branch 2 taken 2203204 times.
✓ Branch 3 taken 688466 times.
✓ Branch 4 taken 24933273 times.
33373871 switch (op->op) {
628 3753448 case SWS_OP_READ:
629 3753448 av_refstruct_unref(&op->rw.filter.kernel);
630 3753448 break;
631 1795480 case SWS_OP_DITHER:
632 1795480 av_refstruct_unref(&op->dither.matrix);
633 1795480 break;
634 2203204 case SWS_OP_FILTER_H:
635 case SWS_OP_FILTER_V:
636 2203204 av_refstruct_unref(&op->filter.kernel);
637 2203204 break;
638 688466 case SWS_OP_LUT_3D:
639 688466 av_refstruct_unref(&op->lut3d.lut);
640 688466 break;
641 }
642
643 33373871 *op = (SwsOp) {0};
644 33373871 }
645
646 1040909 SwsOpList *ff_sws_op_list_alloc(void)
647 {
648 1040909 SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1040909 times.
1040909 if (!ops)
650 return NULL;
651
652
2/2
✓ Branch 0 taken 4163636 times.
✓ Branch 1 taken 1040909 times.
5204545 for (int i = 0; i < 4; i++)
653 4163636 ops->plane_src[i] = ops->plane_dst[i] = i;
654 1040909 ff_fmt_clear(&ops->src);
655 1040909 ff_fmt_clear(&ops->dst);
656 1040909 return ops;
657 }
658
659 5403938 void ff_sws_op_list_free(SwsOpList **p_ops)
660 {
661 5403938 SwsOpList *ops = *p_ops;
662
2/2
✓ Branch 0 taken 1735865 times.
✓ Branch 1 taken 3668073 times.
5403938 if (!ops)
663 1735865 return;
664
665
2/2
✓ Branch 0 taken 23630325 times.
✓ Branch 1 taken 3668073 times.
27298398 for (int i = 0; i < ops->num_ops; i++)
666 23630325 op_uninit(&ops->ops[i]);
667
668 3668073 av_freep(&ops->ops);
669 3668073 av_free(ops);
670 3668073 *p_ops = NULL;
671 }
672
673 2627164 SwsOpList *ff_sws_op_list_duplicate(const SwsOpList *ops)
674 {
675 2627164 SwsOpList *copy = av_malloc(sizeof(*copy));
676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2627164 times.
2627164 if (!copy)
677 return NULL;
678
679 2627164 int num = ops->num_ops;
680
1/2
✓ Branch 0 taken 2627164 times.
✗ Branch 1 not taken.
2627164 if (num)
681 2627164 num = 1 << av_ceil_log2(num);
682
683 2627164 *copy = *ops;
684 2627164 copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2627164 times.
2627164 if (!copy->ops) {
686 av_free(copy);
687 return NULL;
688 }
689
690
2/2
✓ Branch 0 taken 20465390 times.
✓ Branch 1 taken 2627164 times.
23092554 for (int i = 0; i < copy->num_ops; i++) {
691 20465390 const SwsOp *op = &copy->ops[i];
692
5/5
✓ Branch 0 taken 2567121 times.
✓ Branch 1 taken 1335042 times.
✓ Branch 2 taken 1603474 times.
✓ Branch 3 taken 511842 times.
✓ Branch 4 taken 14447911 times.
20465390 switch (op->op) {
693 2567121 case SWS_OP_READ:
694
2/2
✓ Branch 0 taken 963725 times.
✓ Branch 1 taken 1603396 times.
2567121 if (op->rw.filter.kernel)
695 963725 av_refstruct_ref(op->rw.filter.kernel);
696 2567121 break;
697 1335042 case SWS_OP_DITHER:
698 1335042 av_refstruct_ref(op->dither.matrix);
699 1335042 break;
700 1603474 case SWS_OP_FILTER_H:
701 case SWS_OP_FILTER_V:
702 1603474 av_refstruct_ref(op->filter.kernel);
703 1603474 break;
704 511842 case SWS_OP_LUT_3D:
705 511842 av_refstruct_ref_c(op->lut3d.lut);
706 511842 break;
707 }
708 }
709
710 2627164 return copy;
711 }
712
713 1665689 const SwsOp *ff_sws_op_list_input(const SwsOpList *ops)
714 {
715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1665689 times.
1665689 if (!ops->num_ops)
716 return NULL;
717
718 1665689 const SwsOp *read = &ops->ops[0];
719
2/2
✓ Branch 0 taken 1647809 times.
✓ Branch 1 taken 17880 times.
1665689 return read->op == SWS_OP_READ ? read : NULL;
720 }
721
722 3315678 const SwsOp *ff_sws_op_list_output(const SwsOpList *ops)
723 {
724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3315678 times.
3315678 if (!ops->num_ops)
725 return NULL;
726
727 3315678 const SwsOp *write = &ops->ops[ops->num_ops - 1];
728
1/2
✓ Branch 0 taken 3315678 times.
✗ Branch 1 not taken.
3315678 return write->op == SWS_OP_WRITE ? write : NULL;
729 }
730
731 6410147 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
732 {
733 6410147 const int end = ops->num_ops - count;
734 av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
735
2/2
✓ Branch 0 taken 9743546 times.
✓ Branch 1 taken 6410147 times.
16153693 for (int i = 0; i < count; i++)
736 9743546 op_uninit(&ops->ops[index + i]);
737
2/2
✓ Branch 0 taken 45598187 times.
✓ Branch 1 taken 6410147 times.
52008334 for (int i = index; i < end; i++)
738 45598187 ops->ops[i] = ops->ops[i + count];
739 6410147 ops->num_ops = end;
740 6410147 }
741
742 12908481 int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
743 {
744 12908481 void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12908481 times.
12908481 if (!ret) {
746 op_uninit(op);
747 return AVERROR(ENOMEM);
748 }
749
750
2/2
✓ Branch 0 taken 6613613 times.
✓ Branch 1 taken 12908481 times.
19522094 for (int i = ops->num_ops - 1; i > index; i--)
751 6613613 ops->ops[i] = ops->ops[i - 1];
752 12908481 ops->ops[index] = *op;
753 12908481 return 0;
754 }
755
756 12029777 int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
757 {
758 12029777 return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
759 }
760
761 1059051 bool ff_sws_op_list_is_noop(const SwsOpList *ops)
762 {
763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1059051 times.
1059051 if (!ops->num_ops)
764 return true;
765
766 1059051 const SwsOp *read = ff_sws_op_list_input(ops);
767 1059051 const SwsOp *write = ff_sws_op_list_output(ops);
768
4/6
✓ Branch 0 taken 1059051 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1059051 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 207805 times.
✓ Branch 5 taken 851246 times.
1059051 if (!read || !write || ops->num_ops > 2 ||
769
2/2
✓ Branch 0 taken 85310 times.
✓ Branch 1 taken 122495 times.
207805 read->type != write->type ||
770
2/2
✓ Branch 0 taken 19876 times.
✓ Branch 1 taken 65434 times.
85310 read->rw.mode != write->rw.mode ||
771
2/2
✓ Branch 0 taken 19796 times.
✓ Branch 1 taken 80 times.
19876 read->rw.elems != write->rw.elems ||
772
2/2
✓ Branch 0 taken 13902 times.
✓ Branch 1 taken 5894 times.
19796 read->rw.frac != write->rw.frac ||
773
3/4
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 13113 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 789 times.
13902 read->rw.filter.op || write->rw.filter.op)
774 1058262 return false;
775
776 /**
777 * Note that this check is unlikely to ever be hit in practice, since it
778 * would imply the existence of planar formats with different plane orders
779 * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
780 * However, the check is cheap and lets me sleep at night.
781 */
782 789 const int num_planes = ff_sws_rw_op_planes(read);
783
2/2
✓ Branch 0 taken 1729 times.
✓ Branch 1 taken 789 times.
2518 for (int i = 0; i < num_planes; i++) {
784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1729 times.
1729 if (ops->plane_src[i] != ops->plane_dst[i])
785 return false;
786 }
787
788 789 return true;
789 }
790
791 19519 int ff_sws_op_list_max_size(const SwsOpList *ops)
792 {
793 19519 int max_size = 0;
794
2/2
✓ Branch 0 taken 144578 times.
✓ Branch 1 taken 19519 times.
164097 for (int i = 0; i < ops->num_ops; i++) {
795 144578 const int size = ff_sws_pixel_type_size(ops->ops[i].type);
796 144578 max_size = FFMAX(max_size, size);
797 }
798
799 19519 return max_size;
800 }
801
802 13190157 uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
803 {
804 13190157 uint32_t mask = 0;
805
2/2
✓ Branch 0 taken 52760628 times.
✓ Branch 1 taken 13190157 times.
65950785 for (int i = 0; i < 4; i++) {
806
2/2
✓ Branch 0 taken 263803140 times.
✓ Branch 1 taken 52760628 times.
316563768 for (int j = 0; j < 5; j++) {
807
2/2
✓ Branch 1 taken 91749429 times.
✓ Branch 2 taken 172053711 times.
263803140 if (av_cmp_q64(c->m[i][j], Q(i == j)))
808 91749429 mask |= SWS_MASK(i, j);
809 }
810 }
811 13190157 return mask;
812 }
813
814 29598872 static char describe_comp_flags(SwsCompFlags flags)
815 {
816
2/2
✓ Branch 0 taken 12184062 times.
✓ Branch 1 taken 17414810 times.
29598872 if (flags & SWS_COMP_GARBAGE)
817 12184062 return 'X';
818
2/2
✓ Branch 0 taken 44851 times.
✓ Branch 1 taken 17369959 times.
17414810 else if (flags & SWS_COMP_ZERO)
819 44851 return '0';
820
2/2
✓ Branch 0 taken 1372460 times.
✓ Branch 1 taken 15997499 times.
17369959 else if (flags & SWS_COMP_SWAPPED)
821 1372460 return 'z';
822
2/2
✓ Branch 0 taken 290634 times.
✓ Branch 1 taken 15706865 times.
15997499 else if (flags & SWS_COMP_CONST)
823 290634 return '$';
824
2/2
✓ Branch 0 taken 288553 times.
✓ Branch 1 taken 15418312 times.
15706865 else if (flags & SWS_COMP_COPY)
825 288553 return '=';
826
2/2
✓ Branch 0 taken 5169560 times.
✓ Branch 1 taken 10248752 times.
15418312 else if (flags & SWS_COMP_EXACT)
827 5169560 return '+';
828 else
829 10248752 return '.';
830 }
831
832 11006442 static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
833 {
834 11006442 av_bprintf(bp, "{");
835
2/2
✓ Branch 0 taken 44025768 times.
✓ Branch 1 taken 11006442 times.
55032210 for (int i = 0; i < 4; i++) {
836
2/2
✓ Branch 0 taken 33019326 times.
✓ Branch 1 taken 11006442 times.
44025768 if (i)
837 33019326 av_bprintf(bp, " ");
838
2/2
✓ Branch 0 taken 29010093 times.
✓ Branch 1 taken 15015675 times.
44025768 av_bprintf(bp, "%s", deps[i] ? ff_sws_comp_mask_str(deps[i]) : "_");
839 }
840 11006442 av_bprintf(bp, "}");
841 11006442 }
842
843 42601381 static void print_q(AVBPrint *bp, const AVRational64 q)
844 {
845
2/2
✓ Branch 0 taken 190492 times.
✓ Branch 1 taken 42410889 times.
42601381 if (!q.den) {
846
2/4
✓ Branch 0 taken 190492 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 190492 times.
190492 av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
847
2/2
✓ Branch 0 taken 34626858 times.
✓ Branch 1 taken 7784031 times.
42410889 } else if (q.den == 1) {
848 34626858 av_bprintf(bp, "%"PRId64, q.num);
849
7/8
✓ Branch 0 taken 4370839 times.
✓ Branch 1 taken 3413192 times.
✓ Branch 2 taken 2489911 times.
✓ Branch 3 taken 1880928 times.
✓ Branch 4 taken 1868916 times.
✓ Branch 5 taken 620995 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1868916 times.
7784031 } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
850 5915115 av_bprintf(bp, "%f", av_q2d_64(q));
851 } else {
852 1868916 av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
853 }
854 42601381 }
855
856 11128616 static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
857 {
858 11128616 av_bprintf(bp, "{");
859
2/2
✓ Branch 0 taken 44514464 times.
✓ Branch 1 taken 11128616 times.
55643080 for (int i = 0; i < 4; i++) {
860
2/2
✓ Branch 0 taken 33385848 times.
✓ Branch 1 taken 11128616 times.
44514464 if (i)
861 33385848 av_bprintf(bp, " ");
862
2/2
✓ Branch 0 taken 14456763 times.
✓ Branch 1 taken 30057701 times.
44514464 if (!SWS_COMP_TEST(mask, i)) {
863 14456763 av_bprintf(bp, "_");
864 } else {
865 30057701 print_q(bp, q4[i]);
866 }
867 }
868 11128616 av_bprintf(bp, "}");
869 11128616 }
870
871 static const char *const rw_mode_names[] = {
872 [SWS_RW_PLANAR] = "planar",
873 [SWS_RW_PACKED] = "packed",
874 [SWS_RW_PALETTE] = "palette"
875 };
876
877 7399718 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
878 {
879 7399718 const char *name = ff_sws_op_type_name(op->op);
880 7399718 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
881
882
15/17
✓ Branch 0 taken 544458 times.
✓ Branch 1 taken 2473943 times.
✓ Branch 2 taken 56707 times.
✓ Branch 3 taken 52701 times.
✓ Branch 4 taken 278535 times.
✓ Branch 5 taken 279431 times.
✓ Branch 6 taken 495143 times.
✓ Branch 7 taken 936955 times.
✓ Branch 8 taken 439196 times.
✓ Branch 9 taken 473186 times.
✓ Branch 10 taken 260839 times.
✓ Branch 11 taken 627184 times.
✓ Branch 12 taken 271060 times.
✓ Branch 13 taken 69932 times.
✓ Branch 14 taken 140448 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
7399718 switch (op->op) {
883 544458 case SWS_OP_INVALID:
884 case SWS_OP_SWAP_BYTES:
885 544458 av_bprintf(bp, "%s", name);
886 544458 break;
887 2473943 case SWS_OP_READ:
888 case SWS_OP_WRITE:
889 2473943 av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
890 2473943 op->rw.elems, rw_mode_names[op->rw.mode],
891 2473943 op->rw.frac);
892
2/2
✓ Branch 0 taken 1868269 times.
✓ Branch 1 taken 605674 times.
2473943 if (!op->rw.filter.op)
893 1868269 break;
894 605674 const SwsFilterWeights *kernel = op->rw.filter.kernel;
895 605674 av_bprintf(bp, " + %d tap %s filter (%c)",
896 605674 kernel->filter_size, kernel->name,
897
2/2
✓ Branch 0 taken 304521 times.
✓ Branch 1 taken 301153 times.
605674 op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
898 605674 break;
899 56707 case SWS_OP_LSHIFT:
900 56707 av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
901 56707 break;
902 52701 case SWS_OP_RSHIFT:
903 52701 av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
904 52701 break;
905 278535 case SWS_OP_PACK:
906 case SWS_OP_UNPACK:
907 278535 av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
908 278535 op->pack.pattern[0], op->pack.pattern[1],
909 278535 op->pack.pattern[2], op->pack.pattern[3]);
910 278535 break;
911 279431 case SWS_OP_CLEAR:
912 279431 av_bprintf(bp, "%-20s: ", name);
913 279431 print_q4(bp, op->clear.value, mask & op->clear.mask);
914 279431 break;
915 495143 case SWS_OP_SWIZZLE:
916 495143 av_bprintf(bp, "%-20s: %d%d%d%d", name,
917 495143 op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
918 495143 break;
919 936955 case SWS_OP_CONVERT:
920 1873910 av_bprintf(bp, "%-20s: %s -> %s%s", name,
921 936955 ff_sws_pixel_type_name(op->type),
922 936955 ff_sws_pixel_type_name(op->convert.to),
923
2/2
✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 935251 times.
936955 op->convert.expand ? " (expand)" : "");
924 936955 break;
925 439196 case SWS_OP_DITHER:
926 439196 av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
927 439196 1 << op->dither.size_log2, 1 << op->dither.size_log2,
928 439196 op->dither.y_offset[0], op->dither.y_offset[1],
929 439196 op->dither.y_offset[2], op->dither.y_offset[3]);
930 439196 break;
931 473186 case SWS_OP_MIN:
932 473186 av_bprintf(bp, "%-20s: x <= ", name);
933 473186 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
934 473186 break;
935 260839 case SWS_OP_MAX:
936 260839 av_bprintf(bp, "%-20s: ", name);
937 260839 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
938 260839 av_bprintf(bp, " <= x");
939 260839 break;
940 627184 case SWS_OP_LINEAR:
941 627184 av_bprintf(bp, "%-20s: [", name);
942
2/2
✓ Branch 0 taken 2508736 times.
✓ Branch 1 taken 627184 times.
3135920 for (int i = 0; i < 4; i++) {
943
2/2
✓ Branch 0 taken 1881552 times.
✓ Branch 1 taken 627184 times.
2508736 av_bprintf(bp, "%s[", i ? " " : "");
944
2/2
✓ Branch 0 taken 12543680 times.
✓ Branch 1 taken 2508736 times.
15052416 for (int j = 0; j < 5; j++) {
945
2/2
✓ Branch 0 taken 10034944 times.
✓ Branch 1 taken 2508736 times.
12543680 av_bprintf(bp, j ? " " : "");
946 12543680 print_q(bp, op->lin.m[i][j]);
947 }
948 2508736 av_bprintf(bp, "]");
949 }
950 627184 av_bprintf(bp, "]");
951 627184 break;
952 271060 case SWS_OP_SCALE:
953 271060 av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
954
2/2
✓ Branch 0 taken 218301 times.
✓ Branch 1 taken 52759 times.
271060 if (op->scale.factor.den != 1)
955 218301 av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
956 271060 break;
957 69932 case SWS_OP_FILTER_H:
958 case SWS_OP_FILTER_V: {
959 69932 const SwsFilterWeights *kernel = op->filter.kernel;
960 69932 av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
961 69932 kernel->src_size, kernel->dst_size,
962 69932 kernel->name, kernel->filter_size);
963 69932 break;
964 }
965 140448 case SWS_OP_LUT_3D:
966
2/2
✓ Branch 0 taken 70224 times.
✓ Branch 1 taken 70224 times.
140448 av_bprintf(bp, "%-20s: %s", name, op->lut3d.dynamic ? "dynamic" : "static");
967 140448 break;
968 case SWS_OP_TYPE_NB:
969 break;
970 }
971 7399718 }
972
973 2473943 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
974 {
975 2473943 bool inorder = true;
976
2/2
✓ Branch 0 taken 5453345 times.
✓ Branch 1 taken 2473943 times.
7927288 for (int i = 0; i < nb_planes; i++)
977 5453345 inorder &= order[i] == i;
978
2/2
✓ Branch 0 taken 2078296 times.
✓ Branch 1 taken 395647 times.
2473943 if (inorder)
979 2078296 return;
980
981 395647 av_bprintf(bp, ", via {");
982
2/2
✓ Branch 0 taken 1126476 times.
✓ Branch 1 taken 395647 times.
1522123 for (int i = 0; i < nb_planes; i++)
983
2/2
✓ Branch 0 taken 730829 times.
✓ Branch 1 taken 395647 times.
1126476 av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
984 395647 av_bprintf(bp, "}");
985 }
986
987 1268117 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
988 const SwsOpList *ops)
989 {
990 AVBPrint bp;
991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1268117 times.
1268117 if (!ops->num_ops) {
992 av_log(log, lev, " (empty)\n");
993 return;
994 }
995
996 1268117 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
997
998
2/2
✓ Branch 0 taken 7399718 times.
✓ Branch 1 taken 1268117 times.
8667835 for (int i = 0; i < ops->num_ops; i++) {
999 7399718 const SwsOp *op = &ops->ops[i];
1000 7399718 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
1001 7399718 av_bprint_clear(&bp);
1002 7399718 av_bprintf(&bp, " [%3s %c%c%c%c] ",
1003 7399718 ff_sws_pixel_type_name(op->type),
1004 7399718 describe_comp_flags(op->comps.flags[0]),
1005 7399718 describe_comp_flags(op->comps.flags[1]),
1006 7399718 describe_comp_flags(op->comps.flags[2]),
1007 7399718 describe_comp_flags(op->comps.flags[3]));
1008
1009 7399718 ff_sws_op_desc(&bp, op);
1010
1011
4/4
✓ Branch 0 taken 6193892 times.
✓ Branch 1 taken 1205826 times.
✓ Branch 2 taken 1268117 times.
✓ Branch 3 taken 4925775 times.
7399718 if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
1012 2473943 const int planes = ff_sws_rw_op_planes(op);
1013 2473943 desc_plane_order(&bp, planes,
1014
2/2
✓ Branch 0 taken 1205826 times.
✓ Branch 1 taken 1268117 times.
2473943 op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
1015 }
1016
1017
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7399718 times.
7399718 av_assert0(av_bprint_is_complete(&bp));
1018 7399718 av_log(log, lev, "%s\n", bp.str);
1019
1020 /* Only print value ranges if any are relevant */
1021 7399718 SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
1022 7399718 ff_sws_comp_mask_q4(op->comps.max);
1023
2/2
✓ Branch 0 taken 5057580 times.
✓ Branch 1 taken 2342138 times.
7399718 if (range_mask & mask) {
1024 5057580 av_bprint_clear(&bp);
1025 5057580 av_bprintf(&bp, " min: ");
1026 5057580 print_q4(&bp, op->comps.min, mask);
1027 5057580 av_bprintf(&bp, ", max: ");
1028 5057580 print_q4(&bp, op->comps.max, mask);
1029
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5057580 times.
5057580 av_assert0(av_bprint_is_complete(&bp));
1030 5057580 av_log(log, lev_extra, "%s\n", bp.str);
1031 }
1032
1033 7399718 bool has_deps = false;
1034
2/2
✓ Branch 0 taken 29598872 times.
✓ Branch 1 taken 7399718 times.
36998590 for (int i = 0; i < 4; i++)
1035
4/4
✓ Branch 0 taken 15310177 times.
✓ Branch 1 taken 14288695 times.
✓ Branch 2 taken 432703 times.
✓ Branch 3 taken 14877474 times.
29598872 has_deps |= op->comps.dep_in[i] || op->comps.dep_out[i];
1036
2/2
✓ Branch 0 taken 5503221 times.
✓ Branch 1 taken 1896497 times.
7399718 if (has_deps) {
1037 5503221 av_bprint_clear(&bp);
1038 5503221 av_bprintf(&bp, " inputs: ");
1039 5503221 print_deps(&bp, op->comps.dep_in);
1040 5503221 av_bprintf(&bp, ", outputs: ");
1041 5503221 print_deps(&bp, op->comps.dep_out);
1042
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5503221 times.
5503221 av_assert0(av_bprint_is_complete(&bp));
1043 5503221 av_log(log, lev_extra, "%s\n", bp.str);
1044 }
1045
1046 }
1047
1048 1268117 av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1049 }
1050