../../../ffmpeg/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
650 / 706
92.1%
Branches:
471 / 536
87.9%
Functions:
20 / 20
100.0%

libswscale/ops_optimizer.c
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/bswap.h"
24 #include "libavutil/rational.h"
25
26 #include "ops.h"
27 #include "ops_internal.h"
28
29 #define RET(x) \
30 do { \
31 if ((ret = (x)) < 0) \
32 return ret; \
33 } while (0)
34
35 /**
36 * Try to commute a clear op with the next operation. Makes any adjustments
37 * to the operations as needed, but does not perform the actual commutation.
38 *
39 * Returns whether successful.
40 */
41 2353508 static bool op_commute_clear(SwsOp *op, SwsOp *next)
42 {
43 av_assert1(op->op == SWS_OP_CLEAR);
44
5/8
✓ Branch 2 → 3 taken 279582 times.
✓ Branch 2 → 6 taken 441257 times.
✗ Branch 2 → 8 not taken.
✓ Branch 2 → 12 taken 326156 times.
✓ Branch 2 → 18 taken 114912 times.
✓ Branch 2 → 23 taken 1191601 times.
✗ Branch 2 → 24 not taken.
✗ Branch 2 → 25 not taken.
2353508 switch (next->op) {
45 279582 case SWS_OP_CONVERT:
46
2/2
✓ Branch 5 → 4 taken 1118328 times.
✓ Branch 5 → 6 taken 279582 times.
1397910 for (int i = 0; i < 4; i++)
47 1118328 op->clear.type[i] = next->convert.to;
48 av_fallthrough;
49 case SWS_OP_LSHIFT:
50 case SWS_OP_RSHIFT:
51 case SWS_OP_DITHER:
52 case SWS_OP_MIN:
53 case SWS_OP_MAX:
54 case SWS_OP_SCALE:
55 case SWS_OP_READ:
56 720839 ff_sws_apply_op_q(next, op->clear.value);
57 720839 return true;
58 ✗ case SWS_OP_FILTER_H:
59 case SWS_OP_FILTER_V:
60
0/2
✗ Branch 10 → 9 not taken.
✗ Branch 10 → 11 not taken.
✗ for (int i = 0; i < 4; i++)
61 ✗ op->clear.type[i] = next->filter.type;
62 ✗ return true;
63 326156 case SWS_OP_SWIZZLE: {
64 326156 const SwsClearOp orig = op->clear;
65
2/2
✓ Branch 14 → 13 taken 1304624 times.
✓ Branch 14 → 15 taken 326156 times.
1630780 for (int i = 0; i < 4; i++)
66 1304624 op->clear.type[i] = orig.type[next->swizzle.in[i]];
67 326156 ff_sws_comp_mask_swizzle(&op->clear.mask, &next->swizzle);
68 326156 ff_sws_apply_op_q(next, op->clear.value);
69 326156 return true;
70 }
71 114912 case SWS_OP_SWAP_BYTES:
72
2/2
✓ Branch 19 → 20 taken 84218 times.
✓ Branch 19 → 22 taken 30694 times.
114912 switch (ff_sws_op_input_type(next)) {
73 84218 case SWS_PIXEL_U16:
74 case SWS_PIXEL_U32:
75 84218 ff_sws_apply_op_q(next, op->clear.value); /* always representable */
76 84218 return true;
77 30694 default:
78 30694 return false;
79 }
80 1191601 case SWS_OP_INVALID:
81 case SWS_OP_WRITE:
82 case SWS_OP_LINEAR:
83 case SWS_OP_PACK:
84 case SWS_OP_UNPACK:
85 case SWS_OP_CLEAR:
86 case SWS_OP_LUT_3D:
87 1191601 return false;
88 ✗ case SWS_OP_TYPE_NB:
89 ✗ break;
90 }
91
92 ✗ av_unreachable("Invalid operation type!");
93 return false;
94 }
95
96 /**
97 * Try to commute a swizzle op with the next operation. Makes any adjustments
98 * to the operations as needed, but does not perform the actual commutation.
99 *
100 * Returns whether successful.
101 */
102 2843796 static bool op_commute_swizzle(SwsOp *op, SwsOp *next)
103 {
104 2843796 bool seen[4] = {0};
105
106 av_assert1(op->op == SWS_OP_SWIZZLE);
107
4/6
✓ Branch 2 → 3 taken 953064 times.
✓ Branch 2 → 4 taken 186100 times.
✓ Branch 2 → 16 taken 134937 times.
✓ Branch 2 → 27 taken 1569695 times.
✗ Branch 2 → 28 not taken.
✗ Branch 2 → 29 not taken.
2843796 switch (next->op) {
108 953064 case SWS_OP_CONVERT:
109 case SWS_OP_SWAP_BYTES:
110 case SWS_OP_LSHIFT:
111 case SWS_OP_RSHIFT:
112 case SWS_OP_SCALE:
113 case SWS_OP_FILTER_H:
114 case SWS_OP_FILTER_V:
115 953064 return true;
116
117 /**
118 * We can commute per-channel ops only if the per-channel constants are the
119 * same for all duplicated channels; e.g.:
120 * SWIZZLE {0, 0, 0, 3}
121 * NEXT {x, x, x, w}
122 * ->
123 * NEXT {x, _, _, w}
124 * SWIZZLE {0, 0, 0, 3}
125 */
126 186100 case SWS_OP_MIN:
127 case SWS_OP_MAX: {
128 186100 const SwsClampOp c = next->clamp;
129
2/2
✓ Branch 13 → 5 taken 744400 times.
✓ Branch 13 → 14 taken 186100 times.
930500 for (int i = 0; i < 4; i++) {
130
2/2
✓ Branch 5 → 6 taken 172243 times.
✓ Branch 5 → 7 taken 572157 times.
744400 if (!SWS_OP_NEEDED(op, i))
131 172243 continue;
132 572157 const int j = op->swizzle.in[i];
133
3/4
✓ Branch 7 → 8 taken 121750 times.
✓ Branch 7 → 11 taken 450407 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 121750 times.
572157 if (seen[j] && ff_cmp_q64(next->clamp.limit[j], c.limit[i]))
134 ✗ return false;
135 572157 next->clamp.limit[j] = c.limit[i];
136 572157 seen[j] = true;
137 }
138 186100 return true;
139 }
140
141 134937 case SWS_OP_DITHER: {
142 134937 const SwsDitherOp d = next->dither;
143
2/2
✓ Branch 24 → 17 taken 506328 times.
✓ Branch 24 → 25 taken 118227 times.
624555 for (int i = 0; i < 4; i++) {
144
2/2
✓ Branch 17 → 18 taken 110194 times.
✓ Branch 17 → 19 taken 396134 times.
506328 if (!SWS_OP_NEEDED(op, i))
145 110194 continue;
146 396134 const int j = op->swizzle.in[i];
147
4/4
✓ Branch 19 → 20 taken 72896 times.
✓ Branch 19 → 22 taken 323238 times.
✓ Branch 20 → 21 taken 16710 times.
✓ Branch 20 → 22 taken 56186 times.
396134 if (seen[j] && next->dither.y_offset[j] != d.y_offset[i])
148 16710 return false;
149 379424 next->dither.y_offset[j] = d.y_offset[i];
150 379424 seen[j] = true;
151 }
152 118227 return true;
153 }
154
155 1569695 case SWS_OP_INVALID:
156 case SWS_OP_READ:
157 case SWS_OP_WRITE:
158 case SWS_OP_SWIZZLE:
159 case SWS_OP_CLEAR:
160 case SWS_OP_LINEAR:
161 case SWS_OP_PACK:
162 case SWS_OP_UNPACK:
163 case SWS_OP_LUT_3D:
164 1569695 return false;
165 ✗ case SWS_OP_TYPE_NB:
166 ✗ break;
167 }
168
169 ✗ av_unreachable("Invalid operation type!");
170 return false;
171 }
172
173 /**
174 * Try to commute a filter op with the previous operation. Makes any
175 * adjustments to the operations as needed, but does not perform the actual
176 * commutation.
177 *
178 * Returns whether successful.
179 */
180 18928268 static bool op_commute_filter(SwsOp *op, SwsOp *prev)
181 {
182
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 18928268 times.
18928268 av_assert0(!ff_sws_pixel_type_is_int(op->filter.type));
183
184
3/5
✓ Branch 5 → 6 taken 583127 times.
✓ Branch 5 → 7 taken 1690012 times.
✓ Branch 5 → 11 taken 16655129 times.
✗ Branch 5 → 12 not taken.
✗ Branch 5 → 13 not taken.
18928268 switch (prev->op) {
185 583127 case SWS_OP_SWIZZLE:
186 case SWS_OP_SCALE:
187 case SWS_OP_DITHER:
188 583127 return true;
189 1690012 case SWS_OP_LINEAR:
190
2/2
✓ Branch 9 → 8 taken 6760048 times.
✓ Branch 9 → 10 taken 1690012 times.
8450060 for (int i = 0; i < 4; i++)
191 6760048 prev->lin.type[i] = op->filter.type;
192 1690012 return true;
193 16655129 case SWS_OP_CONVERT:
194 case SWS_OP_INVALID:
195 case SWS_OP_READ:
196 case SWS_OP_WRITE:
197 case SWS_OP_SWAP_BYTES:
198 case SWS_OP_UNPACK:
199 case SWS_OP_PACK:
200 case SWS_OP_LSHIFT:
201 case SWS_OP_RSHIFT:
202 case SWS_OP_CLEAR:
203 case SWS_OP_MIN:
204 case SWS_OP_MAX:
205 case SWS_OP_FILTER_H:
206 case SWS_OP_FILTER_V:
207 case SWS_OP_LUT_3D:
208 16655129 return false;
209 ✗ case SWS_OP_TYPE_NB:
210 ✗ break;
211 }
212
213 ✗ av_unreachable("Invalid operation type!");
214 return false;
215 }
216
217 /* returns log2(x) only if x is a power of two, or 0 otherwise */
218 1862300 static int exact_log2(const int x)
219 {
220 int p;
221
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1862300 times.
1862300 if (x <= 0)
222 ✗ return 0;
223 1862300 p = av_log2(x);
224
2/2
✓ Branch 4 → 5 taken 752592 times.
✓ Branch 4 → 6 taken 1109708 times.
1862300 return (1 << p) == x ? p : 0;
225 }
226
227 4885255 static int exact_log2_q64(const AVRational64 x)
228 {
229
2/2
✓ Branch 2 → 3 taken 998543 times.
✓ Branch 2 → 5 taken 3886712 times.
4885255 if (x.den == 1)
230 998543 return exact_log2(x.num);
231
2/2
✓ Branch 5 → 6 taken 863757 times.
✓ Branch 5 → 8 taken 3022955 times.
3886712 else if (x.num == 1)
232 863757 return -exact_log2(x.den);
233 else
234 3022955 return 0;
235 }
236
237 /**
238 * If a linear operation can be reduced to a scalar multiplication, returns
239 * the corresponding scaling factor, or 0 otherwise.
240 */
241 6718656 static bool extract_scalar(const SwsLinearOp *c,
242 const SwsOpPad outputs[4], const SwsOpPad inputs[4],
243 SwsScaleOp *out_scale)
244 {
245 6718656 SwsScaleOp scale = {0};
246
247 /* There are components not on the main diagonal */
248
2/2
✓ Branch 3 → 4 taken 4769712 times.
✓ Branch 3 → 5 taken 1948944 times.
6718656 if (ff_sws_linear_mask(c) & ~SWS_MASK_DIAG4)
249 4769712 return false;
250
251
2/2
✓ Branch 16 → 6 taken 6252766 times.
✓ Branch 16 → 17 taken 514120 times.
6766886 for (int i = 0; i < 4; i++) {
252 6252766 const AVRational64 s = c->m[i][i];
253
3/4
✓ Branch 6 → 7 taken 6252766 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 8 taken 524481 times.
✓ Branch 7 → 9 taken 5728285 times.
6252766 if ((inputs[i].flags & SWS_COMP_ZERO) || !outputs[i].dep_out)
254 524481 continue;
255
4/4
✓ Branch 9 → 10 taken 3779341 times.
✓ Branch 9 → 13 taken 1948944 times.
✓ Branch 11 → 12 taken 1434824 times.
✓ Branch 11 → 13 taken 2344517 times.
5728285 if (scale.factor.den && ff_cmp_q64(s, scale.factor))
256 1434824 return false;
257 4293461 scale.factor = s;
258 }
259
260
1/2
✓ Branch 17 → 18 taken 514120 times.
✗ Branch 17 → 19 not taken.
514120 if (scale.factor.den)
261 514120 *out_scale = scale;
262 514120 return scale.factor.den;
263 }
264
265 /* Extracts an integer clear operation (subset) from the given linear op. */
266 7059769 static bool extract_constant_rows(SwsLinearOp *c, const SwsOpPad inputs[4],
267 SwsClearOp *out_clear)
268 {
269 7059769 const uint32_t mask = ff_sws_linear_mask(c);
270 7059769 SwsClearOp clear = {0};
271 7059769 bool ret = false;
272
273
2/2
✓ Branch 18 → 4 taken 28239076 times.
✓ Branch 18 → 19 taken 7059769 times.
35298845 for (int i = 0; i < 4; i++) {
274 28239076 bool const_row = c->m[i][4].den == 1; /* offset is integer */
275
2/2
✓ Branch 10 → 5 taken 112956304 times.
✓ Branch 10 → 11 taken 28239076 times.
141195380 for (int j = 0; j < 4; j++) {
276
2/2
✓ Branch 5 → 6 taken 46292855 times.
✓ Branch 5 → 7 taken 66663449 times.
159249159 const_row &= c->m[i][j].num == 0 || /* scalar is zero */
277
2/2
✓ Branch 6 → 7 taken 696539 times.
✓ Branch 6 → 8 taken 45596316 times.
46292855 (inputs[j].flags & SWS_COMP_ZERO); /* input is zero */
278 }
279
4/4
✓ Branch 11 → 12 taken 431994 times.
✓ Branch 11 → 17 taken 27807082 times.
✓ Branch 12 → 13 taken 402263 times.
✓ Branch 12 → 17 taken 29731 times.
28239076 if (const_row && (mask & SWS_MASK_ROW(i))) {
280 402263 clear.mask |= SWS_COMP(i);
281 402263 clear.value[i] = c->m[i][4];
282 402263 clear.type[i] = c->type[i];
283
2/2
✓ Branch 15 → 14 taken 2011315 times.
✓ Branch 15 → 16 taken 402263 times.
2413578 for (int j = 0; j < 5; j++)
284 2011315 c->m[i][j] = Q(i == j);
285 402263 ret = true;
286 }
287 }
288
289
2/2
✓ Branch 19 → 20 taken 341113 times.
✓ Branch 19 → 21 taken 6718656 times.
7059769 if (ret)
290 341113 *out_clear = clear;
291 7059769 return ret;
292 }
293
294 /* Unswizzle a linear operation by aligning single-input rows with
295 * their corresponding diagonal */
296 6204536 static bool extract_swizzle(SwsLinearOp *op, const SwsOpPad inputs[4],
297 SwsSwizzleOp *out_swiz)
298 {
299 6204536 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
300 6204536 SwsLinearOp c = *op;
301
302 /* Find non-zero coefficients in the main 4x4 matrix */
303 6204536 uint32_t nonzero = 0;
304
2/2
✓ Branch 11 → 3 taken 24818144 times.
✓ Branch 11 → 12 taken 6204536 times.
31022680 for (int i = 0; i < 4; i++) {
305
2/2
✓ Branch 9 → 4 taken 99272576 times.
✓ Branch 9 → 10 taken 24818144 times.
124090720 for (int j = 0; j < 4; j++) {
306
4/4
✓ Branch 4 → 5 taken 42255452 times.
✓ Branch 4 → 6 taken 57017124 times.
✓ Branch 5 → 6 taken 251335 times.
✓ Branch 5 → 7 taken 42004117 times.
99272576 if (!c.m[i][j].num || (inputs[j].flags & SWS_COMP_ZERO))
307 57268459 continue;
308 42004117 nonzero |= SWS_MASK(i, j);
309 }
310 }
311
312 /* If a value is unique in its row and the target column is
313 * empty, move it there and update the input swizzle */
314
2/2
✓ Branch 22 → 13 taken 24818144 times.
✓ Branch 22 → 23 taken 6204536 times.
31022680 for (int i = 0; i < 4; i++) {
315
2/2
✓ Branch 13 → 14 taken 24553613 times.
✓ Branch 13 → 15 taken 264531 times.
24818144 if (nonzero & SWS_MASK_COL(i))
316 24553613 continue; /* target column is not empty */
317
2/2
✓ Branch 20 → 16 taken 353724 times.
✓ Branch 20 → 21 taken 29731 times.
383455 for (int j = 0; j < 4; j++) {
318
2/2
✓ Branch 16 → 17 taken 234800 times.
✓ Branch 16 → 19 taken 118924 times.
353724 if ((nonzero & SWS_MASK_ROW(i)) == SWS_MASK(i, j)) {
319 /* Move coefficient to the diagonal */
320 234800 c.m[i][i] = c.m[i][j];
321 234800 c.m[i][j] = Q(0);
322 234800 swiz.in[i] = j;
323 234800 break;
324 }
325 }
326 }
327
328
2/2
✓ Branch 23 → 24 taken 6087136 times.
✓ Branch 23 → 25 taken 117400 times.
6204536 if (swiz.mask == SWS_SWIZZLE(0, 1, 2, 3).mask)
329 6087136 return false; /* no swizzle was identified */
330
331 117400 *out_swiz = swiz;
332 117400 *op = c;
333 117400 return true;
334 }
335
336 333992 static int op_result_is_exact(const SwsOp *op)
337 {
338
2/2
✓ Branch 7 → 3 taken 407821 times.
✓ Branch 7 → 8 taken 23241 times.
431062 for (int i = 0; i < 4; i++) {
339
4/4
✓ Branch 3 → 4 taken 376131 times.
✓ Branch 3 → 6 taken 31690 times.
✓ Branch 4 → 5 taken 310751 times.
✓ Branch 4 → 6 taken 65380 times.
407821 if (SWS_OP_NEEDED(op, i) && !(op->outputs[i].flags & SWS_COMP_EXACT))
340 310751 return false;
341 }
342
343 23241 return true;
344 }
345
346 3215509 int ff_sws_op_list_optimize(SwsOpList *ops)
347 {
348 int ret;
349
350 20785542 retry:
351 24001051 ff_sws_op_list_update(ops);
352
353 /* Try to push filters towards the input; do this first to unblock
354 * in-place optimizations like linear op fusion */
355
2/2
✓ Branch 17 → 6 taken 224967476 times.
✓ Branch 17 → 18 taken 20938580 times.
245906056 for (int n = 1; n < ops->num_ops; n++) {
356 224967476 SwsOp *op = &ops->ops[n];
357 224967476 SwsOp *prev = &ops->ops[n - 1];
358
359
2/2
✓ Branch 6 → 7 taken 18928268 times.
✓ Branch 6 → 16 taken 206039208 times.
224967476 switch (op->op) {
360 18928268 case SWS_OP_FILTER_H:
361 case SWS_OP_FILTER_V:
362
2/2
✓ Branch 8 → 9 taken 2273139 times.
✓ Branch 8 → 10 taken 16655129 times.
18928268 if (op_commute_filter(op, prev)) {
363 2273139 FFSWAP(SwsOp, *op, *prev);
364 2273139 goto retry;
365 }
366
367 /* Merge filter with prior conversion */
368
2/2
✓ Branch 10 → 11 taken 2373697 times.
✓ Branch 10 → 15 taken 14281432 times.
16655129 if (prev->op == SWS_OP_CONVERT) {
369 2373697 const SwsPixelType input_type = ff_sws_op_input_type(prev);
370 2373697 int size_from = ff_sws_pixel_type_size(input_type);
371 2373697 int size_to = ff_sws_pixel_type_size(prev->convert.to);
372
2/2
✓ Branch 12 → 13 taken 789332 times.
✓ Branch 12 → 15 taken 1584365 times.
2373697 if (size_from < size_to) {
373 789332 ff_sws_op_list_remove_at(ops, n - 1, 1);
374 789332 goto retry;
375 }
376 }
377 15865797 break;
378 }
379 }
380
381 /* Apply all in-place optimizations (that do not re-order the list) */
382
2/2
✓ Branch 285 → 19 taken 119043874 times.
✓ Branch 285 → 286 taken 5627354 times.
124671228 for (int n = 0; n < ops->num_ops; n++) {
383 119043874 SwsOp dummy = {0};
384 119043874 SwsOp *op = &ops->ops[n];
385
2/2
✓ Branch 19 → 20 taken 98105294 times.
✓ Branch 19 → 21 taken 20938580 times.
119043874 SwsOp *prev = n ? &ops->ops[n - 1] : &dummy;
386
2/2
✓ Branch 22 → 23 taken 113416520 times.
✓ Branch 22 → 24 taken 5627354 times.
119043874 SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy;
387
388 /* common helper variable */
389 119043874 const SwsCompMask needed = ff_sws_comp_mask_needed(op);
390 119043874 bool noop = true;
391
392
4/4
✓ Branch 26 → 27 taken 6552240 times.
✓ Branch 26 → 30 taken 112491634 times.
✓ Branch 27 → 28 taken 924886 times.
✓ Branch 27 → 30 taken 5627354 times.
119043874 if (!needed && op->op != SWS_OP_WRITE) {
393 /* Remove any operation whose output is not needed */
394 924886 ff_sws_op_list_remove_at(ops, n, 1);
395 15311226 goto retry;
396 }
397
398
15/15
✓ Branch 30 → 31 taken 19735950 times.
✓ Branch 30 → 45 taken 8683000 times.
✓ Branch 30 → 49 taken 3313726 times.
✓ Branch 30 → 57 taken 1706172 times.
✓ Branch 30 → 64 taken 6864226 times.
✓ Branch 30 → 108 taken 12811806 times.
✓ Branch 30 → 148 taken 12604331 times.
✓ Branch 30 → 156 taken 5484649 times.
✓ Branch 30 → 170 taken 3696960 times.
✓ Branch 30 → 184 taken 5953186 times.
✓ Branch 30 → 197 taken 11248575 times.
✓ Branch 30 → 254 taken 4885255 times.
✓ Branch 30 → 270 taken 12249224 times.
✓ Branch 30 → 278 taken 2347968 times.
✓ Branch 30 → 282 taken 6533960 times.
118118988 switch (op->op) {
399 19735950 case SWS_OP_READ:
400 /* "Compress" planar reads where not all components are needed */
401
2/2
✓ Branch 31 → 32 taken 11757658 times.
✓ Branch 31 → 44 taken 7978292 times.
19735950 if (op->rw.mode == SWS_RW_PLANAR) {
402 11757658 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
403 11757658 int nb_planes = 0;
404
2/2
✓ Branch 37 → 33 taken 29916819 times.
✓ Branch 37 → 38 taken 11757658 times.
41674477 for (int i = 0; i < op->rw.elems; i++) {
405
2/2
✓ Branch 33 → 34 taken 168254 times.
✓ Branch 33 → 35 taken 29748565 times.
29916819 if (!SWS_OP_NEEDED(op, i)) {
406 168254 swiz.in[i] = 3 - (i - nb_planes); /* map to unused plane */
407 168254 continue;
408 }
409
410 29748565 const int idx = nb_planes++;
411 av_assert1(idx <= i);
412 29748565 ops->plane_src[idx] = ops->plane_src[i];
413 29748565 swiz.in[i] = idx;
414 }
415
416
2/2
✓ Branch 38 → 39 taken 141567 times.
✓ Branch 38 → 43 taken 11616091 times.
11757658 if (nb_planes < op->rw.elems) {
417 141567 op->rw.elems = nb_planes;
418
1/2
✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 141567 times.
141567 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
419 .op = SWS_OP_SWIZZLE,
420 .swizzle = swiz,
421 }));
422 141567 goto retry;
423 }
424 }
425 19594383 break;
426
427 8683000 case SWS_OP_SWAP_BYTES:
428 /* Redundant (double) swap */
429
2/2
✓ Branch 45 → 46 taken 1818 times.
✓ Branch 45 → 48 taken 8681182 times.
8683000 if (next->op == SWS_OP_SWAP_BYTES) {
430 1818 ff_sws_op_list_remove_at(ops, n, 2);
431 1818 goto retry;
432 }
433 8681182 break;
434
435 3313726 case SWS_OP_UNPACK:
436 /* Redundant unpack+pack */
437
2/2
✓ Branch 49 → 50 taken 427 times.
✓ Branch 49 → 56 taken 3313299 times.
3313726 if (next->op == SWS_OP_PACK &&
438
1/2
✓ Branch 50 → 51 taken 427 times.
✗ Branch 50 → 56 not taken.
427 next->pack.pattern[0] == op->pack.pattern[0] &&
439
1/2
✓ Branch 51 → 52 taken 427 times.
✗ Branch 51 → 56 not taken.
427 next->pack.pattern[1] == op->pack.pattern[1] &&
440
1/2
✓ Branch 52 → 53 taken 427 times.
✗ Branch 52 → 56 not taken.
427 next->pack.pattern[2] == op->pack.pattern[2] &&
441
1/2
✓ Branch 53 → 54 taken 427 times.
✗ Branch 53 → 56 not taken.
427 next->pack.pattern[3] == op->pack.pattern[3])
442 {
443 427 ff_sws_op_list_remove_at(ops, n, 2);
444 427 goto retry;
445 }
446 3313299 break;
447
448 1706172 case SWS_OP_LSHIFT:
449 case SWS_OP_RSHIFT:
450 /* Two shifts in the same direction */
451
2/2
✓ Branch 57 → 58 taken 1717 times.
✓ Branch 57 → 60 taken 1704455 times.
1706172 if (next->op == op->op) {
452 1717 op->shift.amount += next->shift.amount;
453 1717 ff_sws_op_list_remove_at(ops, n + 1, 1);
454 1717 goto retry;
455 }
456
457 /* No-op shift */
458
1/2
✗ Branch 60 → 61 not taken.
✓ Branch 60 → 63 taken 1704455 times.
1704455 if (!op->shift.amount) {
459 ✗ ff_sws_op_list_remove_at(ops, n, 1);
460 ✗ goto retry;
461 }
462 1704455 break;
463
464 6864226 case SWS_OP_CLEAR:
465
2/2
✓ Branch 75 → 65 taken 27456904 times.
✓ Branch 75 → 76 taken 6864226 times.
34321130 for (int i = 0; i < 4; i++) {
466
2/2
✓ Branch 65 → 66 taken 18454082 times.
✓ Branch 65 → 67 taken 9002822 times.
27456904 if (!SWS_COMP_TEST(op->clear.mask, i))
467 18454082 continue;
468
469
1/2
✗ Branch 67 → 68 not taken.
✓ Branch 67 → 71 taken 9002822 times.
9002822 if ((prev->outputs[i].flags & SWS_COMP_ZERO) &&
470
0/2
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 71 not taken.
✗ prev->outputs[i].type == op->clear.type[i] &&
471
0/2
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
✗ op->clear.value[i].num == 0)
472 {
473 /* Redundant clear-to-zero of zero component */
474 ✗ op->clear.mask ^= SWS_COMP(i);
475
2/2
✓ Branch 71 → 72 taken 1441373 times.
✓ Branch 71 → 73 taken 7561449 times.
9002822 } else if (!SWS_OP_NEEDED(op, i)) {
476 /* Unnecessary clear of unused component */
477 1441373 op->clear.mask ^= SWS_COMP(i);
478 } else {
479 7561449 noop = false;
480 }
481 }
482
483
2/2
✓ Branch 76 → 77 taken 1308993 times.
✓ Branch 76 → 79 taken 5555233 times.
6864226 if (noop) {
484 1308993 ff_sws_op_list_remove_at(ops, n, 1);
485 1308993 goto retry;
486 }
487
488 /* Transitive clear */
489
2/2
✓ Branch 79 → 80 taken 5234 times.
✓ Branch 79 → 87 taken 5549999 times.
5555233 if (next->op == SWS_OP_CLEAR) {
490
2/2
✓ Branch 84 → 81 taken 20936 times.
✓ Branch 84 → 85 taken 5234 times.
26170 for (int i = 0; i < 4; i++) {
491
2/2
✓ Branch 81 → 82 taken 5234 times.
✓ Branch 81 → 83 taken 15702 times.
20936 if (SWS_COMP_TEST(next->clear.mask, i)) {
492 5234 op->clear.value[i] = next->clear.value[i];
493 5234 op->clear.type[i] = next->clear.type[i];
494 }
495 }
496 5234 op->clear.mask |= next->clear.mask;
497 5234 ff_sws_op_list_remove_at(ops, n + 1, 1);
498 5234 goto retry;
499 }
500
501 /* Fold into linear op */
502
2/2
✓ Branch 87 → 88 taken 18109 times.
✓ Branch 87 → 107 taken 5531890 times.
5549999 if (next->op == SWS_OP_LINEAR) {
503
2/2
✓ Branch 104 → 89 taken 72436 times.
✓ Branch 104 → 105 taken 18109 times.
90545 for (int j = 0; j < 4; j++) {
504
2/2
✓ Branch 89 → 90 taken 40237 times.
✓ Branch 89 → 91 taken 32199 times.
72436 if (!SWS_COMP_TEST(op->clear.mask, j))
505 40237 continue;
506
507 32199 const AVRational64 x = op->clear.value[j];
508
2/2
✓ Branch 100 → 92 taken 128796 times.
✓ Branch 100 → 101 taken 32199 times.
160995 for (int i = 0; i < 4; i++) {
509
2/2
✓ Branch 92 → 93 taken 96597 times.
✓ Branch 92 → 94 taken 32199 times.
128796 if (!next->lin.m[i][j].num)
510 96597 continue;
511
1/2
✗ Branch 94 → 95 not taken.
✓ Branch 94 → 97 taken 32199 times.
32199 av_assert0(next->lin.type[i] == op->clear.type[j]);
512 32199 const AVRational64 kx = ff_mul_q64(next->lin.m[i][j], x);
513 32199 next->lin.m[i][4] = ff_add_q64(next->lin.m[i][4], kx);
514 32199 next->lin.m[i][j] = Q(0);
515 }
516 }
517
518 18109 ff_sws_op_list_remove_at(ops, n, 1);
519 18109 goto retry;
520 }
521 5531890 break;
522
523 12811806 case SWS_OP_SWIZZLE:
524
2/2
✓ Branch 114 → 109 taken 51247224 times.
✓ Branch 114 → 115 taken 12811806 times.
64059030 for (int i = 0; i < 4; i++) {
525
2/2
✓ Branch 109 → 110 taken 12698094 times.
✓ Branch 109 → 111 taken 38549130 times.
51247224 if (!SWS_OP_NEEDED(op, i))
526 12698094 continue;
527
2/2
✓ Branch 111 → 112 taken 26310895 times.
✓ Branch 111 → 113 taken 12238235 times.
38549130 if (op->swizzle.in[i] != i)
528 26310895 noop = false;
529 }
530
531 /* Identity swizzle */
532
2/2
✓ Branch 115 → 116 taken 1990262 times.
✓ Branch 115 → 118 taken 10821544 times.
12811806 if (noop) {
533 1990262 ff_sws_op_list_remove_at(ops, n, 1);
534 1990262 goto retry;
535 }
536
537 /* Transitive swizzle */
538
2/2
✓ Branch 118 → 119 taken 209694 times.
✓ Branch 118 → 124 taken 10611850 times.
10821544 if (next->op == SWS_OP_SWIZZLE) {
539 209694 const SwsSwizzleOp orig = op->swizzle;
540
2/2
✓ Branch 121 → 120 taken 838776 times.
✓ Branch 121 → 122 taken 209694 times.
1048470 for (int i = 0; i < 4; i++)
541 838776 op->swizzle.in[i] = orig.in[next->swizzle.in[i]];
542 209694 ff_sws_op_list_remove_at(ops, n + 1, 1);
543 209694 goto retry;
544 }
545
546 /* Swizzle planes instead of components, if possible */
547
4/4
✓ Branch 124 → 125 taken 1569205 times.
✓ Branch 124 → 139 taken 9042645 times.
✓ Branch 125 → 126 taken 701773 times.
✓ Branch 125 → 139 taken 867432 times.
10611850 if (prev->op == SWS_OP_READ && prev->rw.mode == SWS_RW_PLANAR) {
548
2/2
✓ Branch 138 → 127 taken 977920 times.
✓ Branch 138 → 139 taken 195815 times.
1173735 for (int dst = 0; dst < prev->rw.elems; dst++) {
549 977920 const int src = op->swizzle.in[dst];
550
4/4
✓ Branch 127 → 128 taken 523975 times.
✓ Branch 127 → 137 taken 453945 times.
✓ Branch 128 → 129 taken 505958 times.
✓ Branch 128 → 137 taken 18017 times.
977920 if (src > dst && src < prev->rw.elems) {
551 505958 FFSWAP(int, ops->plane_src[dst], ops->plane_src[src]);
552
2/2
✓ Branch 135 → 130 taken 1808681 times.
✓ Branch 135 → 136 taken 505958 times.
2314639 for (int i = dst; i < 4; i++) {
553
2/2
✓ Branch 130 → 131 taken 530374 times.
✓ Branch 130 → 132 taken 1278307 times.
1808681 if (op->swizzle.in[i] == dst)
554 530374 op->swizzle.in[i] = src;
555
2/2
✓ Branch 132 → 133 taken 505958 times.
✓ Branch 132 → 134 taken 772349 times.
1278307 else if (op->swizzle.in[i] == src)
556 505958 op->swizzle.in[i] = dst;
557 }
558 505958 goto retry;
559 }
560 }
561 }
562
563
4/4
✓ Branch 139 → 140 taken 1509854 times.
✓ Branch 139 → 147 taken 8596038 times.
✓ Branch 140 → 141 taken 984944 times.
✓ Branch 140 → 147 taken 524910 times.
10105892 if (next->op == SWS_OP_WRITE && next->rw.mode == SWS_RW_PLANAR) {
564
2/2
✓ Branch 146 → 142 taken 1355558 times.
✓ Branch 146 → 147 taken 291976 times.
1647534 for (int dst = 0; dst < next->rw.elems; dst++) {
565 1355558 const int src = op->swizzle.in[dst];
566
4/4
✓ Branch 142 → 143 taken 944309 times.
✓ Branch 142 → 145 taken 411249 times.
✓ Branch 143 → 144 taken 692968 times.
✓ Branch 143 → 145 taken 251341 times.
1355558 if (src > dst && src < next->rw.elems) {
567 692968 FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
568 692968 FFSWAP(int, op->swizzle.in[dst], op->swizzle.in[src]);
569 692968 goto retry;
570 }
571 }
572 }
573 9412924 break;
574
575 12604331 case SWS_OP_CONVERT:
576 /* No-op conversion */
577
2/2
✓ Branch 149 → 150 taken 333566 times.
✓ Branch 149 → 152 taken 12270765 times.
12604331 if (op->convert.to == ff_sws_op_input_type(op)) {
578 333566 ff_sws_op_list_remove_at(ops, n, 1);
579 333566 goto retry;
580 }
581
582 /* Transitive conversion */
583
2/2
✓ Branch 152 → 153 taken 292815 times.
✓ Branch 152 → 155 taken 11977950 times.
12270765 if (next->op == SWS_OP_CONVERT) {
584 292815 op->convert.to = next->convert.to;
585 292815 ff_sws_op_list_remove_at(ops, n + 1, 1);
586 292815 goto retry;
587 }
588 11977950 break;
589
590 5484649 case SWS_OP_MIN:
591
2/2
✓ Branch 165 → 157 taken 21938596 times.
✓ Branch 165 → 166 taken 5484649 times.
27423245 for (int i = 0; i < 4; i++) {
592
4/4
✓ Branch 157 → 158 taken 16449264 times.
✓ Branch 157 → 159 taken 5489332 times.
✓ Branch 158 → 159 taken 972502 times.
✓ Branch 158 → 160 taken 15476762 times.
21938596 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
593 6461834 continue;
594
2/2
✓ Branch 161 → 162 taken 1967781 times.
✓ Branch 161 → 163 taken 13508981 times.
15476762 if (ff_cmp_q64(op->clamp.limit[i], prev->outputs[i].max) >= 0)
595 1967781 op->clamp.limit[i] = (AVRational64) {0}; /* no-op */
596 else
597 13508981 noop = false;
598 }
599
600
2/2
✓ Branch 166 → 167 taken 564915 times.
✓ Branch 166 → 169 taken 4919734 times.
5484649 if (noop) {
601 564915 ff_sws_op_list_remove_at(ops, n, 1);
602 564915 goto retry;
603 }
604 4919734 break;
605
606 3696960 case SWS_OP_MAX:
607
2/2
✓ Branch 179 → 171 taken 14787840 times.
✓ Branch 179 → 180 taken 3696960 times.
18484800 for (int i = 0; i < 4; i++) {
608
4/4
✓ Branch 171 → 172 taken 11102127 times.
✓ Branch 171 → 173 taken 3685713 times.
✓ Branch 172 → 173 taken 508505 times.
✓ Branch 172 → 174 taken 10593622 times.
14787840 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
609 4194218 continue;
610
2/2
✓ Branch 175 → 176 taken 3028303 times.
✓ Branch 175 → 177 taken 7565319 times.
10593622 if (ff_cmp_q64(prev->outputs[i].min, op->clamp.limit[i]) >= 0)
611 3028303 op->clamp.limit[i] = (AVRational64) {0};
612 else
613 7565319 noop = false;
614 }
615
616
2/2
✓ Branch 180 → 181 taken 935877 times.
✓ Branch 180 → 183 taken 2761083 times.
3696960 if (noop) {
617 935877 ff_sws_op_list_remove_at(ops, n, 1);
618 935877 goto retry;
619 }
620 2761083 break;
621
622 5953186 case SWS_OP_DITHER:
623
2/2
✓ Branch 192 → 185 taken 23171431 times.
✓ Branch 192 → 193 taken 4856764 times.
28028195 for (int i = 0; i < 4; i++) {
624
2/2
✓ Branch 185 → 186 taken 6709596 times.
✓ Branch 185 → 187 taken 16461835 times.
23171431 if (op->dither.y_offset[i] < 0)
625 6709596 continue;
626
4/4
✓ Branch 187 → 188 taken 15691295 times.
✓ Branch 187 → 189 taken 770540 times.
✓ Branch 188 → 189 taken 325882 times.
✓ Branch 188 → 190 taken 15365413 times.
16461835 if (!SWS_OP_NEEDED(op, i) || (prev->outputs[i].flags & SWS_COMP_EXACT)) {
627 1096422 op->dither.y_offset[i] = -1; /* unnecessary dither */
628 1096422 goto retry;
629 } else {
630 15365413 noop = false;
631 }
632 }
633
634
2/2
✓ Branch 193 → 194 taken 21431 times.
✓ Branch 193 → 196 taken 4835333 times.
4856764 if (noop) {
635 21431 ff_sws_op_list_remove_at(ops, n, 1);
636 21431 goto retry;
637 }
638 4835333 break;
639
640 11248575 case SWS_OP_LINEAR: {
641 11248575 const uint32_t mask = ff_sws_linear_mask(&op->lin);
642 SwsSwizzleOp swizzle;
643 SwsClearOp clear;
644 SwsScaleOp scale;
645
646 /* No-op (identity) linear operation */
647
2/2
✓ Branch 198 → 199 taken 126645 times.
✓ Branch 198 → 201 taken 11121930 times.
11248575 if (!mask) {
648 126645 ff_sws_op_list_remove_at(ops, n, 1);
649 5161439 goto retry;
650 }
651
652
2/2
✓ Branch 201 → 202 taken 2535452 times.
✓ Branch 201 → 215 taken 8586478 times.
11121930 if (next->op == SWS_OP_LINEAR) {
653 /* 5x5 matrix multiplication after appending [ 0 0 0 0 1 ] */
654 2535452 const SwsLinearOp m1 = op->lin;
655 2535452 const SwsLinearOp m2 = next->lin;
656
2/2
✓ Branch 212 → 203 taken 10141808 times.
✓ Branch 212 → 213 taken 2535452 times.
12677260 for (int i = 0; i < 4; i++) {
657 10141808 op->lin.type[i] = m2.type[i];
658
2/2
✓ Branch 210 → 204 taken 50709040 times.
✓ Branch 210 → 211 taken 10141808 times.
60850848 for (int j = 0; j < 5; j++) {
659 50709040 AVRational64 sum = Q(0);
660
2/2
✓ Branch 206 → 205 taken 202836160 times.
✓ Branch 206 → 207 taken 50709040 times.
253545200 for (int k = 0; k < 4; k++)
661 202836160 sum = ff_add_q64(sum, ff_mul_q64(m2.m[i][k], m1.m[k][j]));
662
2/2
✓ Branch 207 → 208 taken 10141808 times.
✓ Branch 207 → 209 taken 40567232 times.
50709040 if (j == 4) /* m1.m[4][j] == 1 */
663 10141808 sum = ff_add_q64(sum, m2.m[i][4]);
664 50709040 op->lin.m[i][j] = sum;
665 }
666 }
667 2535452 ff_sws_op_list_remove_at(ops, n + 1, 1);
668 2535452 goto retry;
669 }
670
671 /* Optimize away zero columns */
672
2/2
✓ Branch 224 → 216 taken 33889459 times.
✓ Branch 224 → 225 taken 8114323 times.
42003782 for (int j = 0; j < 4; j++) {
673 33889459 const uint32_t col = SWS_MASK_COL(j);
674
4/4
✓ Branch 216 → 217 taken 1581737 times.
✓ Branch 216 → 218 taken 32307722 times.
✓ Branch 217 → 218 taken 1109582 times.
✓ Branch 217 → 219 taken 472155 times.
33889459 if (!(prev->outputs[j].flags & SWS_COMP_ZERO) || !(mask & col))
675 33417304 continue;
676
2/2
✓ Branch 221 → 220 taken 1888620 times.
✓ Branch 221 → 222 taken 472155 times.
2360775 for (int i = 0; i < 4; i++)
677 1888620 op->lin.m[i][j] = Q(i == j);
678 472155 goto retry;
679 }
680
681 /* Optimize away unused rows */
682
2/2
✓ Branch 234 → 226 taken 31962169 times.
✓ Branch 234 → 235 taken 7059769 times.
39021938 for (int i = 0; i < 4; i++) {
683 31962169 const uint32_t row = SWS_MASK_ROW(i);
684
4/4
✓ Branch 226 → 227 taken 9853633 times.
✓ Branch 226 → 228 taken 22108536 times.
✓ Branch 227 → 228 taken 8799079 times.
✓ Branch 227 → 229 taken 1054554 times.
31962169 if (SWS_OP_NEEDED(op, i) || !(mask & row))
685 30907615 continue;
686
2/2
✓ Branch 231 → 230 taken 5272770 times.
✓ Branch 231 → 232 taken 1054554 times.
6327324 for (int j = 0; j < 5; j++)
687 5272770 op->lin.m[i][j] = Q(i == j);
688 1054554 goto retry;
689 }
690
691 /* Convert constant rows to explicit clear instruction */
692
2/2
✓ Branch 236 → 237 taken 341113 times.
✓ Branch 236 → 241 taken 6718656 times.
7059769 if (extract_constant_rows(&op->lin, prev->outputs, &clear)) {
693
1/2
✗ Branch 238 → 239 not taken.
✓ Branch 238 → 240 taken 341113 times.
341113 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
694 .op = SWS_OP_CLEAR,
695 .clear = clear,
696 }));
697 341113 goto retry;
698 }
699
700 /* Multiplication by scalar constant */
701
2/2
✓ Branch 242 → 243 taken 514120 times.
✓ Branch 242 → 244 taken 6204536 times.
6718656 if (extract_scalar(&op->lin, op->outputs, prev->outputs, &scale)) {
702 514120 op->op = SWS_OP_SCALE;
703 514120 op->scale = scale;
704 514120 goto retry;
705 }
706
707 /* Swizzle by fixed pattern */
708
2/2
✓ Branch 245 → 246 taken 117400 times.
✓ Branch 245 → 250 taken 6087136 times.
6204536 if (extract_swizzle(&op->lin, prev->outputs, &swizzle)) {
709
1/2
✗ Branch 247 → 248 not taken.
✓ Branch 247 → 249 taken 117400 times.
117400 RET(ff_sws_op_list_insert_at(ops, n, &(SwsOp) {
710 .op = SWS_OP_SWIZZLE,
711 .swizzle = swizzle,
712 }));
713 117400 goto retry;
714 }
715 6087136 break;
716 }
717
718 4885255 case SWS_OP_SCALE: {
719 4885255 const int factor2 = exact_log2_q64(op->scale.factor);
720
721 /* No-op scaling */
722
3/4
✓ Branch 255 → 256 taken 863757 times.
✓ Branch 255 → 259 taken 4021498 times.
✗ Branch 256 → 257 not taken.
✓ Branch 256 → 259 taken 863757 times.
4885255 if (op->scale.factor.num == 1 && op->scale.factor.den == 1) {
723 ✗ ff_sws_op_list_remove_at(ops, n, 1);
724 ✗ goto retry;
725 }
726
727 /* Merge consecutive scaling operations */
728
1/2
✗ Branch 259 → 260 not taken.
✓ Branch 259 → 262 taken 4885255 times.
4885255 if (next->op == SWS_OP_SCALE) {
729 ✗ op->scale.factor = ff_mul_q64(op->scale.factor, next->scale.factor);
730 ✗ ff_sws_op_list_remove_at(ops, n + 1, 1);
731 ✗ goto retry;
732 }
733
734 /* Scaling by exact power of two */
735
4/4
✓ Branch 262 → 263 taken 752592 times.
✓ Branch 262 → 269 taken 4132663 times.
✓ Branch 264 → 265 taken 8398 times.
✓ Branch 264 → 269 taken 744194 times.
4885255 if (factor2 && ff_sws_pixel_type_is_int(ff_sws_op_input_type(op))) {
736
1/2
✓ Branch 265 → 266 taken 8398 times.
✗ Branch 265 → 267 not taken.
8398 op->op = factor2 > 0 ? SWS_OP_LSHIFT : SWS_OP_RSHIFT;
737 8398 op->shift.amount = FFABS(factor2);
738 8398 goto retry;
739 }
740 4876857 break;
741 }
742
743 12249224 case SWS_OP_FILTER_H:
744 case SWS_OP_FILTER_V:
745 /* Merge with prior simple planar read */
746
4/4
✓ Branch 270 → 271 taken 3773694 times.
✓ Branch 270 → 277 taken 8475530 times.
✓ Branch 271 → 272 taken 2829422 times.
✓ Branch 271 → 277 taken 944272 times.
12249224 if (prev->op == SWS_OP_READ && !prev->rw.filter.op &&
747
4/4
✓ Branch 272 → 273 taken 1210077 times.
✓ Branch 272 → 277 taken 1619345 times.
✓ Branch 273 → 274 taken 1093254 times.
✓ Branch 273 → 277 taken 116823 times.
2829422 prev->rw.mode == SWS_RW_PLANAR && !prev->rw.frac) {
748 1093254 prev->rw.filter.op = op->op;
749 1093254 prev->rw.filter.kernel = av_refstruct_ref(op->filter.kernel);
750 1093254 prev->rw.filter.type = op->filter.type;
751 1093254 ff_sws_op_list_remove_at(ops, n, 1);
752 1093254 goto retry;
753 }
754 11155970 break;
755
756 2347968 case SWS_OP_LUT_3D:
757 /* Eliminate unnecessary 3DLUT */
758
2/2
✓ Branch 278 → 279 taken 1476 times.
✓ Branch 278 → 281 taken 2346492 times.
2347968 if (!(needed & SWS_COMP_ELEMS(3))) {
759 1476 ff_sws_op_list_remove_at(ops, n, 1);
760 1476 goto retry;
761 }
762 2346492 break;
763 }
764 }
765
766 /* Push clears to the back to void any unused components */
767
2/2
✓ Branch 293 → 287 taken 38267190 times.
✓ Branch 293 → 294 taken 4496141 times.
42763331 for (int n = 0; n < ops->num_ops - 1; n++) {
768 38267190 SwsOp *op = &ops->ops[n];
769 38267190 SwsOp *next = &ops->ops[n + 1];
770
771
2/2
✓ Branch 287 → 288 taken 2353508 times.
✓ Branch 287 → 292 taken 35913682 times.
38267190 switch (op->op) {
772 2353508 case SWS_OP_CLEAR:
773
2/2
✓ Branch 289 → 290 taken 1131213 times.
✓ Branch 289 → 291 taken 1222295 times.
2353508 if (op_commute_clear(op, next)) {
774 1131213 FFSWAP(SwsOp, *op, *next);
775 1131213 goto retry;
776 }
777 1222295 break;
778 }
779 }
780
781 /* Apply any remaining preferential re-ordering optimizations; do these
782 * last because they are more likely to block other optimizations if done
783 * too aggressively */
784
2/2
✓ Branch 317 → 295 taken 25844416 times.
✓ Branch 317 → 318 taken 3215509 times.
29059925 for (int n = 0; n < ops->num_ops - 1; n++) {
785 25844416 SwsOp *op = &ops->ops[n];
786 25844416 SwsOp *next = &ops->ops[n + 1];
787
788
4/4
✓ Branch 295 → 296 taken 2843796 times.
✓ Branch 295 → 300 taken 1519514 times.
✓ Branch 295 → 307 taken 1874746 times.
✓ Branch 295 → 316 taken 19606360 times.
25844416 switch (op->op) {
789 2843796 case SWS_OP_SWIZZLE: {
790 /* Try to push swizzles towards the output */
791
2/2
✓ Branch 297 → 298 taken 1257391 times.
✓ Branch 297 → 299 taken 1586405 times.
2843796 if (op_commute_swizzle(op, next)) {
792 1257391 FFSWAP(SwsOp, *op, *next);
793 1257391 goto retry;
794 }
795 1586405 break;
796 }
797
798 1519514 case SWS_OP_SCALE:
799 /* Exact integer multiplication */
800
4/4
✓ Branch 300 → 301 taken 360033 times.
✓ Branch 300 → 306 taken 1159481 times.
✓ Branch 301 → 302 taken 46289 times.
✓ Branch 301 → 306 taken 313744 times.
1519514 if (op->scale.factor.den == 1 && next->op == SWS_OP_CONVERT &&
801
3/4
✓ Branch 302 → 303 taken 46289 times.
✗ Branch 302 → 306 not taken.
✓ Branch 304 → 305 taken 15631 times.
✓ Branch 304 → 306 taken 30658 times.
92578 ff_sws_pixel_type_is_int(next->convert.to) &&
802 46289 op_result_is_exact(op))
803 {
804 15631 FFSWAP(SwsOp, *op, *next);
805 15631 goto retry;
806 }
807 1503883 break;
808
809 1874746 case SWS_OP_LINEAR:
810 /* Exact integer linear transformation */
811
2/2
✓ Branch 307 → 308 taken 287703 times.
✓ Branch 307 → 315 taken 1587043 times.
1874746 if (next->op == SWS_OP_CONVERT &&
812
3/4
✓ Branch 308 → 309 taken 287703 times.
✗ Branch 308 → 315 not taken.
✓ Branch 310 → 311 taken 7610 times.
✓ Branch 310 → 315 taken 280093 times.
575406 ff_sws_pixel_type_is_int(next->convert.to) &&
813 287703 op_result_is_exact(op))
814 {
815
2/2
✓ Branch 313 → 312 taken 30440 times.
✓ Branch 313 → 314 taken 7610 times.
38050 for (int i = 0; i < 4; i++)
816 30440 op->lin.type[i] = next->convert.to;
817 7610 FFSWAP(SwsOp, *op, *next);
818 7610 goto retry;
819 }
820 1867136 break;
821 }
822 }
823
824 3215509 return 0;
825 }
826
827 232686 static int select_planes(SwsOpList *ops, SwsCompMask planes)
828 {
829 232686 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
830 232686 SwsOp *write = &ops->ops[ops->num_ops - 1];
831
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 232686 times.
232686 av_assert0(write->op == SWS_OP_WRITE);
832
833 232686 write->rw.elems = 0;
834
2/2
✓ Branch 10 → 6 taken 930744 times.
✓ Branch 10 → 11 taken 232686 times.
1163430 for (int src = 0; src < 4; src++) {
835
2/2
✓ Branch 6 → 7 taken 480978 times.
✓ Branch 6 → 8 taken 449766 times.
930744 if (!SWS_COMP_TEST(planes, src))
836 480978 continue; /* plane not selected */
837 449766 const int dst = write->rw.elems++;
838 av_assert2(src >= dst);
839 449766 swiz.in[dst] = src;
840 449766 FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
841 }
842
843 /* Insert swizzle to select desired planes */
844 232686 int ret = ff_sws_op_list_insert_at(ops, ops->num_ops - 1, &(SwsOp) {
845 .op = SWS_OP_SWIZZLE,
846 .swizzle = swiz,
847 });
848
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 232686 times.
232686 if (ret < 0)
849 ✗ return ret;
850
851 /* The optimizer will take care of the rest */
852 232686 return ff_sws_op_list_optimize(ops);
853 }
854
855 3132091 int ff_sws_op_list_split_planes(SwsOpList *ops1, SwsOpList **out_ops2, SwsCompMask planes)
856 {
857 3132091 const SwsOp *write = ff_sws_op_list_output(ops1);
858
3/4
✓ Branch 3 → 4 taken 3132091 times.
✗ Branch 3 → 5 not taken.
✓ Branch 4 → 5 taken 970119 times.
✓ Branch 4 → 6 taken 2161972 times.
3132091 if (!write || write->rw.mode != SWS_RW_PLANAR) {
859 970119 *out_ops2 = NULL;
860 970119 return 0;
861 }
862
863 2161972 const SwsCompMask full = SWS_COMP_ELEMS(write->rw.elems);
864 2161972 const SwsCompMask mask1 = planes & full;
865 2161972 const SwsCompMask mask2 = full ^ mask1;
866
4/4
✓ Branch 6 → 7 taken 233364 times.
✓ Branch 6 → 8 taken 1928608 times.
✓ Branch 7 → 8 taken 117021 times.
✓ Branch 7 → 9 taken 116343 times.
2161972 if (!mask1 || !mask2) {
867 /* Nothing to filter */
868 2045629 *out_ops2 = NULL;
869 2045629 return 0;
870 }
871
872 116343 SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
873
1/2
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 116343 times.
116343 if (!ops2)
874 ✗ return AVERROR(ENOMEM);
875
876 int ret;
877
2/4
✓ Branch 13 → 14 taken 116343 times.
✗ Branch 13 → 16 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 116343 times.
232686 if ((ret = select_planes(ops1, mask1)) < 0 ||
878 116343 (ret = select_planes(ops2, mask2)) < 0)
879 {
880 ✗ ff_sws_op_list_free(&ops2);
881 ✗ return ret;
882 }
883
884 116343 *out_ops2 = ops2;
885 116343 return 0;
886 }
887
888 64824 int ff_sws_shuffle_mask(const SwsUOp *uop, int8_t shuffle[], int size)
889 {
890 64824 const SwsShuffleUOp *par = &uop->par.shuffle;
891 av_assert1(uop->uop == SWS_UOP_RW_SHUFFLE);
892 av_assert1(par->write_size <= sizeof(uop->data.shuffle.mask));
893 av_assert1(size <= INT8_MAX);
894
895 64824 const int num_groups = size / FFMAX(par->read_size, par->write_size);
896
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 64824 times.
64824 if (!num_groups)
897 ✗ return AVERROR(EINVAL);
898
899 64824 memset(shuffle, 0, size);
900
2/2
✓ Branch 9 → 5 taken 356431 times.
✓ Branch 9 → 10 taken 64824 times.
421255 for (int n = 0; n < num_groups; n++) {
901 356431 const int base_in = n * par->read_size;
902 356431 const int base_out = n * par->write_size;
903
2/2
✓ Branch 7 → 6 taken 836518 times.
✓ Branch 7 → 8 taken 356431 times.
1192949 for (int i = 0; i < par->write_size; i++) {
904 836518 const int8_t idx = uop->data.shuffle.mask[i];
905 836518 shuffle[base_out + i] = idx + (idx >= 0) * base_in;
906 }
907 }
908
909 64824 return num_groups;
910 }
911
912 1754 static bool pixel_is_repeating(SwsPixelType type, SwsPixel val)
913 {
914
3/4
✓ Branch 2 → 3 taken 853 times.
✓ Branch 2 → 4 taken 745 times.
✓ Branch 2 → 5 taken 156 times.
✗ Branch 2 → 6 not taken.
1754 switch (ff_sws_pixel_type_size(type)) {
915 853 case 1: return true;
916 745 case 2: return val.u16 == val.u8 * 0x101ul;
917 156 case 4: return val.u32 == val.u8 * 0x1010101ul;
918 ✗ default: break;
919 }
920
921 ✗ av_unreachable("Invalid pixel type!");
922 return false;
923 }
924
925 1750601 static int solve_shuffle(const SwsUOpList *const uops, SwsUOp *out)
926 {
927
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1750601 times.
1750601 if (!uops->num_ops)
928 ✗ return AVERROR(EINVAL);
929 1750601 const SwsUOp *read = &uops->ops[0];
930
3/3
✓ Branch 4 → 5 taken 264117 times.
✓ Branch 4 → 6 taken 455091 times.
✓ Branch 4 → 9 taken 1031393 times.
1750601 switch (read->uop) {
931 264117 case SWS_UOP_READ_PACKED:
932 264117 break;
933 455091 case SWS_UOP_READ_PLANAR:
934
2/2
✓ Branch 6 → 7 taken 225546 times.
✓ Branch 6 → 8 taken 229545 times.
455091 if (read->mask != SWS_COMP_ELEMS(1))
935 225546 return AVERROR(ENOTSUP);
936 229545 break;
937 1031393 default:
938 1031393 return AVERROR(ENOTSUP);
939 }
940
941 493662 const int read_size = ff_sws_pixel_type_size(read->type);
942 493662 uint32_t mask[4] = {0};
943 493662 int clear_val = -1;
944 493662 int read_elems = 0;
945
2/2
✓ Branch 14 → 11 taken 1974648 times.
✓ Branch 14 → 15 taken 493662 times.
2468310 for (int i = 0; i < 4; i++) {
946
2/2
✓ Branch 11 → 12 taken 1151450 times.
✓ Branch 11 → 13 taken 823198 times.
1974648 if (SWS_COMP_TEST(read->mask, i)) {
947 1151450 mask[i] = 0x01010101 * i * read_size + 0x03020100;
948 1151450 read_elems++;
949 }
950 }
951
952
1/2
✓ Branch 67 → 16 taken 728347 times.
✗ Branch 67 → 68 not taken.
728347 for (int opidx = 1; opidx < uops->num_ops; opidx++) {
953 728347 const SwsUOp *uop = &uops->ops[opidx];
954 728347 const SwsUOpParams *par = &uop->par;
955
7/7
✓ Branch 16 → 17 taken 34661 times.
✓ Branch 16 → 28 taken 197034 times.
✓ Branch 16 → 35 taken 1745 times.
✓ Branch 16 → 48 taken 1457 times.
✓ Branch 16 → 52 taken 223693 times.
✓ Branch 16 → 54 taken 3452 times.
✓ Branch 16 → 65 taken 266305 times.
728347 switch (uop->uop) {
956 34661 case SWS_UOP_COPY:
957 case SWS_UOP_PERMUTE: {
958 uint32_t tmp;
959
2/2
✓ Branch 25 → 18 taken 42218 times.
✓ Branch 25 → 26 taken 34661 times.
76879 for (int i = 0; i < par->move.num_moves; i++) {
960 42218 const int dst_idx = par->move.dst[i];
961 42218 const int src_idx = par->move.src[i];
962
2/2
✓ Branch 18 → 19 taken 1485 times.
✓ Branch 18 → 20 taken 40733 times.
42218 uint32_t *src = src_idx < 0 ? &tmp : &mask[src_idx];
963
2/2
✓ Branch 21 → 22 taken 1485 times.
✓ Branch 21 → 23 taken 40733 times.
42218 uint32_t *dst = dst_idx < 0 ? &tmp : &mask[dst_idx];
964 42218 *dst = *src;
965 }
966 34661 break;
967 }
968
969 197034 case SWS_UOP_SWAP_BYTES:
970
2/2
✓ Branch 33 → 29 taken 788136 times.
✓ Branch 33 → 34 taken 197034 times.
985170 for (int i = 0; i < 4; i++) {
971
2/3
✓ Branch 29 → 30 taken 549360 times.
✓ Branch 29 → 31 taken 238776 times.
✗ Branch 29 → 32 not taken.
788136 switch (ff_sws_pixel_type_size(uop->type)) {
972 549360 case 2: mask[i] = av_bswap16(mask[i]); break;
973 238776 case 4: mask[i] = av_bswap32(mask[i]); break;
974 }
975 }
976 197034 break;
977
978 1745 case SWS_UOP_CLEAR:
979
2/2
✓ Branch 46 → 36 taken 6908 times.
✓ Branch 46 → 47 taken 1533 times.
8441 for (int i = 0; i < 4; i++) {
980
2/2
✓ Branch 36 → 37 taken 5154 times.
✓ Branch 36 → 38 taken 1754 times.
6908 if (!SWS_COMP_TEST(uop->mask, i))
981 5154 continue;
982 1754 SwsPixel val = uop->data.vec4[i];
983
4/4
✓ Branch 39 → 40 taken 1542 times.
✓ Branch 39 → 42 taken 212 times.
✓ Branch 40 → 41 taken 9 times.
✓ Branch 40 → 43 taken 1533 times.
1754 if (!pixel_is_repeating(uop->type, val) ||
984
1/2
✗ Branch 41 → 42 not taken.
✓ Branch 41 → 43 taken 9 times.
9 (clear_val >= 0 && clear_val != val.u8))
985 212 return AVERROR(ENOTSUP); /* would require different bytes */
986 1542 mask[i] = 0xFFFFFFFFul; /* (uint8_t[4]) { -1, -1, -1, -1 } */
987 1542 clear_val = val.u8;
988 }
989 1533 break;
990
991 1457 case SWS_UOP_EXPAND_PAIR:
992 case SWS_UOP_EXPAND_QUAD:
993
2/2
✓ Branch 50 → 49 taken 5828 times.
✓ Branch 50 → 51 taken 1457 times.
7285 for (int i = 0; i < 4; i++)
994 5828 mask[i] = 0x01010101 * (mask[i] & 0xFF);
995 1457 break;
996
997 223693 case SWS_UOP_WRITE_PLANAR:
998
2/2
✓ Branch 52 → 53 taken 167467 times.
✓ Branch 52 → 54 taken 56226 times.
223693 if (uop->mask != SWS_COMP_ELEMS(1))
999 167467 return AVERROR(ENOTSUP);
1000 av_fallthrough;
1001 case SWS_UOP_WRITE_PACKED: {
1002 59678 const int write_elems = av_popcount(uop->mask);
1003 59678 const int write_size = ff_sws_pixel_type_size(uop->type);
1004 59678 *out = (SwsUOp) {
1005 .uop = SWS_UOP_RW_SHUFFLE,
1006 .type = SWS_PIXEL_U8,
1007 .mask = SWS_COMP_ELEMS(1), /* single plane for now */
1008 };
1009
1010 59678 SwsShuffleUOp *par = &out->par.shuffle;
1011 59678 SwsShuffleMask *data = &out->data.shuffle;
1012 59678 *par = (SwsShuffleUOp) {
1013 .read_size = read_elems * read_size,
1014 .write_size = write_elems * write_size,
1015 59678 .clear_value = clear_val >= 0 ? clear_val : 0,
1016 };
1017
1018 /* Generate baseline shuffle for a single pixel */
1019 59678 data->pixels = 1;
1020
2/2
✓ Branch 59 → 55 taken 68500 times.
✓ Branch 59 → 60 taken 59678 times.
128178 for (int i = 0; i < write_elems; i++) {
1021 68500 const int offset = i * write_size;
1022
2/2
✓ Branch 57 → 56 taken 152450 times.
✓ Branch 57 → 58 taken 68500 times.
220950 for (int b = 0; b < write_size; b++)
1023 152450 data->mask[offset + b] = mask[i] >> (b * 8);
1024 }
1025
1026 /* Expand as many times as needed to round up to the size of the
1027 * shuffle uop data mask */
1028 int8_t tmp[FF_ARRAY_ELEMS(data->mask)];
1029 59678 const int num_groups = ff_sws_shuffle_mask(out, tmp, sizeof(tmp));
1030
1/2
✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 59678 times.
59678 if (num_groups < 0)
1031 ✗ return num_groups;
1032 59678 memcpy(data->mask, tmp, sizeof(tmp));
1033 59678 par->read_size *= num_groups;
1034 59678 par->write_size *= num_groups;
1035 59678 data->pixels = num_groups;
1036 59678 return 0;
1037 }
1038
1039 266305 default:
1040 266305 return AVERROR(ENOTSUP);
1041 }
1042 }
1043
1044 ✗ return AVERROR(EINVAL);
1045 }
1046
1047 /* Only checks exact integer scale ops */
1048 736123 static bool is_scale(const SwsUOp *op, int64_t val)
1049 {
1050
2/2
✓ Branch 2 → 3 taken 77429 times.
✓ Branch 2 → 4 taken 658694 times.
736123 if (op->uop != SWS_UOP_SCALE)
1051 77429 return false;
1052
1053
4/4
✓ Branch 4 → 5 taken 1001 times.
✓ Branch 4 → 6 taken 6423 times.
✓ Branch 4 → 7 taken 644 times.
✓ Branch 4 → 8 taken 650626 times.
658694 switch (op->type) {
1054 1001 case SWS_PIXEL_U8: return op->data.scalar.u8 == val;
1055 6423 case SWS_PIXEL_U16: return op->data.scalar.u16 == val;
1056 644 case SWS_PIXEL_U32: return op->data.scalar.u32 == val;
1057 650626 default: return false;
1058 }
1059 }
1060
1061 2839435 int ff_sws_uop_list_optimize(SwsContext *ctx, SwsUOpFlags flags, SwsUOpList *uops)
1062 {
1063 static const SwsUOp dummy = {0};
1064
1065 3651 retry:
1066
2/2
✓ Branch 27 → 5 taken 15465591 times.
✓ Branch 27 → 28 taken 2839435 times.
18305026 for (int i = 0; i < uops->num_ops; i++) {
1067
2/2
✓ Branch 5 → 6 taken 12626156 times.
✓ Branch 5 → 7 taken 2839435 times.
15465591 const SwsUOp *next = i < uops->num_ops - 1 ? &uops->ops[i + 1] : &dummy;
1068 15465591 SwsUOp *op = &uops->ops[i];
1069
1070
4/4
✓ Branch 8 → 9 taken 970292 times.
✓ Branch 8 → 15 taken 89572 times.
✓ Branch 8 → 21 taken 659288 times.
✓ Branch 8 → 26 taken 13746439 times.
15465591 switch (op->uop) {
1071 970292 case SWS_UOP_TO_U16:
1072
4/4
✓ Branch 9 → 10 taken 79903 times.
✓ Branch 9 → 14 taken 890389 times.
✓ Branch 11 → 12 taken 3144 times.
✓ Branch 11 → 14 taken 76759 times.
970292 if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x101)) {
1073 3144 op->uop = SWS_UOP_EXPAND_PAIR;
1074 3144 ff_sws_uop_list_remove_at(uops, i + 1, 1);
1075 3144 goto retry;
1076 }
1077 967148 break;
1078
1079 89572 case SWS_UOP_TO_U32:
1080
3/4
✓ Branch 15 → 16 taken 1828 times.
✓ Branch 15 → 20 taken 87744 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 20 taken 1828 times.
89572 if (ff_sws_pixel_type_is_int(op->type) && is_scale(next, 0x1010101)) {
1081 ✗ op->uop = SWS_UOP_EXPAND_QUAD;
1082 ✗ ff_sws_uop_list_remove_at(uops, i + 1, 1);
1083 ✗ goto retry;
1084 }
1085 89572 break;
1086
1087 659288 case SWS_UOP_SCALE:
1088
2/2
✓ Branch 21 → 22 taken 654392 times.
✓ Branch 21 → 25 taken 4896 times.
659288 if (flags & SWS_UOP_FLAG_EXPAND_BIT) {
1089 654392 const int bits = 8 * ff_sws_pixel_type_size(op->type);
1090
2/2
✓ Branch 23 → 24 taken 507 times.
✓ Branch 23 → 25 taken 653885 times.
654392 if (is_scale(op, UINT64_MAX >> (64 - bits))) {
1091 507 op->uop = SWS_UOP_EXPAND_BIT;
1092 507 memset(&op->par, 0, sizeof(op->par));
1093 507 goto retry;
1094 }
1095 }
1096 658781 break;
1097 }
1098 }
1099
1100 /* Try promoting the entire uop list to a packed shuffle operation */
1101
2/2
✓ Branch 28 → 29 taken 1750601 times.
✓ Branch 28 → 39 taken 1088834 times.
2839435 if (flags & SWS_UOP_FLAG_PSHUFB) {
1102 SwsUOp shuffle;
1103 1750601 int ret = solve_shuffle(uops, &shuffle);
1104
2/2
✓ Branch 30 → 31 taken 59678 times.
✓ Branch 30 → 34 taken 1690923 times.
1750601 if (ret >= 0) {
1105 59678 ff_sws_uop_list_remove_at(uops, 0, uops->num_ops);
1106 59678 return ff_sws_uop_list_append(uops, &shuffle);
1107
2/4
✓ Branch 34 → 35 taken 1690923 times.
✗ Branch 34 → 37 not taken.
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 1690923 times.
1690923 } else if (ret < 0 && ret != AVERROR(ENOTSUP)) {
1108 ✗ return ret;
1109 }
1110 }
1111
1112 2779757 return 0;
1113 }
1114
1115 /**
1116 * Determine a suitable intermediate buffer format for a given combination
1117 * of pixel types and number of planes. The exact interpretation of these
1118 * formats does not matter at all; since they will only ever be used as
1119 * temporary intermediate buffers. We still need to pick *some* format as
1120 * a consequence of ff_sws_graph_add_pass() taking an AVPixelFormat for the
1121 * output buffer.
1122 */
1123 886701 static enum AVPixelFormat get_planar_fmt(SwsPixelType type, int nb_planes)
1124 {
1125
3/4
✓ Branch 2 → 3 taken 220527 times.
✓ Branch 2 → 9 taken 328782 times.
✓ Branch 2 → 15 taken 337392 times.
✗ Branch 2 → 21 not taken.
886701 switch (ff_sws_pixel_type_size(type)) {
1126 220527 case 1:
1127
4/5
✓ Branch 3 → 4 taken 18627 times.
✓ Branch 3 → 5 taken 2666 times.
✓ Branch 3 → 6 taken 182447 times.
✓ Branch 3 → 7 taken 16787 times.
✗ Branch 3 → 8 not taken.
220527 switch (nb_planes) {
1128 18627 case 1: return AV_PIX_FMT_GRAY8;
1129 2666 case 2: return AV_PIX_FMT_YUV444P; // FIXME: no 2-plane planar fmt
1130 182447 case 3: return AV_PIX_FMT_YUV444P;
1131 16787 case 4: return AV_PIX_FMT_YUVA444P;
1132 }
1133 ✗ break;
1134 328782 case 2:
1135
4/5
✓ Branch 9 → 10 taken 51636 times.
✓ Branch 9 → 11 taken 5416 times.
✓ Branch 9 → 12 taken 242142 times.
✓ Branch 9 → 13 taken 29588 times.
✗ Branch 9 → 14 not taken.
328782 switch (nb_planes) {
1136 51636 case 1: return AV_PIX_FMT_GRAY16;
1137 5416 case 2: return AV_PIX_FMT_YUV444P16; // FIXME: no 2-plane planar fmt
1138 242142 case 3: return AV_PIX_FMT_YUV444P16;
1139 29588 case 4: return AV_PIX_FMT_YUVA444P16;
1140 }
1141 ✗ break;
1142 337392 case 4:
1143
4/5
✓ Branch 15 → 16 taken 61020 times.
✓ Branch 15 → 17 taken 10261 times.
✓ Branch 15 → 18 taken 231084 times.
✓ Branch 15 → 19 taken 35027 times.
✗ Branch 15 → 20 not taken.
337392 switch (nb_planes) {
1144 61020 case 1: return AV_PIX_FMT_GRAYF32;
1145 10261 case 2: return AV_PIX_FMT_GBRPF32; // FIXME: no 2-plane planar fmt
1146 231084 case 3: return AV_PIX_FMT_GBRPF32;
1147 35027 case 4: return AV_PIX_FMT_GBRAPF32;
1148 }
1149 ✗ break;
1150 }
1151
1152 ✗ av_unreachable("Invalid pixel type or number of planes?");
1153 return AV_PIX_FMT_NONE;
1154 }
1155
1156 886701 static void get_input_size(const SwsOpList *ops, SwsFormat *fmt)
1157 {
1158 886701 fmt->width = ops->src.width;
1159 886701 fmt->height = ops->src.height;
1160
1161 886701 const SwsOp *read = ff_sws_op_list_input(ops);
1162
2/4
✓ Branch 3 → 4 taken 886701 times.
✗ Branch 3 → 6 not taken.
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 886701 times.
886701 if (read && read->rw.filter.op == SWS_OP_FILTER_V) {
1163 ✗ fmt->height = read->rw.filter.kernel->dst_size;
1164
3/4
✓ Branch 6 → 7 taken 886701 times.
✗ Branch 6 → 9 not taken.
✓ Branch 7 → 8 taken 278637 times.
✓ Branch 7 → 9 taken 608064 times.
886701 } else if (read && read->rw.filter.op == SWS_OP_FILTER_H) {
1165 278637 fmt->width = read->rw.filter.kernel->dst_size;
1166 }
1167 886701 }
1168
1169 886701 int ff_sws_op_list_split_at(SwsOpList *ops1, SwsOpList **out_ops2, int index)
1170 {
1171 int ret;
1172
2/4
✓ Branch 2 → 3 taken 886701 times.
✗ Branch 2 → 4 not taken.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 886701 times.
886701 if (index <= 0 || index >= ops1->num_ops) {
1173 ✗ *out_ops2 = NULL;
1174 ✗ return 0;
1175 }
1176
1177 886701 const SwsOp *op = &ops1->ops[index];
1178 886701 const SwsOp *prev = &ops1->ops[index - 1];
1179
1180 886701 SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
1181
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 886701 times.
886701 if (!ops2)
1182 ✗ return AVERROR(ENOMEM);
1183
1184 /**
1185 * Not all components may be needed; but we need the ones that *are*
1186 * used to be contiguous for the write/read operations. So, first
1187 * compress them into a linearly ascending list of components
1188 */
1189 886701 int nb_planes = 0;
1190 886701 SwsSwizzleOp swiz_wr = SWS_SWIZZLE(0, 1, 2, 3);
1191 886701 SwsSwizzleOp swiz_rd = SWS_SWIZZLE(0, 1, 2, 3);
1192
2/2
✓ Branch 12 → 9 taken 3546804 times.
✓ Branch 12 → 13 taken 886701 times.
4433505 for (int i = 0; i < 4; i++) {
1193
2/2
✓ Branch 9 → 10 taken 2460596 times.
✓ Branch 9 → 11 taken 1086208 times.
3546804 if (SWS_OP_NEEDED(prev, i)) {
1194 2460596 const int o = nb_planes++;
1195 2460596 swiz_wr.in[o] = i;
1196 2460596 swiz_rd.in[i] = o;
1197 }
1198 }
1199
1200 /* Determine metadata for the intermediate format */
1201 886701 const SwsPixelType type = ff_sws_op_input_type(op);
1202 886701 ops2->src.format = get_planar_fmt(type, nb_planes);
1203 886701 ops2->src.desc = av_pix_fmt_desc_get(ops2->src.format);
1204 886701 ops2->src.field = FIELD_TOP;
1205 886701 ops2->src.interlaced = 0;
1206 886701 get_input_size(ops1, &ops2->src);
1207 886701 ops1->dst = ops2->src;
1208
1209
2/2
✓ Branch 19 → 18 taken 2460596 times.
✓ Branch 19 → 20 taken 886701 times.
3347297 for (int i = 0; i < nb_planes; i++) {
1210 2460596 const int idx = swiz_wr.in[i];
1211 2460596 ops1->plane_dst[i] = ops2->plane_src[i] = i;
1212 2460596 ops2->inputs[i].flags = prev->outputs[idx].flags;
1213 2460596 ops2->inputs[i].min = prev->outputs[idx].min;
1214 2460596 ops2->inputs[i].max = prev->outputs[idx].max;
1215 }
1216
1217 886701 ff_sws_op_list_remove_at(ops1, index, ops1->num_ops - index);
1218 886701 ff_sws_op_list_remove_at(ops2, 0, index);
1219 886701 op = NULL; /* the above command may invalidate op */
1220
1221
2/2
✓ Branch 22 → 23 taken 73940 times.
✓ Branch 22 → 27 taken 812761 times.
886701 if (swiz_wr.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1222 73940 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1223 .op = SWS_OP_SWIZZLE,
1224 .swizzle = swiz_wr,
1225 });
1226
1/2
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 73940 times.
73940 if (ret < 0)
1227 ✗ goto fail;
1228 }
1229
1230 886701 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1231 .op = SWS_OP_WRITE,
1232 .rw.type = type,
1233 .rw.elems = nb_planes,
1234 });
1235
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 886701 times.
886701 if (ret < 0)
1236 ✗ goto fail;
1237
1238 886701 ret = ff_sws_op_list_insert_at(ops2, 0, &(SwsOp) {
1239 .op = SWS_OP_READ,
1240 .rw.type = type,
1241 .rw.elems = nb_planes,
1242 });
1243
1/2
✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 886701 times.
886701 if (ret < 0)
1244 ✗ goto fail;
1245
1246
2/2
✓ Branch 33 → 34 taken 73940 times.
✓ Branch 33 → 38 taken 812761 times.
886701 if (swiz_rd.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1247 73940 ret = ff_sws_op_list_insert_at(ops2, 1, &(SwsOp) {
1248 .op = SWS_OP_SWIZZLE,
1249 .swizzle = swiz_rd,
1250 });
1251
1/2
✗ Branch 35 → 36 not taken.
✓ Branch 35 → 37 taken 73940 times.
73940 if (ret < 0)
1252 ✗ goto fail;
1253 }
1254
1255 886701 ret = ff_sws_op_list_optimize(ops1);
1256
1/2
✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 886701 times.
886701 if (ret < 0)
1257 ✗ goto fail;
1258
1259 886701 ret = ff_sws_op_list_optimize(ops2);
1260
1/2
✗ Branch 42 → 43 not taken.
✓ Branch 42 → 44 taken 886701 times.
886701 if (ret < 0)
1261 ✗ goto fail;
1262
1263 886701 *out_ops2 = ops2;
1264 886701 return 0;
1265
1266 ✗ fail:
1267 ✗ ff_sws_op_list_free(&ops2);
1268 ✗ return ret;
1269 }
1270