FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops.c
Date: 2026-10-09 17:04:47
Exec Total Coverage
Lines: 615 670 91.8%
Functions: 30 31 96.8%
Branches: 403 458 88.0%

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 15142350 const char *ff_sws_pixel_type_name(SwsPixelType type)
57 {
58
4/7
✓ Branch 0 taken 2094799 times.
✓ Branch 1 taken 5021162 times.
✓ Branch 2 taken 739303 times.
✓ Branch 3 taken 7287086 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
15142350 switch (type) {
59 2094799 case SWS_PIXEL_U8: return "u8";
60 5021162 case SWS_PIXEL_U16: return "u16";
61 739303 case SWS_PIXEL_U32: return "u32";
62 7287086 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 10593029 const char *ff_sws_op_type_name(SwsOpType op)
72 {
73
18/21
✓ Branch 0 taken 1552892 times.
✓ Branch 1 taken 1631025 times.
✓ Branch 2 taken 766956 times.
✓ Branch 3 taken 801087 times.
✓ Branch 4 taken 195822 times.
✓ Branch 5 taken 188055 times.
✓ Branch 6 taken 92823 times.
✓ Branch 7 taken 91499 times.
✓ Branch 8 taken 452006 times.
✓ Branch 9 taken 1412558 times.
✓ Branch 10 taken 675752 times.
✓ Branch 11 taken 428195 times.
✓ Branch 12 taken 335024 times.
✓ Branch 13 taken 1021061 times.
✓ Branch 14 taken 596654 times.
✓ Branch 15 taken 99228 times.
✓ Branch 16 taken 107672 times.
✓ Branch 17 taken 144720 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
10593029 switch (op) {
74 1552892 case SWS_OP_READ: return "SWS_OP_READ";
75 1631025 case SWS_OP_WRITE: return "SWS_OP_WRITE";
76 766956 case SWS_OP_SWAP_BYTES: return "SWS_OP_SWAP_BYTES";
77 801087 case SWS_OP_SWIZZLE: return "SWS_OP_SWIZZLE";
78 195822 case SWS_OP_UNPACK: return "SWS_OP_UNPACK";
79 188055 case SWS_OP_PACK: return "SWS_OP_PACK";
80 92823 case SWS_OP_LSHIFT: return "SWS_OP_LSHIFT";
81 91499 case SWS_OP_RSHIFT: return "SWS_OP_RSHIFT";
82 452006 case SWS_OP_CLEAR: return "SWS_OP_CLEAR";
83 1412558 case SWS_OP_CONVERT: return "SWS_OP_CONVERT";
84 675752 case SWS_OP_MIN: return "SWS_OP_MIN";
85 428195 case SWS_OP_MAX: return "SWS_OP_MAX";
86 335024 case SWS_OP_SCALE: return "SWS_OP_SCALE";
87 1021061 case SWS_OP_LINEAR: return "SWS_OP_LINEAR";
88 596654 case SWS_OP_DITHER: return "SWS_OP_DITHER";
89 99228 case SWS_OP_FILTER_H: return "SWS_OP_FILTER_H";
90 107672 case SWS_OP_FILTER_V: return "SWS_OP_FILTER_V";
91 144720 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 23323721 SwsCompMask ff_sws_comp_mask_q4(const AVRational64 q[4])
101 {
102 23323721 SwsCompMask mask = 0;
103
2/2
✓ Branch 0 taken 93294884 times.
✓ Branch 1 taken 23323721 times.
116618605 for (int i = 0; i < 4; i++) {
104
2/2
✓ Branch 0 taken 41379513 times.
✓ Branch 1 taken 51915371 times.
93294884 if (q[i].den)
105 41379513 mask |= SWS_COMP(i);
106 }
107 23323721 return mask;
108 }
109
110 196525 void ff_sws_comp_mask_swizzle(SwsCompMask *mask, const SwsSwizzleOp *swiz)
111 {
112 196525 const SwsCompMask orig = *mask;
113 196525 SwsCompMask res = 0;
114
2/2
✓ Branch 0 taken 786100 times.
✓ Branch 1 taken 196525 times.
982625 for (int i = 0; i < 4; i++) {
115 786100 const int src = swiz->in[i];
116
2/2
✓ Branch 0 taken 303988 times.
✓ Branch 1 taken 482112 times.
786100 if (SWS_COMP_TEST(orig, src))
117 303988 res |= SWS_COMP(i);
118 }
119
120 196525 *mask = res;
121 196525 }
122
123 96708535 SwsCompMask ff_sws_comp_mask_needed(const SwsOp *op)
124 {
125 96708535 SwsCompMask mask = 0;
126
2/2
✓ Branch 0 taken 386834140 times.
✓ Branch 1 taken 96708535 times.
483542675 for (int i = 0; i < 4; i++) {
127
2/2
✓ Branch 0 taken 254641526 times.
✓ Branch 1 taken 132192614 times.
386834140 if (SWS_OP_NEEDED(op, i))
128 254641526 mask |= SWS_COMP(i);
129 }
130 96708535 return mask;
131 }
132
133 7957777 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 5668863 times.
✓ Branch 1 taken 2274710 times.
✓ Branch 2 taken 14204 times.
✗ Branch 3 not taken.
7957777 switch (op->rw.mode) {
137 5668863 case SWS_RW_PLANAR: return op->rw.elems;
138 2274710 case SWS_RW_PACKED: return 1;
139 14204 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 105462692 static AVRational64 av_min_q64(AVRational64 a, AVRational64 b)
148 {
149
2/2
✓ Branch 1 taken 23980651 times.
✓ Branch 2 taken 81482041 times.
105462692 return ff_cmp_q64(a, b) == 1 ? b : a;
150 }
151
152 87048548 static AVRational64 av_max_q64(AVRational64 a, AVRational64 b)
153 {
154
2/2
✓ Branch 1 taken 12669095 times.
✓ Branch 2 taken 74379453 times.
87048548 return ff_cmp_q64(a, b) == -1 ? b : a;
155 }
156
157 228248195 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 61776654 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5107110 times.
✓ Branch 3 taken 50952 times.
✓ Branch 4 taken 16874522 times.
✓ Branch 5 taken 2552703 times.
✓ Branch 6 taken 2344378 times.
✓ Branch 7 taken 40234897 times.
✓ Branch 8 taken 43743265 times.
✓ Branch 9 taken 99548 times.
✓ Branch 10 taken 26365673 times.
✓ Branch 11 taken 21762137 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7336356 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
228248195 switch (op->op) {
163 61776654 case SWS_OP_READ:
164 case SWS_OP_WRITE:
165 61776654 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 5107110 case SWS_OP_PACK: {
175 av_assert1(ff_sws_pixel_type_is_int(op->type));
176 5107110 ff_sws_pack_op_decode(op, mask, shift);
177 5107110 unsigned val = 0;
178
2/2
✓ Branch 0 taken 20428440 times.
✓ Branch 1 taken 5107110 times.
25535550 for (int i = 0; i < 4; i++)
179 20428440 val |= (x[i].num & mask[i]) << shift[i];
180 5107110 x[0] = Q(val);
181 5107110 return;
182 }
183 50952 case SWS_OP_SWAP_BYTES:
184
1/3
✓ Branch 0 taken 50952 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
50952 switch (op->type) {
185 50952 case SWS_PIXEL_U16:
186
2/2
✓ Branch 0 taken 203808 times.
✓ Branch 1 taken 50952 times.
254760 for (int i = 0; i < 4; i++) {
187 av_assert2(x[i].num >= 0 && x[i].num <= UINT16_MAX);
188 203808 x[i].num = av_bswap16(x[i].num);
189 }
190 50952 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 16874522 case SWS_OP_CLEAR:
201
2/2
✓ Branch 0 taken 67498088 times.
✓ Branch 1 taken 16874522 times.
84372610 for (int i = 0; i < 4; i++) {
202
2/2
✓ Branch 0 taken 19974376 times.
✓ Branch 1 taken 47523712 times.
67498088 if (SWS_COMP_TEST(op->clear.mask, i))
203 19974376 x[i] = op->clear.value[i];
204 }
205 16874522 return;
206 2552703 case SWS_OP_LSHIFT: {
207 av_assert1(ff_sws_pixel_type_is_int(op->type));
208 2552703 AVRational64 mult = Q(1 << op->shift.amount);
209
2/2
✓ Branch 0 taken 10210812 times.
✓ Branch 1 taken 2552703 times.
12763515 for (int i = 0; i < 4; i++)
210
2/2
✓ Branch 0 taken 8741253 times.
✓ Branch 1 taken 1469559 times.
10210812 x[i] = x[i].den ? ff_mul_q64(x[i], mult) : x[i];
211 2552703 return;
212 }
213 2344378 case SWS_OP_RSHIFT: {
214 av_assert1(ff_sws_pixel_type_is_int(op->type));
215
2/2
✓ Branch 0 taken 9377512 times.
✓ Branch 1 taken 2344378 times.
11721890 for (int i = 0; i < 4; i++)
216
2/2
✓ Branch 0 taken 6838208 times.
✓ Branch 1 taken 2539304 times.
9377512 x[i] = x[i].den ? Q((x[i].num / x[i].den) >> op->shift.amount) : x[i];
217 2344378 return;
218 }
219 40234897 case SWS_OP_SWIZZLE: {
220 40234897 const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
221
2/2
✓ Branch 0 taken 160939588 times.
✓ Branch 1 taken 40234897 times.
201174485 for (int i = 0; i < 4; i++)
222 160939588 x[i] = orig[op->swizzle.in[i]];
223 40234897 return;
224 }
225 43743265 case SWS_OP_CONVERT:
226
2/2
✓ Branch 0 taken 34021779 times.
✓ Branch 1 taken 9721486 times.
43743265 if (ff_sws_pixel_type_is_int(op->convert.to)) {
227
2/2
✓ Branch 0 taken 136087116 times.
✓ Branch 1 taken 34021779 times.
170108895 for (int i = 0; i < 4; i++)
228
2/2
✓ Branch 0 taken 119038924 times.
✓ Branch 1 taken 17048192 times.
136087116 x[i] = x[i].den ? Q(x[i].num / x[i].den) : x[i];
229 }
230 43743265 return;
231 99548 case SWS_OP_DITHER:
232 av_assert1(!ff_sws_pixel_type_is_int(op->type));
233
2/2
✓ Branch 0 taken 398192 times.
✓ Branch 1 taken 99548 times.
497740 for (int i = 0; i < 4; i++) {
234
3/4
✓ Branch 0 taken 255035 times.
✓ Branch 1 taken 143157 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 255035 times.
398192 if (op->dither.y_offset[i] >= 0 && x[i].den)
235 ✗ x[i] = ff_add_q64(x[i], ff_make_q64(1, 2));
236 }
237 99548 return;
238 26365673 case SWS_OP_MIN:
239
2/2
✓ Branch 0 taken 105462692 times.
✓ Branch 1 taken 26365673 times.
131828365 for (int i = 0; i < 4; i++)
240 105462692 x[i] = av_min_q64(x[i], op->clamp.limit[i]);
241 26365673 return;
242 21762137 case SWS_OP_MAX:
243
2/2
✓ Branch 0 taken 87048548 times.
✓ Branch 1 taken 21762137 times.
108810685 for (int i = 0; i < 4; i++)
244 87048548 x[i] = av_max_q64(x[i], op->clamp.limit[i]);
245 21762137 return;
246 ✗ case SWS_OP_LINEAR: {
247 ✗ const AVRational64 orig[4] = { x[0], x[1], x[2], x[3] };
248 ✗ for (int i = 0; i < 4; i++) {
249 ✗ AVRational64 sum = op->lin.m[i][4];
250 ✗ for (int j = 0; j < 4; j++)
251 ✗ sum = ff_add_q64(sum, ff_mul_q64(orig[j], op->lin.m[i][j]));
252 ✗ x[i] = sum;
253 }
254 ✗ return;
255 }
256 7336356 case SWS_OP_SCALE:
257
2/2
✓ Branch 0 taken 29345424 times.
✓ Branch 1 taken 7336356 times.
36681780 for (int i = 0; i < 4; i++)
258
2/2
✓ Branch 0 taken 19443054 times.
✓ Branch 1 taken 9902370 times.
29345424 x[i] = x[i].den ? ff_mul_q64(x[i], op->scale.factor) : x[i];
259 7336356 return;
260 ✗ case SWS_OP_FILTER_H:
261 case SWS_OP_FILTER_V:
262 /* Filters have normalized energy by definition, so they don't
263 * conceptually modify individual components */
264 ✗ return;
265 ✗ case SWS_OP_LUT_3D:
266 /* 3D LUTs are treated as a black box, so set those values to NaN */
267 ✗ for (int i = 0; i < 3; i++)
268 ✗ x[i] = (AVRational64) {0};
269 ✗ return;
270 }
271
272 ✗ av_unreachable("Invalid operation type!");
273 }
274
275 enum {
276 SWS_COMP_IDENTITY = SWS_COMP_ZERO | SWS_COMP_EXACT |
277 SWS_COMP_COPY | SWS_COMP_CONST,
278
279 SWS_COMP_DIRTY = ~(SWS_COMP_COPY | SWS_COMP_CONST),
280 };
281
282 /* merge_comp_flags() forms a monoid with SWS_COMP_IDENTITY as the null element */
283 632754261 static SwsCompFlags merge_comp_flags(SwsCompFlags a, SwsCompFlags b)
284 {
285 632754261 const SwsCompFlags flags_or = SWS_COMP_GARBAGE | SWS_COMP_SWAPPED;
286 632754261 const SwsCompFlags flags_and = SWS_COMP_IDENTITY;
287 632754261 return ((a & b) & flags_and) | ((a | b) & flags_or);
288 }
289
290 15126270 static void apply_filter_weights(SwsComps *comps, const SwsComps *prev,
291 const SwsFilterWeights *weights)
292 {
293 15126270 const AVRational64 posw = { weights->sum_positive, SWS_FILTER_SCALE };
294 15126270 const AVRational64 negw = { weights->sum_negative, SWS_FILTER_SCALE };
295
2/2
✓ Branch 0 taken 60505080 times.
✓ Branch 1 taken 15126270 times.
75631350 for (int i = 0; i < 4; i++) {
296 60505080 comps->flags[i] = prev->flags[i] & SWS_COMP_DIRTY;
297 60505080 comps->dep_in[i] = prev->dep_in[i];
298 /* Only point sampling preserves exactness */
299
2/2
✓ Branch 0 taken 59306384 times.
✓ Branch 1 taken 1198696 times.
60505080 if (weights->filter_size != 1)
300 59306384 comps->flags[i] &= ~SWS_COMP_EXACT;
301 /* Update min/max assuming extremes */
302 60505080 comps->min[i] = ff_add_q64(ff_mul_q64(prev->min[i], posw),
303 ff_mul_q64(prev->max[i], negw));
304 60505080 comps->max[i] = ff_add_q64(ff_mul_q64(prev->min[i], negw),
305 ff_mul_q64(prev->max[i], posw));
306 }
307 15126270 }
308
309 /* Infer + propagate known information about components */
310 15806203 void ff_sws_op_list_update_comps(SwsOpList *ops)
311 {
312 15806203 SwsComps prev = { .flags = {
313 SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE, SWS_COMP_GARBAGE,
314 }};
315
316 /* Forwards pass, propagates knowledge about the incoming pixel values */
317
2/2
✓ Branch 0 taken 174194687 times.
✓ Branch 1 taken 15806203 times.
190000890 for (int n = 0; n < ops->num_ops; n++) {
318 174194687 SwsOp *op = &ops->ops[n];
319
320
2/2
✓ Branch 0 taken 60414880 times.
✓ Branch 1 taken 113779807 times.
174194687 switch (op->op) {
321 60414880 case SWS_OP_LINEAR:
322 case SWS_OP_DITHER:
323 case SWS_OP_SWAP_BYTES:
324 case SWS_OP_UNPACK:
325 case SWS_OP_FILTER_H:
326 case SWS_OP_FILTER_V:
327 case SWS_OP_LUT_3D:
328 60414880 break; /* special cases, handled below */
329 113779807 default:
330 113779807 memcpy(op->comps.min, prev.min, sizeof(prev.min));
331 113779807 memcpy(op->comps.max, prev.max, sizeof(prev.max));
332 113779807 ff_sws_apply_op_q(op, op->comps.min);
333 113779807 ff_sws_apply_op_q(op, op->comps.max);
334 113779807 break;
335 }
336
337
2/2
✓ Branch 0 taken 696778748 times.
✓ Branch 1 taken 174194687 times.
870973435 for (int i = 0; i < 4; i++) {
338 696778748 op->comps.flags[i] = SWS_COMP_IDENTITY;
339 696778748 op->comps.dep_in[i] = SWS_COMP_NONE;
340 }
341
342 #define FORWARD(I, J, EXPR) do { \
343 SwsCompFlags flags = prev.flags[J]; \
344 op->comps.flags[I] = merge_comp_flags(op->comps.flags[I], (EXPR)); \
345 op->comps.dep_in[I] |= prev.dep_in[J]; \
346 } while (0)
347
348 #define RESET(I) do { \
349 op->comps.flags[I] = SWS_COMP_GARBAGE; \
350 op->comps.min[I] = op->comps.max[I] = (AVRational64) {0}; \
351 op->comps.dep_in[I] = SWS_COMP_NONE; \
352 } while (0)
353
354
15/16
✓ Branch 0 taken 15082124 times.
✓ Branch 1 taken 10664438 times.
✓ Branch 2 taken 15806203 times.
✓ Branch 3 taken 2446652 times.
✓ Branch 4 taken 23981406 times.
✓ Branch 5 taken 9029116 times.
✓ Branch 6 taken 2520959 times.
✓ Branch 7 taken 2553555 times.
✓ Branch 8 taken 8437261 times.
✓ Branch 9 taken 20019186 times.
✓ Branch 10 taken 21785242 times.
✓ Branch 11 taken 22852954 times.
✓ Branch 12 taken 3668178 times.
✓ Branch 13 taken 12321227 times.
✓ Branch 14 taken 3026186 times.
✗ Branch 15 not taken.
174194687 switch (op->op) {
355 15082124 case SWS_OP_READ:
356 /* Active components are taken from the user-provided values,
357 * other components are explicitly stripped */
358
2/2
✓ Branch 0 taken 38157239 times.
✓ Branch 1 taken 15082124 times.
53239363 for (int i = 0; i < op->rw.elems; i++) {
359 38157239 int idx = 0;
360
3/4
✓ Branch 0 taken 275068 times.
✓ Branch 1 taken 14543001 times.
✓ Branch 2 taken 23339170 times.
✗ Branch 3 not taken.
38157239 switch (op->rw.mode) {
361 275068 case SWS_RW_PALETTE: idx = i; break;
362 14543001 case SWS_RW_PACKED: idx = i; break;
363 23339170 case SWS_RW_PLANAR: idx = ops->plane_src[i]; break;
364 }
365
366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38157239 times.
38157239 av_assert0(!(ops->comps_src.flags[idx] & SWS_COMP_GARBAGE));
367 38157239 op->comps.flags[i] = ops->comps_src.flags[idx] & SWS_COMP_DIRTY;
368 38157239 op->comps.min[i] = ops->comps_src.min[idx];
369 38157239 op->comps.max[i] = ops->comps_src.max[idx];
370 38157239 op->comps.dep_in[i] = SWS_COMP(i);
371
372 /**
373 * Don't mark packed or fractional reads as a copy, because the
374 * read operation implicitly unpacks the data into separate
375 * components. The only case in which op lists involving such
376 * reads can be refcopies is in the case of a true noop, which
377 * is already covered by the no-op check.
378 */
379
4/4
✓ Branch 0 taken 23339170 times.
✓ Branch 1 taken 14818069 times.
✓ Branch 2 taken 23098851 times.
✓ Branch 3 taken 240319 times.
38157239 if (op->rw.mode == SWS_RW_PLANAR && !op->rw.frac)
380 23098851 op->comps.flags[i] |= SWS_COMP_COPY;
381 }
382
383
2/2
✓ Branch 0 taken 2805043 times.
✓ Branch 1 taken 12277081 times.
15082124 if (op->rw.filter.op) {
384 2805043 const SwsComps prev = op->comps;
385 2805043 apply_filter_weights(&op->comps, &prev, op->rw.filter.kernel);
386 }
387 15082124 break;
388 10664438 case SWS_OP_SWAP_BYTES:
389
2/2
✓ Branch 0 taken 42657752 times.
✓ Branch 1 taken 10664438 times.
53322190 for (int i = 0; i < 4; i++) {
390 42657752 FORWARD(i, i, (flags ^ SWS_COMP_SWAPPED) & SWS_COMP_DIRTY);
391 42657752 op->comps.min[i] = prev.min[i];
392 42657752 op->comps.max[i] = prev.max[i];
393 }
394 10664438 break;
395 15806203 case SWS_OP_WRITE:
396
2/2
✓ Branch 0 taken 41354270 times.
✓ Branch 1 taken 15806203 times.
57160473 for (int i = 0; i < op->rw.elems; i++)
397 av_assert1(!(prev.flags[i] & SWS_COMP_GARBAGE));
398
2/2
✓ Branch 0 taken 63224812 times.
✓ Branch 1 taken 15806203 times.
79031015 for (int i = 0; i < 4; i++)
399 63224812 FORWARD(i, i, flags);
400 15806203 break;
401 2446652 case SWS_OP_LSHIFT:
402 case SWS_OP_RSHIFT:
403
2/2
✓ Branch 0 taken 9786608 times.
✓ Branch 1 taken 2446652 times.
12233260 for (int i = 0; i < 4; i++)
404 9786608 FORWARD(i, i, flags & SWS_COMP_DIRTY);
405 2446652 break;
406 23981406 case SWS_OP_MIN:
407 case SWS_OP_MAX: {
408
2/2
✓ Branch 0 taken 13133711 times.
✓ Branch 1 taken 10847695 times.
23981406 AVRational64 *bound = op->op == SWS_OP_MIN ? op->comps.max : op->comps.min;
409
2/2
✓ Branch 0 taken 95925624 times.
✓ Branch 1 taken 23981406 times.
119907030 for (int i = 0; i < 4; i++) {
410 95925624 FORWARD(i, i, flags);
411
2/2
✓ Branch 0 taken 78904940 times.
✓ Branch 1 taken 17020684 times.
95925624 if (op->clamp.limit[i].den)
412 78904940 op->comps.flags[i] &= SWS_COMP_DIRTY;
413
2/2
✓ Branch 0 taken 20959369 times.
✓ Branch 1 taken 74966255 times.
95925624 if (!bound[i].den) /* reset undefined bounds to known range */
414 20959369 bound[i] = op->clamp.limit[i];
415 }
416 23981406 break;
417 }
418 9029116 case SWS_OP_DITHER:
419
2/2
✓ Branch 0 taken 36116464 times.
✓ Branch 1 taken 9029116 times.
45145580 for (int i = 0; i < 4; i++) {
420 36116464 FORWARD(i, i, flags);
421 36116464 op->comps.min[i] = prev.min[i];
422 36116464 op->comps.max[i] = prev.max[i];
423
2/2
✓ Branch 0 taken 5862648 times.
✓ Branch 1 taken 30253816 times.
36116464 if (op->dither.y_offset[i] < 0)
424 5862648 continue;
425 /* Strip zero flag because of the nonzero dithering offset */
426 30253816 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
427 30253816 op->comps.min[i] = ff_add_q64(op->comps.min[i], op->dither.min);
428 30253816 op->comps.max[i] = ff_add_q64(op->comps.max[i], op->dither.max);
429 }
430 9029116 break;
431 2520959 case SWS_OP_UNPACK:
432
2/2
✓ Branch 0 taken 10083836 times.
✓ Branch 1 taken 2520959 times.
12604795 for (int i = 0; i < 4; i++) {
433 10083836 const int pattern = op->pack.pattern[i];
434
2/2
✓ Branch 0 taken 8432168 times.
✓ Branch 1 taken 1651668 times.
10083836 if (pattern) {
435 av_assert1(pattern < 32);
436 8432168 FORWARD(i, 0, flags & SWS_COMP_DIRTY);
437 8432168 op->comps.min[i] = Q(0);
438 8432168 op->comps.max[i] = Q((1ULL << pattern) - 1);
439 } else
440 1651668 RESET(i);
441 }
442 2520959 break;
443 2553555 case SWS_OP_PACK:
444
2/2
✓ Branch 0 taken 10214220 times.
✓ Branch 1 taken 2553555 times.
12767775 for (int i = 0; i < 4; i++) {
445
2/2
✓ Branch 0 taken 8550665 times.
✓ Branch 1 taken 1663555 times.
10214220 if (op->pack.pattern[i])
446 8550665 FORWARD(0, i, flags & SWS_COMP_DIRTY);
447
2/2
✓ Branch 0 taken 7660665 times.
✓ Branch 1 taken 2553555 times.
10214220 if (i > 0) /* clear remaining comps for sanity */
448 7660665 RESET(i);
449 }
450 2553555 break;
451 8437261 case SWS_OP_CLEAR:
452
2/2
✓ Branch 0 taken 33749044 times.
✓ Branch 1 taken 8437261 times.
42186305 for (int i = 0; i < 4; i++) {
453
2/2
✓ Branch 0 taken 9987188 times.
✓ Branch 1 taken 23761856 times.
33749044 if (SWS_COMP_TEST(op->clear.mask, i)) {
454 9987188 op->comps.flags[i] = SWS_COMP_CONST;
455
2/2
✓ Branch 0 taken 5690089 times.
✓ Branch 1 taken 4297099 times.
9987188 if (op->clear.value[i].num == 0)
456 5690089 op->comps.flags[i] |= SWS_COMP_ZERO;
457
1/2
✓ Branch 0 taken 9987188 times.
✗ Branch 1 not taken.
9987188 if (op->clear.value[i].den == 1)
458 9987188 op->comps.flags[i] |= SWS_COMP_EXACT;
459 } else {
460 23761856 FORWARD(i, i, flags);
461 }
462 }
463 8437261 break;
464 20019186 case SWS_OP_SWIZZLE:
465
2/2
✓ Branch 0 taken 80076744 times.
✓ Branch 1 taken 20019186 times.
100095930 for (int i = 0; i < 4; i++)
466 80076744 FORWARD(i, op->swizzle.in[i], flags);
467 20019186 break;
468 21785242 case SWS_OP_CONVERT:
469
2/2
✓ Branch 0 taken 87140968 times.
✓ Branch 1 taken 21785242 times.
108926210 for (int i = 0; i < 4; i++) {
470 87140968 FORWARD(i, i, flags);
471
2/2
✓ Branch 0 taken 52514573 times.
✓ Branch 1 taken 34626395 times.
87140968 if (!(prev.flags[i] & SWS_COMP_EXACT))
472 52514573 op->comps.flags[i] &= SWS_COMP_DIRTY;
473
2/2
✓ Branch 0 taken 67697996 times.
✓ Branch 1 taken 19442972 times.
87140968 if (ff_sws_pixel_type_is_int(op->convert.to))
474 67697996 op->comps.flags[i] |= SWS_COMP_EXACT;
475 }
476 21785242 break;
477 22852954 case SWS_OP_LINEAR:
478
2/2
✓ Branch 0 taken 91411816 times.
✓ Branch 1 taken 22852954 times.
114264770 for (int i = 0; i < 4; i++) {
479 91411816 AVRational64 min = Q(0), max = Q(0);
480 91411816 bool first = true;
481
2/2
✓ Branch 0 taken 365647264 times.
✓ Branch 1 taken 91411816 times.
457059080 for (int j = 0; j < 4; j++) {
482 365647264 const AVRational64 k = op->lin.m[i][j];
483 365647264 AVRational64 mink = ff_mul_q64(prev.min[j], k);
484 365647264 AVRational64 maxk = ff_mul_q64(prev.max[j], k);
485
2/2
✓ Branch 0 taken 132146028 times.
✓ Branch 1 taken 233501236 times.
365647264 if (k.num) {
486 132146028 FORWARD(i, j, flags);
487
2/2
✓ Branch 0 taken 79671600 times.
✓ Branch 1 taken 52474428 times.
132146028 if (k.den != 1) /* fractional coefficient */
488 79671600 op->comps.flags[i] &= ~SWS_COMP_EXACT;
489
2/2
✓ Branch 0 taken 24041737 times.
✓ Branch 1 taken 108104291 times.
132146028 if (k.num < 0)
490 24041737 FFSWAP(AVRational64, mink, maxk);
491 132146028 min = ff_add_q64(min, mink);
492 132146028 max = ff_add_q64(max, maxk);
493
4/4
✓ Branch 0 taken 91364441 times.
✓ Branch 1 taken 40781587 times.
✓ Branch 3 taken 58116247 times.
✓ Branch 4 taken 33248194 times.
132146028 if (!first || ff_cmp_q64(k, Q(1)))
494 98897834 op->comps.flags[i] &= SWS_COMP_DIRTY;
495 132146028 first = false;
496 }
497 }
498
2/2
✓ Branch 0 taken 23990476 times.
✓ Branch 1 taken 67421340 times.
91411816 if (op->lin.m[i][4].num) { /* nonzero offset */
499 23990476 op->comps.flags[i] &= ~SWS_COMP_ZERO & SWS_COMP_DIRTY;
500
2/2
✓ Branch 0 taken 9465518 times.
✓ Branch 1 taken 14524958 times.
23990476 if (op->lin.m[i][4].den != 1) /* fractional offset */
501 9465518 op->comps.flags[i] &= ~SWS_COMP_EXACT;
502 23990476 min = ff_add_q64(min, op->lin.m[i][4]);
503 23990476 max = ff_add_q64(max, op->lin.m[i][4]);
504 }
505 91411816 op->comps.min[i] = min;
506 91411816 op->comps.max[i] = max;
507 }
508 22852954 break;
509 3668178 case SWS_OP_SCALE:
510
2/2
✓ Branch 0 taken 14672712 times.
✓ Branch 1 taken 3668178 times.
18340890 for (int i = 0; i < 4; i++) {
511 14672712 FORWARD(i, i, flags & SWS_COMP_DIRTY);
512
2/2
✓ Branch 0 taken 11668180 times.
✓ Branch 1 taken 3004532 times.
14672712 if (op->scale.factor.den != 1) /* fractional scale */
513 11668180 op->comps.flags[i] &= ~SWS_COMP_EXACT;
514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14672712 times.
14672712 if (op->scale.factor.num < 0)
515 ✗ FFSWAP(AVRational64, op->comps.min[i], op->comps.max[i]);
516 }
517 3668178 break;
518 12321227 case SWS_OP_FILTER_H:
519 case SWS_OP_FILTER_V: {
520 12321227 apply_filter_weights(&op->comps, &prev, op->filter.kernel);
521 12321227 break;
522 }
523 3026186 case SWS_OP_LUT_3D:
524
2/2
✓ Branch 0 taken 9078558 times.
✓ Branch 1 taken 3026186 times.
12104744 for (int i = 0; i < 3; i++) {
525 /* 3x3 dependency matrix; strip all information except
526 * SWS_COMP_GARBAGE (for correctness validation) */
527
2/2
✓ Branch 0 taken 27235674 times.
✓ Branch 1 taken 9078558 times.
36314232 for (int j = 0; j < 3; j++)
528 27235674 FORWARD(i, j, flags & SWS_COMP_GARBAGE);
529 /* LUT output domain is always scaled to full 16-bit range */
530 9078558 op->comps.min[i] = Q(0);
531 9078558 op->comps.max[i] = Q(UINT16_MAX);
532 }
533 /* Pass through alpha channel untouched */
534 3026186 FORWARD(3, 3, flags);
535 3026186 op->comps.min[3] = prev.min[3];
536 3026186 op->comps.max[3] = prev.max[3];
537 3026186 break;
538 case SWS_OP_INVALID:
539 case SWS_OP_TYPE_NB:
540 av_unreachable("Invalid operation type!");
541 }
542
543 174194687 prev = op->comps;
544 }
545
546 /* Backwards pass, solves for output component dependencies */
547 15806203 SwsCompMask need_out[4] = {0};
548
549
2/2
✓ Branch 0 taken 174194687 times.
✓ Branch 1 taken 15806203 times.
190000890 for (int n = ops->num_ops - 1; n >= 0; n--) {
550 174194687 SwsOp *op = &ops->ops[n];
551 174194687 SwsCompMask need_in[4] = {0};
552
553
2/2
✓ Branch 0 taken 696778748 times.
✓ Branch 1 taken 174194687 times.
870973435 for (int i = 0; i < 4; i++) {
554 696778748 op->comps.dep_out[i] = need_out[i];
555
2/2
✓ Branch 0 taken 246329493 times.
✓ Branch 1 taken 450449255 times.
696778748 if (!need_out[i])
556 246329493 RESET(i);
557 }
558
559
8/9
✓ Branch 0 taken 30888327 times.
✓ Branch 1 taken 83896259 times.
✓ Branch 2 taken 2520959 times.
✓ Branch 3 taken 2553555 times.
✓ Branch 4 taken 8437261 times.
✓ Branch 5 taken 20019186 times.
✓ Branch 6 taken 22852954 times.
✓ Branch 7 taken 3026186 times.
✗ Branch 8 not taken.
174194687 switch (op->op) {
560 30888327 case SWS_OP_READ:
561 case SWS_OP_WRITE:
562
2/2
✓ Branch 0 taken 79511509 times.
✓ Branch 1 taken 30888327 times.
110399836 for (int i = 0; i < op->rw.elems; i++)
563
2/2
✓ Branch 0 taken 41354270 times.
✓ Branch 1 taken 38157239 times.
79511509 need_in[i] = (op->op == SWS_OP_WRITE) ? SWS_COMP(i) : 0;
564
2/2
✓ Branch 0 taken 44041799 times.
✓ Branch 1 taken 30888327 times.
74930126 for (int i = op->rw.elems; i < 4; i++)
565 44041799 need_in[i] = need_out[i];
566 30888327 break;
567 83896259 case SWS_OP_SWAP_BYTES:
568 case SWS_OP_LSHIFT:
569 case SWS_OP_RSHIFT:
570 case SWS_OP_CONVERT:
571 case SWS_OP_DITHER:
572 case SWS_OP_MIN:
573 case SWS_OP_MAX:
574 case SWS_OP_SCALE:
575 case SWS_OP_FILTER_H:
576 case SWS_OP_FILTER_V:
577
2/2
✓ Branch 0 taken 335585036 times.
✓ Branch 1 taken 83896259 times.
419481295 for (int i = 0; i < 4; i++)
578 335585036 need_in[i] = need_out[i];
579 83896259 break;
580 2520959 case SWS_OP_UNPACK:
581
4/4
✓ Branch 0 taken 10083836 times.
✓ Branch 1 taken 869291 times.
✓ Branch 2 taken 8432168 times.
✓ Branch 3 taken 1651668 times.
10953127 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
582 8432168 need_in[0] |= need_out[i];
583 2520959 break;
584 2553555 case SWS_OP_PACK:
585
4/4
✓ Branch 0 taken 10214220 times.
✓ Branch 1 taken 890000 times.
✓ Branch 2 taken 8550665 times.
✓ Branch 3 taken 1663555 times.
11104220 for (int i = 0; i < 4 && op->pack.pattern[i]; i++)
586 8550665 need_in[i] = need_out[0];
587 2553555 break;
588 8437261 case SWS_OP_CLEAR:
589
2/2
✓ Branch 0 taken 33749044 times.
✓ Branch 1 taken 8437261 times.
42186305 for (int i = 0; i < 4; i++) {
590
2/2
✓ Branch 0 taken 23761856 times.
✓ Branch 1 taken 9987188 times.
33749044 if (!SWS_COMP_TEST(op->clear.mask, i))
591 23761856 need_in[i] = need_out[i];
592 }
593 8437261 break;
594 20019186 case SWS_OP_SWIZZLE:
595
2/2
✓ Branch 0 taken 80076744 times.
✓ Branch 1 taken 20019186 times.
100095930 for (int i = 0; i < 4; i++)
596 80076744 need_in[op->swizzle.in[i]] |= need_out[i];
597 20019186 break;
598 22852954 case SWS_OP_LINEAR:
599
2/2
✓ Branch 0 taken 91411816 times.
✓ Branch 1 taken 22852954 times.
114264770 for (int i = 0; i < 4; i++) {
600
2/2
✓ Branch 0 taken 365647264 times.
✓ Branch 1 taken 91411816 times.
457059080 for (int j = 0; j < 4; j++) {
601
2/2
✓ Branch 0 taken 132146028 times.
✓ Branch 1 taken 233501236 times.
365647264 if (op->lin.m[i][j].num)
602 132146028 need_in[j] |= need_out[i];
603 }
604 }
605 22852954 break;
606 3026186 case SWS_OP_LUT_3D:
607
2/2
✓ Branch 0 taken 9078558 times.
✓ Branch 1 taken 3026186 times.
12104744 for (int i = 0; i < 3; i++)
608 9078558 need_in[i] = need_out[0] | need_out[1] | need_out[2];
609 3026186 need_in[3] = need_out[3];
610 3026186 break;
611 }
612
613 174194687 memcpy(need_out, need_in, sizeof(need_in));
614 }
615
616 #undef FORWARD
617 #undef RESET
618 15806203 }
619
620 36854305 static void op_uninit(SwsOp *op)
621 {
622
5/5
✓ Branch 0 taken 4127494 times.
✓ Branch 1 taken 1952333 times.
✓ Branch 2 taken 2423119 times.
✓ Branch 3 taken 709618 times.
✓ Branch 4 taken 27641741 times.
36854305 switch (op->op) {
623 4127494 case SWS_OP_READ:
624 4127494 av_refstruct_unref(&op->rw.filter.kernel);
625 4127494 break;
626 1952333 case SWS_OP_DITHER:
627 1952333 av_refstruct_unref(&op->dither.matrix);
628 1952333 break;
629 2423119 case SWS_OP_FILTER_H:
630 case SWS_OP_FILTER_V:
631 2423119 av_refstruct_unref(&op->filter.kernel);
632 2423119 break;
633 709618 case SWS_OP_LUT_3D:
634 709618 av_refstruct_unref(&op->lut3d.lut);
635 709618 break;
636 }
637
638 36854305 *op = (SwsOp) {0};
639 36854305 }
640
641 1158682 SwsOpList *ff_sws_op_list_alloc(void)
642 {
643 1158682 SwsOpList *ops = av_mallocz(sizeof(SwsOpList));
644
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1158682 times.
1158682 if (!ops)
645 ✗ return NULL;
646
647
2/2
✓ Branch 0 taken 4634728 times.
✓ Branch 1 taken 1158682 times.
5793410 for (int i = 0; i < 4; i++)
648 4634728 ops->plane_src[i] = ops->plane_dst[i] = i;
649 1158682 ff_fmt_clear(&ops->src);
650 1158682 ff_fmt_clear(&ops->dst);
651 1158682 return ops;
652 }
653
654 6042467 void ff_sws_op_list_free(SwsOpList **p_ops)
655 {
656 6042467 SwsOpList *ops = *p_ops;
657
2/2
✓ Branch 0 taken 2052579 times.
✓ Branch 1 taken 3989888 times.
6042467 if (!ops)
658 2052579 return;
659
660
2/2
✓ Branch 0 taken 25518591 times.
✓ Branch 1 taken 3989888 times.
29508479 for (int i = 0; i < ops->num_ops; i++)
661 25518591 op_uninit(&ops->ops[i]);
662
663 3989888 av_freep(&ops->ops);
664 3989888 av_free(ops);
665 3989888 *p_ops = NULL;
666 }
667
668 2831206 SwsOpList *ff_sws_op_list_duplicate(const SwsOpList *ops)
669 {
670 2831206 SwsOpList *copy = av_malloc(sizeof(*copy));
671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2831206 times.
2831206 if (!copy)
672 ✗ return NULL;
673
674 2831206 int num = ops->num_ops;
675
1/2
✓ Branch 0 taken 2831206 times.
✗ Branch 1 not taken.
2831206 if (num)
676 2831206 num = 1 << av_ceil_log2(num);
677
678 2831206 *copy = *ops;
679 2831206 copy->ops = av_memdup(ops->ops, num * sizeof(ops->ops[0]));
680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2831206 times.
2831206 if (!copy->ops) {
681 ✗ av_free(copy);
682 ✗ return NULL;
683 }
684
685
2/2
✓ Branch 0 taken 21986529 times.
✓ Branch 1 taken 2831206 times.
24817735 for (int i = 0; i < copy->num_ops; i++) {
686 21986529 const SwsOp *op = &copy->ops[i];
687
5/5
✓ Branch 0 taken 2761647 times.
✓ Branch 1 taken 1426810 times.
✓ Branch 2 taken 1732290 times.
✓ Branch 3 taken 528178 times.
✓ Branch 4 taken 15537604 times.
21986529 switch (op->op) {
688 2761647 case SWS_OP_READ:
689
2/2
✓ Branch 0 taken 1007866 times.
✓ Branch 1 taken 1753781 times.
2761647 if (op->rw.filter.kernel)
690 1007866 av_refstruct_ref(op->rw.filter.kernel);
691 2761647 break;
692 1426810 case SWS_OP_DITHER:
693 1426810 av_refstruct_ref(op->dither.matrix);
694 1426810 break;
695 1732290 case SWS_OP_FILTER_H:
696 case SWS_OP_FILTER_V:
697 1732290 av_refstruct_ref(op->filter.kernel);
698 1732290 break;
699 528178 case SWS_OP_LUT_3D:
700 528178 av_refstruct_ref_c(op->lut3d.lut);
701 528178 break;
702 }
703 }
704
705 2831206 return copy;
706 }
707
708 2075874 const SwsOp *ff_sws_op_list_input(const SwsOpList *ops)
709 {
710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2075874 times.
2075874 if (!ops->num_ops)
711 ✗ return NULL;
712
713 2075874 const SwsOp *read = &ops->ops[0];
714
2/2
✓ Branch 0 taken 2041672 times.
✓ Branch 1 taken 34202 times.
2075874 return read->op == SWS_OP_READ ? read : NULL;
715 }
716
717 4019385 const SwsOp *ff_sws_op_list_output(const SwsOpList *ops)
718 {
719
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4019385 times.
4019385 if (!ops->num_ops)
720 ✗ return NULL;
721
722 4019385 const SwsOp *write = &ops->ops[ops->num_ops - 1];
723
1/2
✓ Branch 0 taken 4019385 times.
✗ Branch 1 not taken.
4019385 return write->op == SWS_OP_WRITE ? write : NULL;
724 }
725
726 7520104 void ff_sws_op_list_remove_at(SwsOpList *ops, int index, int count)
727 {
728 7520104 const int end = ops->num_ops - count;
729 av_assert2(index >= 0 && count >= 0 && index + count <= ops->num_ops);
730
2/2
✓ Branch 0 taken 11335714 times.
✓ Branch 1 taken 7520104 times.
18855818 for (int i = 0; i < count; i++)
731 11335714 op_uninit(&ops->ops[index + i]);
732
2/2
✓ Branch 0 taken 52844566 times.
✓ Branch 1 taken 7520104 times.
60364670 for (int i = index; i < end; i++)
733 52844566 ops->ops[i] = ops->ops[i + count];
734 7520104 ops->num_ops = end;
735 7520104 }
736
737 14867776 int ff_sws_op_list_insert_at(SwsOpList *ops, int index, SwsOp *op)
738 {
739 14867776 void *ret = av_dynarray2_add((void **) &ops->ops, &ops->num_ops, sizeof(*op), NULL);
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14867776 times.
14867776 if (!ret) {
741 ✗ op_uninit(op);
742 ✗ return AVERROR(ENOMEM);
743 }
744
745
2/2
✓ Branch 0 taken 7616196 times.
✓ Branch 1 taken 14867776 times.
22483972 for (int i = ops->num_ops - 1; i > index; i--)
746 7616196 ops->ops[i] = ops->ops[i - 1];
747 14867776 ops->ops[index] = *op;
748 14867776 return 0;
749 }
750
751 13833664 int ff_sws_op_list_append(SwsOpList *ops, SwsOp *op)
752 {
753 13833664 return ff_sws_op_list_insert_at(ops, ops->num_ops, op);
754 }
755
756 1236929 bool ff_sws_op_list_is_noop(const SwsOpList *ops)
757 {
758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1236929 times.
1236929 if (!ops->num_ops)
759 ✗ return true;
760
761 1236929 const SwsOp *read = ff_sws_op_list_input(ops);
762 1236929 const SwsOp *write = ff_sws_op_list_output(ops);
763
4/6
✓ Branch 0 taken 1236929 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1236929 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 235352 times.
✓ Branch 5 taken 1001577 times.
1236929 if (!read || !write || ops->num_ops > 2 ||
764
2/2
✓ Branch 0 taken 96355 times.
✓ Branch 1 taken 138997 times.
235352 read->type != write->type ||
765
2/2
✓ Branch 0 taken 22702 times.
✓ Branch 1 taken 73653 times.
96355 read->rw.mode != write->rw.mode ||
766
2/2
✓ Branch 0 taken 22599 times.
✓ Branch 1 taken 103 times.
22702 read->rw.elems != write->rw.elems ||
767
2/2
✓ Branch 0 taken 16017 times.
✓ Branch 1 taken 6582 times.
22599 read->rw.frac != write->rw.frac ||
768
3/4
✓ Branch 0 taken 834 times.
✓ Branch 1 taken 15183 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 834 times.
16017 read->rw.filter.op || write->rw.filter.op)
769 1236095 return false;
770
771 /**
772 * Note that this check is unlikely to ever be hit in practice, since it
773 * would imply the existence of planar formats with different plane orders
774 * between them, e.g. rgbap <-> gbrap, which doesn't currently exist.
775 * However, the check is cheap and lets me sleep at night.
776 */
777 834 const int num_planes = ff_sws_rw_op_planes(read);
778
2/2
✓ Branch 0 taken 1860 times.
✓ Branch 1 taken 834 times.
2694 for (int i = 0; i < num_planes; i++) {
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1860 times.
1860 if (ops->plane_src[i] != ops->plane_dst[i])
780 ✗ return false;
781 }
782
783 834 return true;
784 }
785
786 ✗ int ff_sws_op_list_max_size(const SwsOpList *ops)
787 {
788 ✗ int max_size = 0;
789 ✗ for (int i = 0; i < ops->num_ops; i++) {
790 ✗ const int size = ff_sws_pixel_type_size(ops->ops[i].type);
791 ✗ max_size = FFMAX(max_size, size);
792 }
793
794 ✗ return max_size;
795 }
796
797 15120143 uint32_t ff_sws_linear_mask(const SwsLinearOp *c)
798 {
799 15120143 uint32_t mask = 0;
800
2/2
✓ Branch 0 taken 60480572 times.
✓ Branch 1 taken 15120143 times.
75600715 for (int i = 0; i < 4; i++) {
801
2/2
✓ Branch 0 taken 302402860 times.
✓ Branch 1 taken 60480572 times.
362883432 for (int j = 0; j < 5; j++) {
802
2/2
✓ Branch 1 taken 105525158 times.
✓ Branch 2 taken 196877702 times.
302402860 if (ff_cmp_q64(c->m[i][j], Q(i == j)))
803 105525158 mask |= SWS_MASK(i, j);
804 }
805 }
806 15120143 return mask;
807 }
808
809 42372116 static char describe_comp_flags(SwsCompFlags flags)
810 {
811
2/2
✓ Branch 0 taken 15289908 times.
✓ Branch 1 taken 27082208 times.
42372116 if (flags & SWS_COMP_GARBAGE)
812 15289908 return 'X';
813
2/2
✓ Branch 0 taken 56386 times.
✓ Branch 1 taken 27025822 times.
27082208 else if (flags & SWS_COMP_ZERO)
814 56386 return '0';
815
2/2
✓ Branch 0 taken 1789818 times.
✓ Branch 1 taken 25236004 times.
27025822 else if (flags & SWS_COMP_SWAPPED)
816 1789818 return 'z';
817
2/2
✓ Branch 0 taken 364609 times.
✓ Branch 1 taken 24871395 times.
25236004 else if (flags & SWS_COMP_CONST)
818 364609 return '$';
819
2/2
✓ Branch 0 taken 434918 times.
✓ Branch 1 taken 24436477 times.
24871395 else if (flags & SWS_COMP_COPY)
820 434918 return '=';
821
2/2
✓ Branch 0 taken 6785082 times.
✓ Branch 1 taken 17651395 times.
24436477 else if (flags & SWS_COMP_EXACT)
822 6785082 return '+';
823 else
824 17651395 return '.';
825 }
826
827 13998436 static void print_deps(AVBPrint *bp, const SwsCompMask *deps)
828 {
829 13998436 av_bprintf(bp, "{");
830
2/2
✓ Branch 0 taken 55993744 times.
✓ Branch 1 taken 13998436 times.
69992180 for (int i = 0; i < 4; i++) {
831
2/2
✓ Branch 0 taken 41995308 times.
✓ Branch 1 taken 13998436 times.
55993744 if (i)
832 41995308 av_bprintf(bp, " ");
833
2/2
✓ Branch 0 taken 36808577 times.
✓ Branch 1 taken 19185167 times.
55993744 av_bprintf(bp, "%s", deps[i] ? ff_sws_comp_mask_str(deps[i]) : "_");
834 }
835 13998436 av_bprintf(bp, "}");
836 13998436 }
837
838 59166447 static void print_q(AVBPrint *bp, const AVRational64 q)
839 {
840
2/2
✓ Branch 0 taken 241563 times.
✓ Branch 1 taken 58924884 times.
59166447 if (!q.den) {
841
2/4
✓ Branch 0 taken 241563 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 241563 times.
241563 av_bprintf(bp, "%s", q.num > 0 ? "inf" : q.num < 0 ? "-inf" : "nan");
842
2/2
✓ Branch 0 taken 48037005 times.
✓ Branch 1 taken 10887879 times.
58924884 } else if (q.den == 1) {
843 48037005 av_bprintf(bp, "%"PRId64, q.num);
844
7/8
✓ Branch 0 taken 6245036 times.
✓ Branch 1 taken 4642843 times.
✓ Branch 2 taken 3578729 times.
✓ Branch 3 taken 2666307 times.
✓ Branch 4 taken 2596445 times.
✓ Branch 5 taken 982284 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2596445 times.
10887879 } else if (q.num > 1000 || q.num < -1000 || q.den > 1000 || q.den < -1000) {
845 8291434 av_bprintf(bp, "%f", ff_q2d_64(q));
846 } else {
847 2596445 av_bprintf(bp, "%"PRId64"/%"PRId64, q.num, q.den);
848 }
849 59166447 }
850
851 14400305 static void print_q4(AVBPrint *bp, const AVRational64 q4[4], SwsCompMask mask)
852 {
853 14400305 av_bprintf(bp, "{");
854
2/2
✓ Branch 0 taken 57601220 times.
✓ Branch 1 taken 14400305 times.
72001525 for (int i = 0; i < 4; i++) {
855
2/2
✓ Branch 0 taken 43200915 times.
✓ Branch 1 taken 14400305 times.
57601220 if (i)
856 43200915 av_bprintf(bp, " ");
857
2/2
✓ Branch 0 taken 18855993 times.
✓ Branch 1 taken 38745227 times.
57601220 if (!SWS_COMP_TEST(mask, i)) {
858 18855993 av_bprintf(bp, "_");
859 } else {
860 38745227 print_q(bp, q4[i]);
861 }
862 }
863 14400305 av_bprintf(bp, "}");
864 14400305 }
865
866 static const char *const rw_mode_names[] = {
867 [SWS_RW_PLANAR] = "planar",
868 [SWS_RW_PACKED] = "packed",
869 [SWS_RW_PALETTE] = "palette"
870 };
871
872 10593029 void ff_sws_op_desc(AVBPrint *bp, const SwsOp *op)
873 {
874 10593029 const char *name = ff_sws_op_type_name(op->op);
875 10593029 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
876
877
15/17
✓ Branch 0 taken 766956 times.
✓ Branch 1 taken 3183917 times.
✓ Branch 2 taken 92823 times.
✓ Branch 3 taken 91499 times.
✓ Branch 4 taken 383877 times.
✓ Branch 5 taken 452006 times.
✓ Branch 6 taken 801087 times.
✓ Branch 7 taken 1412558 times.
✓ Branch 8 taken 596654 times.
✓ Branch 9 taken 675752 times.
✓ Branch 10 taken 428195 times.
✓ Branch 11 taken 1021061 times.
✓ Branch 12 taken 335024 times.
✓ Branch 13 taken 206900 times.
✓ Branch 14 taken 144720 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
10593029 switch (op->op) {
878 766956 case SWS_OP_INVALID:
879 case SWS_OP_SWAP_BYTES:
880 766956 av_bprintf(bp, "%s", name);
881 766956 break;
882 3183917 case SWS_OP_READ:
883 case SWS_OP_WRITE:
884 3183917 av_bprintf(bp, "%-20s: %d elem(s) %s >> %d", name,
885 3183917 op->rw.elems, rw_mode_names[op->rw.mode],
886 3183917 op->rw.frac);
887
2/2
✓ Branch 0 taken 2508259 times.
✓ Branch 1 taken 675658 times.
3183917 if (!op->rw.filter.op)
888 2508259 break;
889 675658 const SwsFilterWeights *kernel = op->rw.filter.kernel;
890 675658 av_bprintf(bp, " + %d tap %s filter (%c)",
891 675658 kernel->filter_size, kernel->name,
892
2/2
✓ Branch 0 taken 343408 times.
✓ Branch 1 taken 332250 times.
675658 op->rw.filter.op == SWS_OP_FILTER_H ? 'H' : 'V');
893 675658 break;
894 92823 case SWS_OP_LSHIFT:
895 92823 av_bprintf(bp, "%-20s: << %u", name, op->shift.amount);
896 92823 break;
897 91499 case SWS_OP_RSHIFT:
898 91499 av_bprintf(bp, "%-20s: >> %u", name, op->shift.amount);
899 91499 break;
900 383877 case SWS_OP_PACK:
901 case SWS_OP_UNPACK:
902 383877 av_bprintf(bp, "%-20s: {%d %d %d %d}", name,
903 383877 op->pack.pattern[0], op->pack.pattern[1],
904 383877 op->pack.pattern[2], op->pack.pattern[3]);
905 383877 break;
906 452006 case SWS_OP_CLEAR:
907 452006 av_bprintf(bp, "%-20s: ", name);
908 452006 print_q4(bp, op->clear.value, mask & op->clear.mask);
909 452006 break;
910 801087 case SWS_OP_SWIZZLE:
911 801087 av_bprintf(bp, "%-20s: %d%d%d%d", name,
912 801087 op->swizzle.x, op->swizzle.y, op->swizzle.z, op->swizzle.w);
913 801087 break;
914 1412558 case SWS_OP_CONVERT:
915 1412558 av_bprintf(bp, "%-20s: %s -> %s", name,
916 1412558 ff_sws_pixel_type_name(op->type),
917 1412558 ff_sws_pixel_type_name(op->convert.to));
918 1412558 break;
919 596654 case SWS_OP_DITHER:
920 596654 av_bprintf(bp, "%-20s: %dx%d matrix + {%d %d %d %d}", name,
921 596654 1 << op->dither.size_log2, 1 << op->dither.size_log2,
922 596654 op->dither.y_offset[0], op->dither.y_offset[1],
923 596654 op->dither.y_offset[2], op->dither.y_offset[3]);
924 596654 break;
925 675752 case SWS_OP_MIN:
926 675752 av_bprintf(bp, "%-20s: x <= ", name);
927 675752 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
928 675752 break;
929 428195 case SWS_OP_MAX:
930 428195 av_bprintf(bp, "%-20s: ", name);
931 428195 print_q4(bp, op->clamp.limit, mask & ff_sws_comp_mask_q4(op->clamp.limit));
932 428195 av_bprintf(bp, " <= x");
933 428195 break;
934 1021061 case SWS_OP_LINEAR:
935 1021061 av_bprintf(bp, "%-20s: [", name);
936
2/2
✓ Branch 0 taken 4084244 times.
✓ Branch 1 taken 1021061 times.
5105305 for (int i = 0; i < 4; i++) {
937
2/2
✓ Branch 0 taken 3063183 times.
✓ Branch 1 taken 1021061 times.
4084244 av_bprintf(bp, "%s[", i ? " " : "");
938
2/2
✓ Branch 0 taken 20421220 times.
✓ Branch 1 taken 4084244 times.
24505464 for (int j = 0; j < 5; j++) {
939
2/2
✓ Branch 0 taken 16336976 times.
✓ Branch 1 taken 4084244 times.
20421220 av_bprintf(bp, j ? " " : "");
940 20421220 print_q(bp, op->lin.m[i][j]);
941 }
942 4084244 av_bprintf(bp, "]");
943 }
944 1021061 av_bprintf(bp, "]");
945 1021061 break;
946 335024 case SWS_OP_SCALE:
947 335024 av_bprintf(bp, "%-20s: * %"PRId64, name, op->scale.factor.num);
948
2/2
✓ Branch 0 taken 268174 times.
✓ Branch 1 taken 66850 times.
335024 if (op->scale.factor.den != 1)
949 268174 av_bprintf(bp, "/%"PRId64, op->scale.factor.den);
950 335024 break;
951 206900 case SWS_OP_FILTER_H:
952 case SWS_OP_FILTER_V: {
953 206900 const SwsFilterWeights *kernel = op->filter.kernel;
954 206900 av_bprintf(bp, "%-20s: %d -> %d %s (%d taps)", name,
955 206900 kernel->src_size, kernel->dst_size,
956 206900 kernel->name, kernel->filter_size);
957 206900 break;
958 }
959 144720 case SWS_OP_LUT_3D:
960
2/2
✓ Branch 0 taken 72360 times.
✓ Branch 1 taken 72360 times.
144720 av_bprintf(bp, "%-20s: %s", name, op->lut3d.dynamic ? "dynamic" : "static");
961 144720 break;
962 ✗ case SWS_OP_TYPE_NB:
963 ✗ break;
964 }
965 10593029 }
966
967 3183917 static void desc_plane_order(AVBPrint *bp, int nb_planes, const uint8_t *order)
968 {
969 3183917 bool inorder = true;
970
2/2
✓ Branch 0 taken 6938380 times.
✓ Branch 1 taken 3183917 times.
10122297 for (int i = 0; i < nb_planes; i++)
971 6938380 inorder &= order[i] == i;
972
2/2
✓ Branch 0 taken 2709163 times.
✓ Branch 1 taken 474754 times.
3183917 if (inorder)
973 2709163 return;
974
975 474754 av_bprintf(bp, ", via {");
976
2/2
✓ Branch 0 taken 1345870 times.
✓ Branch 1 taken 474754 times.
1820624 for (int i = 0; i < nb_planes; i++)
977
2/2
✓ Branch 0 taken 871116 times.
✓ Branch 1 taken 474754 times.
1345870 av_bprintf(bp, "%s%d", i ? ", " : "", order[i]);
978 474754 av_bprintf(bp, "}");
979 }
980
981 1631025 void ff_sws_op_list_print(void *log, int lev, int lev_extra,
982 const SwsOpList *ops)
983 {
984 AVBPrint bp;
985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1631025 times.
1631025 if (!ops->num_ops) {
986 ✗ av_log(log, lev, " (empty)\n");
987 ✗ return;
988 }
989
990 1631025 av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
991
992
2/2
✓ Branch 0 taken 10593029 times.
✓ Branch 1 taken 1631025 times.
12224054 for (int i = 0; i < ops->num_ops; i++) {
993 10593029 const SwsOp *op = &ops->ops[i];
994 10593029 const SwsCompMask mask = ff_sws_comp_mask_needed(op);
995 10593029 av_bprint_clear(&bp);
996 10593029 av_bprintf(&bp, " [%3s %c%c%c%c] ",
997 10593029 ff_sws_pixel_type_name(op->type),
998 10593029 describe_comp_flags(op->comps.flags[0]),
999 10593029 describe_comp_flags(op->comps.flags[1]),
1000 10593029 describe_comp_flags(op->comps.flags[2]),
1001 10593029 describe_comp_flags(op->comps.flags[3]));
1002
1003 10593029 ff_sws_op_desc(&bp, op);
1004
1005
4/4
✓ Branch 0 taken 9040137 times.
✓ Branch 1 taken 1552892 times.
✓ Branch 2 taken 1631025 times.
✓ Branch 3 taken 7409112 times.
10593029 if (op->op == SWS_OP_READ || op->op == SWS_OP_WRITE) {
1006 3183917 const int planes = ff_sws_rw_op_planes(op);
1007 3183917 desc_plane_order(&bp, planes,
1008
2/2
✓ Branch 0 taken 1552892 times.
✓ Branch 1 taken 1631025 times.
3183917 op->op == SWS_OP_READ ? ops->plane_src : ops->plane_dst);
1009 }
1010
1011
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10593029 times.
10593029 av_assert0(av_bprint_is_complete(&bp));
1012 10593029 av_log(log, lev, "%s\n", bp.str);
1013
1014 /* Only print value ranges if any are relevant */
1015 10593029 SwsCompMask range_mask = ff_sws_comp_mask_q4(op->comps.min) |
1016 10593029 ff_sws_comp_mask_q4(op->comps.max);
1017
2/2
✓ Branch 0 taken 6422176 times.
✓ Branch 1 taken 4170853 times.
10593029 if (range_mask & mask) {
1018 6422176 av_bprint_clear(&bp);
1019 6422176 av_bprintf(&bp, " min: ");
1020 6422176 print_q4(&bp, op->comps.min, mask);
1021 6422176 av_bprintf(&bp, ", max: ");
1022 6422176 print_q4(&bp, op->comps.max, mask);
1023
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6422176 times.
6422176 av_assert0(av_bprint_is_complete(&bp));
1024 6422176 av_log(log, lev_extra, "%s\n", bp.str);
1025 }
1026
1027 10593029 bool has_deps = false;
1028
2/2
✓ Branch 0 taken 42372116 times.
✓ Branch 1 taken 10593029 times.
52965145 for (int i = 0; i < 4; i++)
1029
4/4
✓ Branch 0 taken 24229315 times.
✓ Branch 1 taken 18142801 times.
✓ Branch 2 taken 522975 times.
✓ Branch 3 taken 23706340 times.
42372116 has_deps |= op->comps.dep_in[i] || op->comps.dep_out[i];
1030
2/2
✓ Branch 0 taken 6999218 times.
✓ Branch 1 taken 3593811 times.
10593029 if (has_deps) {
1031 6999218 av_bprint_clear(&bp);
1032 6999218 av_bprintf(&bp, " inputs: ");
1033 6999218 print_deps(&bp, op->comps.dep_in);
1034 6999218 av_bprintf(&bp, ", outputs: ");
1035 6999218 print_deps(&bp, op->comps.dep_out);
1036
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6999218 times.
6999218 av_assert0(av_bprint_is_complete(&bp));
1037 6999218 av_log(log, lev_extra, "%s\n", bp.str);
1038 }
1039
1040 }
1041
1042 1631025 av_log(log, lev, " ('X' unused, 'z' byteswapped, '=' copied, '$' const, '+' integer, '0' zero)\n");
1043 }
1044