FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops_optimizer.c
Date: 2026-05-01 22:15:40
Exec Total Coverage
Lines: 417 570 73.2%
Functions: 9 13 69.2%
Branches: 339 480 70.6%

Line Branch Exec Source
1 /**
2 * Copyright (C) 2025 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "libavutil/attributes.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/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 51904 static bool op_commute_clear(SwsOp *op, SwsOp *next)
42 {
43 51904 SwsClearOp tmp = {0};
44
45 av_assert1(op->op == SWS_OP_CLEAR);
46
5/7
✓ Branch 0 taken 9120 times.
✓ Branch 1 taken 8778 times.
✓ Branch 2 taken 6532 times.
✓ Branch 3 taken 3529 times.
✓ Branch 4 taken 23945 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
51904 switch (next->op) {
47 9120 case SWS_OP_CONVERT:
48 9120 op->type = next->convert.to;
49 av_fallthrough;
50 17898 case SWS_OP_LSHIFT:
51 case SWS_OP_RSHIFT:
52 case SWS_OP_DITHER:
53 case SWS_OP_MIN:
54 case SWS_OP_MAX:
55 case SWS_OP_SCALE:
56 case SWS_OP_READ:
57 case SWS_OP_FILTER_H:
58 case SWS_OP_FILTER_V:
59 17898 ff_sws_apply_op_q(next, op->clear.value);
60 17898 return true;
61 6532 case SWS_OP_SWIZZLE:
62 6532 op->clear.mask = ff_sws_comp_mask_swizzle(op->clear.mask, next->swizzle);
63 6532 ff_sws_apply_op_q(next, op->clear.value);
64 6532 return true;
65 3529 case SWS_OP_SWAP_BYTES:
66
2/3
✓ Branch 0 taken 2920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 609 times.
3529 switch (next->type) {
67 2920 case SWS_PIXEL_U16:
68 2920 ff_sws_apply_op_q(next, op->clear.value); /* always works */
69 2920 return true;
70 case SWS_PIXEL_U32:
71 for (int i = 0; i < 4; i++) {
72 if (!SWS_COMP_TEST(op->clear.mask, i))
73 continue;
74 uint32_t v = av_bswap32(op->clear.value[i].num);
75 if (v > INT_MAX)
76 return false; /* can't represent as AVRational anymore */
77 tmp.value[i] = Q(v);
78 }
79 op->clear = tmp;
80 return true;
81 609 default:
82 609 return false;
83 }
84 23945 case SWS_OP_INVALID:
85 case SWS_OP_WRITE:
86 case SWS_OP_LINEAR:
87 case SWS_OP_PACK:
88 case SWS_OP_UNPACK:
89 case SWS_OP_CLEAR:
90 23945 return false;
91 case SWS_OP_TYPE_NB:
92 break;
93 }
94
95 av_unreachable("Invalid operation type!");
96 return false;
97 }
98
99 /**
100 * Try to commute a swizzle op with the next operation. Makes any adjustments
101 * to the operations as needed, but does not perform the actual commutation.
102 *
103 * Returns whether successful.
104 */
105 60367 static bool op_commute_swizzle(SwsOp *op, SwsOp *next)
106 {
107 60367 bool seen[4] = {0};
108
109 av_assert1(op->op == SWS_OP_SWIZZLE);
110
5/7
✓ Branch 0 taken 19578 times.
✓ Branch 1 taken 11779 times.
✓ Branch 2 taken 3178 times.
✓ Branch 3 taken 2814 times.
✓ Branch 4 taken 23018 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
60367 switch (next->op) {
111 19578 case SWS_OP_CONVERT:
112 19578 op->type = next->convert.to;
113 av_fallthrough;
114 31357 case SWS_OP_SWAP_BYTES:
115 case SWS_OP_LSHIFT:
116 case SWS_OP_RSHIFT:
117 case SWS_OP_SCALE:
118 case SWS_OP_FILTER_H:
119 case SWS_OP_FILTER_V:
120 31357 return true;
121
122 /**
123 * We can commute per-channel ops only if the per-channel constants are the
124 * same for all duplicated channels; e.g.:
125 * SWIZZLE {0, 0, 0, 3}
126 * NEXT {x, x, x, w}
127 * ->
128 * NEXT {x, _, _, w}
129 * SWIZZLE {0, 0, 0, 3}
130 */
131 3178 case SWS_OP_MIN:
132 case SWS_OP_MAX: {
133 3178 const SwsClampOp c = next->clamp;
134
2/2
✓ Branch 0 taken 12712 times.
✓ Branch 1 taken 3178 times.
15890 for (int i = 0; i < 4; i++) {
135
2/2
✓ Branch 0 taken 2934 times.
✓ Branch 1 taken 9778 times.
12712 if (!SWS_OP_NEEDED(op, i))
136 2934 continue;
137 9778 const int j = op->swizzle.in[i];
138
3/4
✓ Branch 0 taken 2124 times.
✓ Branch 1 taken 7654 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2124 times.
9778 if (seen[j] && av_cmp_q(next->clamp.limit[j], c.limit[i]))
139 return false;
140 9778 next->clamp.limit[j] = c.limit[i];
141 9778 seen[j] = true;
142 }
143 3178 return true;
144 }
145
146 2814 case SWS_OP_DITHER: {
147 2814 const SwsDitherOp d = next->dither;
148
2/2
✓ Branch 0 taken 10440 times.
✓ Branch 1 taken 2406 times.
12846 for (int i = 0; i < 4; i++) {
149
2/2
✓ Branch 0 taken 2260 times.
✓ Branch 1 taken 8180 times.
10440 if (!SWS_OP_NEEDED(op, i))
150 2260 continue;
151 8180 const int j = op->swizzle.in[i];
152
4/4
✓ Branch 0 taken 1740 times.
✓ Branch 1 taken 6440 times.
✓ Branch 2 taken 408 times.
✓ Branch 3 taken 1332 times.
8180 if (seen[j] && next->dither.y_offset[j] != d.y_offset[i])
153 408 return false;
154 7772 next->dither.y_offset[j] = d.y_offset[i];
155 7772 seen[j] = true;
156 }
157 2406 return true;
158 }
159
160 23018 case SWS_OP_INVALID:
161 case SWS_OP_READ:
162 case SWS_OP_WRITE:
163 case SWS_OP_SWIZZLE:
164 case SWS_OP_CLEAR:
165 case SWS_OP_LINEAR:
166 case SWS_OP_PACK:
167 case SWS_OP_UNPACK:
168 23018 return false;
169 case SWS_OP_TYPE_NB:
170 break;
171 }
172
173 av_unreachable("Invalid operation type!");
174 return false;
175 }
176
177 /**
178 * Try to commute a filter op with the previous operation. Makes any
179 * adjustments to the operations as needed, but does not perform the actual
180 * commutation.
181 *
182 * Returns whether successful.
183 */
184 static bool op_commute_filter(SwsOp *op, SwsOp *prev)
185 {
186 switch (prev->op) {
187 case SWS_OP_SWIZZLE:
188 case SWS_OP_SCALE:
189 case SWS_OP_LINEAR:
190 case SWS_OP_DITHER:
191 prev->type = SWS_PIXEL_F32;
192 return true;
193 case SWS_OP_CONVERT:
194 if (prev->convert.to == SWS_PIXEL_F32) {
195 av_assert0(!prev->convert.expand);
196 FFSWAP(SwsPixelType, op->type, prev->type);
197 return true;
198 }
199 return false;
200 case SWS_OP_INVALID:
201 case SWS_OP_READ:
202 case SWS_OP_WRITE:
203 case SWS_OP_SWAP_BYTES:
204 case SWS_OP_UNPACK:
205 case SWS_OP_PACK:
206 case SWS_OP_LSHIFT:
207 case SWS_OP_RSHIFT:
208 case SWS_OP_CLEAR:
209 case SWS_OP_MIN:
210 case SWS_OP_MAX:
211 case SWS_OP_FILTER_H:
212 case SWS_OP_FILTER_V:
213 return false;
214 case SWS_OP_TYPE_NB:
215 break;
216 }
217
218 av_unreachable("Invalid operation type!");
219 return false;
220 }
221
222 /* returns log2(x) only if x is a power of two, or 0 otherwise */
223 41654 static int exact_log2(const int x)
224 {
225 int p;
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41654 times.
41654 if (x <= 0)
227 return 0;
228 41654 p = av_log2(x);
229
2/2
✓ Branch 0 taken 15230 times.
✓ Branch 1 taken 26424 times.
41654 return (1 << p) == x ? p : 0;
230 }
231
232 83751 static int exact_log2_q(const AVRational x)
233 {
234
2/2
✓ Branch 0 taken 22547 times.
✓ Branch 1 taken 61204 times.
83751 if (x.den == 1)
235 22547 return exact_log2(x.num);
236
2/2
✓ Branch 0 taken 19107 times.
✓ Branch 1 taken 42097 times.
61204 else if (x.num == 1)
237 19107 return -exact_log2(x.den);
238 else
239 42097 return 0;
240 }
241
242 /**
243 * If a linear operation can be reduced to a scalar multiplication, returns
244 * the corresponding scaling factor, or 0 otherwise.
245 */
246 121637 static bool extract_scalar(const SwsLinearOp *c, SwsComps comps, SwsComps prev,
247 SwsScaleOp *out_scale)
248 {
249 121637 SwsScaleOp scale = {0};
250
251 /* There are components not on the main diagonal */
252
2/2
✓ Branch 0 taken 93244 times.
✓ Branch 1 taken 28393 times.
121637 if (c->mask & ~SWS_MASK_DIAG4)
253 93244 return false;
254
255
2/2
✓ Branch 0 taken 85250 times.
✓ Branch 1 taken 10262 times.
95512 for (int i = 0; i < 4; i++) {
256 85250 const AVRational s = c->m[i][i];
257
1/2
✓ Branch 0 taken 85250 times.
✗ Branch 1 not taken.
85250 if ((prev.flags[i] & SWS_COMP_ZERO) ||
258
2/2
✓ Branch 0 taken 10702 times.
✓ Branch 1 taken 74548 times.
85250 (comps.flags[i] & SWS_COMP_GARBAGE))
259 10702 continue;
260
4/4
✓ Branch 0 taken 46155 times.
✓ Branch 1 taken 28393 times.
✓ Branch 3 taken 18131 times.
✓ Branch 4 taken 28024 times.
74548 if (scale.factor.den && av_cmp_q(s, scale.factor))
261 18131 return false;
262 56417 scale.factor = s;
263 }
264
265
1/2
✓ Branch 0 taken 10262 times.
✗ Branch 1 not taken.
10262 if (scale.factor.den)
266 10262 *out_scale = scale;
267 10262 return scale.factor.den;
268 }
269
270 /* Extracts an integer clear operation (subset) from the given linear op. */
271 130383 static bool extract_constant_rows(SwsLinearOp *c, SwsComps prev,
272 SwsClearOp *out_clear)
273 {
274 130383 SwsClearOp clear = {0};
275 130383 bool ret = false;
276
277
2/2
✓ Branch 0 taken 521532 times.
✓ Branch 1 taken 130383 times.
651915 for (int i = 0; i < 4; i++) {
278 521532 bool const_row = c->m[i][4].den == 1; /* offset is integer */
279
2/2
✓ Branch 0 taken 2086128 times.
✓ Branch 1 taken 521532 times.
2607660 for (int j = 0; j < 4; j++) {
280
2/2
✓ Branch 0 taken 856102 times.
✓ Branch 1 taken 1230026 times.
2942230 const_row &= c->m[i][j].num == 0 || /* scalar is zero */
281
2/2
✓ Branch 0 taken 17304 times.
✓ Branch 1 taken 838798 times.
856102 (prev.flags[j] & SWS_COMP_ZERO); /* input is zero */
282 }
283
3/4
✓ Branch 0 taken 10740 times.
✓ Branch 1 taken 510792 times.
✓ Branch 2 taken 10740 times.
✗ Branch 3 not taken.
521532 if (const_row && (c->mask & SWS_MASK_ROW(i))) {
284 10740 clear.mask |= SWS_COMP(i);
285 10740 clear.value[i] = c->m[i][4];
286
2/2
✓ Branch 0 taken 53700 times.
✓ Branch 1 taken 10740 times.
64440 for (int j = 0; j < 5; j++)
287 53700 c->m[i][j] = Q(i == j);
288 10740 c->mask &= ~SWS_MASK_ROW(i);
289 10740 ret = true;
290 }
291 }
292
293
2/2
✓ Branch 0 taken 8746 times.
✓ Branch 1 taken 121637 times.
130383 if (ret)
294 8746 *out_clear = clear;
295 130383 return ret;
296 }
297
298 /* Unswizzle a linear operation by aligning single-input rows with
299 * their corresponding diagonal */
300 111375 static bool extract_swizzle(SwsLinearOp *op, SwsComps prev, SwsSwizzleOp *out_swiz)
301 {
302 111375 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
303 111375 SwsLinearOp c = *op;
304
305 /* Find non-zero coefficients in the main 4x4 matrix */
306 111375 uint32_t nonzero = 0;
307
2/2
✓ Branch 0 taken 445500 times.
✓ Branch 1 taken 111375 times.
556875 for (int i = 0; i < 4; i++) {
308
2/2
✓ Branch 0 taken 1782000 times.
✓ Branch 1 taken 445500 times.
2227500 for (int j = 0; j < 4; j++) {
309
4/4
✓ Branch 0 taken 763466 times.
✓ Branch 1 taken 1018534 times.
✓ Branch 2 taken 5184 times.
✓ Branch 3 taken 758282 times.
1782000 if (!c.m[i][j].num || (prev.flags[j] & SWS_COMP_ZERO))
310 1023718 continue;
311 758282 nonzero |= SWS_MASK(i, j);
312 }
313 }
314
315 /* If a value is unique in its row and the target column is
316 * empty, move it there and update the input swizzle */
317
2/2
✓ Branch 0 taken 445500 times.
✓ Branch 1 taken 111375 times.
556875 for (int i = 0; i < 4; i++) {
318
2/2
✓ Branch 0 taken 440316 times.
✓ Branch 1 taken 5184 times.
445500 if (nonzero & SWS_MASK_COL(i))
319 440316 continue; /* target column is not empty */
320
1/2
✓ Branch 0 taken 5184 times.
✗ Branch 1 not taken.
5184 for (int j = 0; j < 4; j++) {
321
1/2
✓ Branch 0 taken 5184 times.
✗ Branch 1 not taken.
5184 if ((nonzero & SWS_MASK_ROW(i)) == SWS_MASK(i, j)) {
322 /* Move coefficient to the diagonal */
323 5184 c.m[i][i] = c.m[i][j];
324 5184 c.m[i][j] = Q(0);
325 5184 swiz.in[i] = j;
326 5184 break;
327 }
328 }
329 }
330
331
2/2
✓ Branch 0 taken 108783 times.
✓ Branch 1 taken 2592 times.
111375 if (swiz.mask == SWS_SWIZZLE(0, 1, 2, 3).mask)
332 108783 return false; /* no swizzle was identified */
333
334 2592 c.mask = ff_sws_linear_mask(c);
335 2592 *out_swiz = swiz;
336 2592 *op = c;
337 2592 return true;
338 }
339
340 31704 int ff_sws_op_list_optimize(SwsOpList *ops)
341 {
342 int ret;
343
344 386416 retry:
345 418120 ff_sws_op_list_update_comps(ops);
346
347 /* Try to push filters towards the input; do this first to unblock
348 * in-place optimizations like linear op fusion */
349
2/2
✓ Branch 0 taken 4086978 times.
✓ Branch 1 taken 418120 times.
4505098 for (int n = 1; n < ops->num_ops; n++) {
350 4086978 SwsOp *op = &ops->ops[n];
351 4086978 SwsOp *prev = &ops->ops[n - 1];
352
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4086978 times.
4086978 switch (op->op) {
354 case SWS_OP_FILTER_H:
355 case SWS_OP_FILTER_V:
356 if (op_commute_filter(op, prev)) {
357 FFSWAP(SwsOp, *op, *prev);
358 goto retry;
359 }
360 break;
361 }
362 }
363
364 /* Apply all in-place optimizations (that do not re-order the list) */
365
2/2
✓ Branch 0 taken 2383753 times.
✓ Branch 1 taken 97819 times.
2481572 for (int n = 0; n < ops->num_ops; n++) {
366 2383753 SwsOp dummy = {0};
367 2383753 SwsOp *op = &ops->ops[n];
368
2/2
✓ Branch 0 taken 1965633 times.
✓ Branch 1 taken 418120 times.
2383753 SwsOp *prev = n ? &ops->ops[n - 1] : &dummy;
369
2/2
✓ Branch 0 taken 2285934 times.
✓ Branch 1 taken 97819 times.
2383753 SwsOp *next = n + 1 < ops->num_ops ? &ops->ops[n + 1] : &dummy;
370
371 /* common helper variable */
372 2383753 bool noop = true;
373
374
4/4
✓ Branch 0 taken 178158 times.
✓ Branch 1 taken 2205595 times.
✓ Branch 2 taken 100059 times.
✓ Branch 3 taken 78099 times.
2383753 if (!SWS_OP_NEEDED(op, 0) && !SWS_OP_NEEDED(op, 1) &&
375
3/4
✓ Branch 0 taken 97819 times.
✓ Branch 1 taken 2240 times.
✓ Branch 2 taken 97819 times.
✗ Branch 3 not taken.
100059 !SWS_OP_NEEDED(op, 2) && !SWS_OP_NEEDED(op, 3) &&
376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 97819 times.
97819 op->op != SWS_OP_WRITE)
377 {
378 /* Remove any operation whose output is not needed */
379 ff_sws_op_list_remove_at(ops, n, 1);
380 320301 goto retry;
381 }
382
383
13/14
✓ Branch 0 taken 418120 times.
✓ Branch 1 taken 198572 times.
✓ Branch 2 taken 77772 times.
✓ Branch 3 taken 44114 times.
✓ Branch 4 taken 164131 times.
✓ Branch 5 taken 286900 times.
✓ Branch 6 taken 497029 times.
✓ Branch 7 taken 88800 times.
✓ Branch 8 taken 56524 times.
✓ Branch 9 taken 115816 times.
✓ Branch 10 taken 235355 times.
✓ Branch 11 taken 83751 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 116869 times.
2383753 switch (op->op) {
384 418120 case SWS_OP_READ:
385 /* "Compress" planar reads where not all components are needed */
386
2/2
✓ Branch 0 taken 231385 times.
✓ Branch 1 taken 186735 times.
418120 if (!op->rw.packed) {
387 231385 SwsSwizzleOp swiz = SWS_SWIZZLE(0, 1, 2, 3);
388 231385 int nb_planes = 0;
389
2/2
✓ Branch 0 taken 567045 times.
✓ Branch 1 taken 231385 times.
798430 for (int i = 0; i < op->rw.elems; i++) {
390
2/2
✓ Branch 0 taken 5180 times.
✓ Branch 1 taken 561865 times.
567045 if (!SWS_OP_NEEDED(op, i)) {
391 5180 swiz.in[i] = 3 - (i - nb_planes); /* map to unused plane */
392 5180 continue;
393 }
394
395 561865 const int idx = nb_planes++;
396 av_assert1(idx <= i);
397 561865 ops->plane_src[idx] = ops->plane_src[i];
398 561865 swiz.in[i] = idx;
399 }
400
401
2/2
✓ Branch 0 taken 4230 times.
✓ Branch 1 taken 227155 times.
231385 if (nb_planes < op->rw.elems) {
402 4230 op->rw.elems = nb_planes;
403
2/4
✓ Branch 0 taken 4230 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4230 times.
4230 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
404 .op = SWS_OP_SWIZZLE,
405 .type = op->rw.filter ? SWS_PIXEL_F32 : op->type,
406 .swizzle = swiz,
407 }));
408 4230 goto retry;
409 }
410 }
411 413890 break;
412
413 198572 case SWS_OP_SWAP_BYTES:
414 /* Redundant (double) swap */
415
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 198363 times.
198572 if (next->op == SWS_OP_SWAP_BYTES) {
416 209 ff_sws_op_list_remove_at(ops, n, 2);
417 209 goto retry;
418 }
419 198363 break;
420
421 77772 case SWS_OP_UNPACK:
422 /* Redundant unpack+pack */
423
3/4
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 77726 times.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
77772 if (next->op == SWS_OP_PACK && next->type == op->type &&
424
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 next->pack.pattern[0] == op->pack.pattern[0] &&
425
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 next->pack.pattern[1] == op->pack.pattern[1] &&
426
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 next->pack.pattern[2] == op->pack.pattern[2] &&
427
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 next->pack.pattern[3] == op->pack.pattern[3])
428 {
429 46 ff_sws_op_list_remove_at(ops, n, 2);
430 46 goto retry;
431 }
432 77726 break;
433
434 44114 case SWS_OP_LSHIFT:
435 case SWS_OP_RSHIFT:
436 /* Two shifts in the same direction */
437
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 43910 times.
44114 if (next->op == op->op) {
438 204 op->shift.amount += next->shift.amount;
439 204 ff_sws_op_list_remove_at(ops, n + 1, 1);
440 204 goto retry;
441 }
442
443 /* No-op shift */
444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43910 times.
43910 if (!op->shift.amount) {
445 ff_sws_op_list_remove_at(ops, n, 1);
446 goto retry;
447 }
448 43910 break;
449
450 164131 case SWS_OP_CLEAR:
451
2/2
✓ Branch 0 taken 656524 times.
✓ Branch 1 taken 164131 times.
820655 for (int i = 0; i < 4; i++) {
452
2/2
✓ Branch 0 taken 439631 times.
✓ Branch 1 taken 216893 times.
656524 if (!SWS_COMP_TEST(op->clear.mask, i))
453 439631 continue;
454
455
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 216893 times.
216893 if ((prev->comps.flags[i] & SWS_COMP_ZERO) &&
456 !(prev->comps.flags[i] & SWS_COMP_GARBAGE) &&
457 op->clear.value[i].num == 0)
458 {
459 /* Redundant clear-to-zero of zero component */
460 op->clear.mask ^= SWS_COMP(i);
461
2/2
✓ Branch 0 taken 31704 times.
✓ Branch 1 taken 185189 times.
216893 } else if (!SWS_OP_NEEDED(op, i)) {
462 /* Unnecessary clear of unused component */
463 31704 op->clear.mask ^= SWS_COMP(i);
464 } else {
465 185189 noop = false;
466 }
467 }
468
469
2/2
✓ Branch 0 taken 31704 times.
✓ Branch 1 taken 132427 times.
164131 if (noop) {
470 31704 ff_sws_op_list_remove_at(ops, n, 1);
471 31704 goto retry;
472 }
473
474 /* Transitive clear */
475
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 132237 times.
132427 if (next->op == SWS_OP_CLEAR) {
476
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 190 times.
950 for (int i = 0; i < 4; i++) {
477
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 570 times.
760 if (SWS_COMP_TEST(next->clear.mask, i))
478 190 op->clear.value[i] = next->clear.value[i];
479 }
480 190 op->clear.mask |= next->clear.mask;
481 190 ff_sws_op_list_remove_at(ops, n + 1, 1);
482 190 goto retry;
483 }
484 132237 break;
485
486 286900 case SWS_OP_SWIZZLE:
487
2/2
✓ Branch 0 taken 1147600 times.
✓ Branch 1 taken 286900 times.
1434500 for (int i = 0; i < 4; i++) {
488
2/2
✓ Branch 0 taken 283491 times.
✓ Branch 1 taken 864109 times.
1147600 if (!SWS_OP_NEEDED(op, i))
489 283491 continue;
490
2/2
✓ Branch 0 taken 594279 times.
✓ Branch 1 taken 269830 times.
864109 if (op->swizzle.in[i] != i)
491 594279 noop = false;
492 }
493
494 /* Identity swizzle */
495
2/2
✓ Branch 0 taken 45109 times.
✓ Branch 1 taken 241791 times.
286900 if (noop) {
496 45109 ff_sws_op_list_remove_at(ops, n, 1);
497 45109 goto retry;
498 }
499
500 /* Transitive swizzle */
501
2/2
✓ Branch 0 taken 3586 times.
✓ Branch 1 taken 238205 times.
241791 if (next->op == SWS_OP_SWIZZLE) {
502 3586 const SwsSwizzleOp orig = op->swizzle;
503
2/2
✓ Branch 0 taken 14344 times.
✓ Branch 1 taken 3586 times.
17930 for (int i = 0; i < 4; i++)
504 14344 op->swizzle.in[i] = orig.in[next->swizzle.in[i]];
505 3586 ff_sws_op_list_remove_at(ops, n + 1, 1);
506 3586 goto retry;
507 }
508
509 /* Swizzle planes instead of components, if possible */
510
4/4
✓ Branch 0 taken 51682 times.
✓ Branch 1 taken 186523 times.
✓ Branch 2 taken 8992 times.
✓ Branch 3 taken 42690 times.
238205 if (prev->op == SWS_OP_READ && !prev->rw.packed) {
511
2/2
✓ Branch 0 taken 13310 times.
✓ Branch 1 taken 1186 times.
14496 for (int dst = 0; dst < prev->rw.elems; dst++) {
512 13310 const int src = op->swizzle.in[dst];
513
4/4
✓ Branch 0 taken 8216 times.
✓ Branch 1 taken 5094 times.
✓ Branch 2 taken 7806 times.
✓ Branch 3 taken 410 times.
13310 if (src > dst && src < prev->rw.elems) {
514 7806 FFSWAP(int, ops->plane_src[dst], ops->plane_src[src]);
515
2/2
✓ Branch 0 taken 27330 times.
✓ Branch 1 taken 7806 times.
35136 for (int i = dst; i < 4; i++) {
516
2/2
✓ Branch 0 taken 7806 times.
✓ Branch 1 taken 19524 times.
27330 if (op->swizzle.in[i] == dst)
517 7806 op->swizzle.in[i] = src;
518
2/2
✓ Branch 0 taken 7806 times.
✓ Branch 1 taken 11718 times.
19524 else if (op->swizzle.in[i] == src)
519 7806 op->swizzle.in[i] = dst;
520 }
521 7806 goto retry;
522 }
523 }
524 }
525
526
4/4
✓ Branch 0 taken 25297 times.
✓ Branch 1 taken 205102 times.
✓ Branch 2 taken 13413 times.
✓ Branch 3 taken 11884 times.
230399 if (next->op == SWS_OP_WRITE && !next->rw.packed) {
527
2/2
✓ Branch 0 taken 15805 times.
✓ Branch 1 taken 1118 times.
16923 for (int dst = 0; dst < next->rw.elems; dst++) {
528 15805 const int src = op->swizzle.in[dst];
529
4/4
✓ Branch 0 taken 12751 times.
✓ Branch 1 taken 3054 times.
✓ Branch 2 taken 12295 times.
✓ Branch 3 taken 456 times.
15805 if (src > dst && src < next->rw.elems) {
530 12295 FFSWAP(int, ops->plane_dst[dst], ops->plane_dst[src]);
531 12295 FFSWAP(int, op->swizzle.in[dst], op->swizzle.in[src]);
532 12295 goto retry;
533 }
534 }
535 }
536 218104 break;
537
538 497029 case SWS_OP_CONVERT:
539 /* No-op conversion */
540
2/2
✓ Branch 0 taken 9088 times.
✓ Branch 1 taken 487941 times.
497029 if (op->type == op->convert.to) {
541 9088 ff_sws_op_list_remove_at(ops, n, 1);
542 9088 goto retry;
543 }
544
545 /* Transitive conversion */
546
2/2
✓ Branch 0 taken 12941 times.
✓ Branch 1 taken 475000 times.
487941 if (next->op == SWS_OP_CONVERT &&
547
1/2
✓ Branch 0 taken 12941 times.
✗ Branch 1 not taken.
12941 op->convert.expand == next->convert.expand)
548 {
549 av_assert1(op->convert.to == next->type);
550 12941 op->convert.to = next->convert.to;
551 12941 ff_sws_op_list_remove_at(ops, n + 1, 1);
552 12941 goto retry;
553 }
554
555 /* Conversion followed by integer expansion */
556
3/4
✓ Branch 0 taken 64481 times.
✓ Branch 1 taken 410519 times.
✓ Branch 2 taken 64481 times.
✗ Branch 3 not taken.
475000 if (next->op == SWS_OP_SCALE && !op->convert.expand &&
557
1/2
✓ Branch 0 taken 64481 times.
✗ Branch 1 not taken.
64481 ff_sws_pixel_type_is_int(op->type) &&
558
4/4
✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 63403 times.
✓ Branch 2 taken 360 times.
✓ Branch 3 taken 718 times.
65559 ff_sws_pixel_type_is_int(op->convert.to) &&
559 1078 !av_cmp_q(next->scale.factor,
560 ff_sws_pixel_expand(op->type, op->convert.to)))
561 {
562 360 op->convert.expand = true;
563 360 ff_sws_op_list_remove_at(ops, n + 1, 1);
564 360 goto retry;
565 }
566 474640 break;
567
568 88800 case SWS_OP_MIN:
569
2/2
✓ Branch 0 taken 355200 times.
✓ Branch 1 taken 88800 times.
444000 for (int i = 0; i < 4; i++) {
570
4/4
✓ Branch 0 taken 261646 times.
✓ Branch 1 taken 93554 times.
✓ Branch 2 taken 3000 times.
✓ Branch 3 taken 258646 times.
355200 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
571 96554 continue;
572
2/2
✓ Branch 1 taken 201974 times.
✓ Branch 2 taken 56672 times.
258646 if (av_cmp_q(op->clamp.limit[i], prev->comps.max[i]) < 0)
573 201974 noop = false;
574 }
575
576
2/2
✓ Branch 0 taken 13260 times.
✓ Branch 1 taken 75540 times.
88800 if (noop) {
577 13260 ff_sws_op_list_remove_at(ops, n, 1);
578 13260 goto retry;
579 }
580 75540 break;
581
582 56524 case SWS_OP_MAX:
583
2/2
✓ Branch 0 taken 226096 times.
✓ Branch 1 taken 56524 times.
282620 for (int i = 0; i < 4; i++) {
584
3/4
✓ Branch 0 taken 166108 times.
✓ Branch 1 taken 59988 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 166108 times.
226096 if (!SWS_OP_NEEDED(op, i) || !op->clamp.limit[i].den)
585 59988 continue;
586
2/2
✓ Branch 1 taken 93488 times.
✓ Branch 2 taken 72620 times.
166108 if (av_cmp_q(prev->comps.min[i], op->clamp.limit[i]) < 0)
587 93488 noop = false;
588 }
589
590
2/2
✓ Branch 0 taken 21150 times.
✓ Branch 1 taken 35374 times.
56524 if (noop) {
591 21150 ff_sws_op_list_remove_at(ops, n, 1);
592 21150 goto retry;
593 }
594 35374 break;
595
596 115816 case SWS_OP_DITHER:
597
2/2
✓ Branch 0 taken 440575 times.
✓ Branch 1 taken 86955 times.
527530 for (int i = 0; i < 4; i++) {
598
2/2
✓ Branch 0 taken 138559 times.
✓ Branch 1 taken 302016 times.
440575 if (op->dither.y_offset[i] < 0)
599 138559 continue;
600
4/4
✓ Branch 0 taken 284519 times.
✓ Branch 1 taken 17497 times.
✓ Branch 2 taken 11364 times.
✓ Branch 3 taken 273155 times.
302016 if (!SWS_OP_NEEDED(op, i) || (prev->comps.flags[i] & SWS_COMP_EXACT)) {
601 28861 op->dither.y_offset[i] = -1; /* unnecessary dither */
602 28861 goto retry;
603 } else {
604 273155 noop = false;
605 }
606 }
607
608
2/2
✓ Branch 0 taken 1712 times.
✓ Branch 1 taken 85243 times.
86955 if (noop) {
609 1712 ff_sws_op_list_remove_at(ops, n, 1);
610 1712 goto retry;
611 }
612 85243 break;
613
614 235355 case SWS_OP_LINEAR: {
615 SwsSwizzleOp swizzle;
616 SwsClearOp clear;
617 SwsScaleOp scale;
618
619 /* No-op (identity) linear operation */
620
2/2
✓ Branch 0 taken 3018 times.
✓ Branch 1 taken 232337 times.
235355 if (!op->lin.mask) {
621 3018 ff_sws_op_list_remove_at(ops, n, 1);
622 126572 goto retry;
623 }
624
625
2/2
✓ Branch 0 taken 59722 times.
✓ Branch 1 taken 172615 times.
232337 if (next->op == SWS_OP_LINEAR) {
626 /* 5x5 matrix multiplication after appending [ 0 0 0 0 1 ] */
627 59722 const SwsLinearOp m1 = op->lin;
628 59722 const SwsLinearOp m2 = next->lin;
629
2/2
✓ Branch 0 taken 238888 times.
✓ Branch 1 taken 59722 times.
298610 for (int i = 0; i < 4; i++) {
630
2/2
✓ Branch 0 taken 1194440 times.
✓ Branch 1 taken 238888 times.
1433328 for (int j = 0; j < 5; j++) {
631 1194440 AVRational sum = Q(0);
632
2/2
✓ Branch 0 taken 4777760 times.
✓ Branch 1 taken 1194440 times.
5972200 for (int k = 0; k < 4; k++)
633 4777760 sum = av_add_q(sum, av_mul_q(m2.m[i][k], m1.m[k][j]));
634
2/2
✓ Branch 0 taken 238888 times.
✓ Branch 1 taken 955552 times.
1194440 if (j == 4) /* m1.m[4][j] == 1 */
635 238888 sum = av_add_q(sum, m2.m[i][4]);
636 1194440 op->lin.m[i][j] = sum;
637 }
638 }
639 59722 op->lin.mask = ff_sws_linear_mask(op->lin);
640 59722 ff_sws_op_list_remove_at(ops, n + 1, 1);
641 59722 goto retry;
642 }
643
644 /* Optimize away zero columns */
645
2/2
✓ Branch 0 taken 678232 times.
✓ Branch 1 taken 158479 times.
836711 for (int j = 0; j < 4; j++) {
646 678232 const uint32_t col = SWS_MASK_COL(j);
647
4/4
✓ Branch 0 taken 43384 times.
✓ Branch 1 taken 634848 times.
✓ Branch 2 taken 29248 times.
✓ Branch 3 taken 14136 times.
678232 if (!(prev->comps.flags[j] & SWS_COMP_ZERO) || !(op->lin.mask & col))
648 664096 continue;
649
2/2
✓ Branch 0 taken 56544 times.
✓ Branch 1 taken 14136 times.
70680 for (int i = 0; i < 4; i++)
650 56544 op->lin.m[i][j] = Q(i == j);
651 14136 op->lin.mask &= ~col;
652 14136 goto retry;
653 }
654
655 /* Optimize away unused rows */
656
2/2
✓ Branch 0 taken 621688 times.
✓ Branch 1 taken 130383 times.
752071 for (int i = 0; i < 4; i++) {
657 621688 const uint32_t row = SWS_MASK_ROW(i);
658
4/4
✓ Branch 0 taken 219254 times.
✓ Branch 1 taken 402434 times.
✓ Branch 2 taken 191158 times.
✓ Branch 3 taken 28096 times.
621688 if (SWS_OP_NEEDED(op, i) || !(op->lin.mask & row))
659 593592 continue;
660
2/2
✓ Branch 0 taken 140480 times.
✓ Branch 1 taken 28096 times.
168576 for (int j = 0; j < 5; j++)
661 140480 op->lin.m[i][j] = Q(i == j);
662 28096 op->lin.mask &= ~row;
663 28096 goto retry;
664 }
665
666 /* Convert constant rows to explicit clear instruction */
667
2/2
✓ Branch 1 taken 8746 times.
✓ Branch 2 taken 121637 times.
130383 if (extract_constant_rows(&op->lin, prev->comps, &clear)) {
668
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8746 times.
8746 RET(ff_sws_op_list_insert_at(ops, n + 1, &(SwsOp) {
669 .op = SWS_OP_CLEAR,
670 .type = op->type,
671 .comps = op->comps,
672 .clear = clear,
673 }));
674 8746 goto retry;
675 }
676
677 /* Multiplication by scalar constant */
678
2/2
✓ Branch 1 taken 10262 times.
✓ Branch 2 taken 111375 times.
121637 if (extract_scalar(&op->lin, op->comps, prev->comps, &scale)) {
679 10262 op->op = SWS_OP_SCALE;
680 10262 op->scale = scale;
681 10262 goto retry;
682 }
683
684 /* Swizzle by fixed pattern */
685
2/2
✓ Branch 1 taken 2592 times.
✓ Branch 2 taken 108783 times.
111375 if (extract_swizzle(&op->lin, prev->comps, &swizzle)) {
686
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2592 times.
2592 RET(ff_sws_op_list_insert_at(ops, n, &(SwsOp) {
687 .op = SWS_OP_SWIZZLE,
688 .type = op->type,
689 .swizzle = swizzle,
690 }));
691 2592 goto retry;
692 }
693 108783 break;
694 }
695
696 83751 case SWS_OP_SCALE: {
697 83751 const int factor2 = exact_log2_q(op->scale.factor);
698
699 /* No-op scaling */
700
3/4
✓ Branch 0 taken 19107 times.
✓ Branch 1 taken 64644 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19107 times.
83751 if (op->scale.factor.num == 1 && op->scale.factor.den == 1) {
701 ff_sws_op_list_remove_at(ops, n, 1);
702 goto retry;
703 }
704
705 /* Merge consecutive scaling operations (that don't overflow) */
706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83751 times.
83751 if (next->op == SWS_OP_SCALE) {
707 int64_t p = op->scale.factor.num * (int64_t) next->scale.factor.num;
708 int64_t q = op->scale.factor.den * (int64_t) next->scale.factor.den;
709 if (FFABS(p) <= INT_MAX && FFABS(q) <= INT_MAX) {
710 av_reduce(&op->scale.factor.num, &op->scale.factor.den, p, q, INT_MAX);
711 ff_sws_op_list_remove_at(ops, n + 1, 1);
712 goto retry;
713 }
714 }
715
716 /* Scaling by exact power of two */
717
4/4
✓ Branch 0 taken 15230 times.
✓ Branch 1 taken 68521 times.
✓ Branch 2 taken 978 times.
✓ Branch 3 taken 14252 times.
83751 if (factor2 && ff_sws_pixel_type_is_int(op->type)) {
718
1/2
✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
978 op->op = factor2 > 0 ? SWS_OP_LSHIFT : SWS_OP_RSHIFT;
719 978 op->shift.amount = FFABS(factor2);
720 978 goto retry;
721 }
722 82773 break;
723 }
724
725 case SWS_OP_FILTER_H:
726 case SWS_OP_FILTER_V:
727 /* Merge with prior simple planar read */
728 if (prev->op == SWS_OP_READ && !prev->rw.filter &&
729 !prev->rw.packed && !prev->rw.frac) {
730 prev->rw.filter = op->op;
731 prev->rw.kernel = av_refstruct_ref(op->filter.kernel);
732 ff_sws_op_list_remove_at(ops, n, 1);
733 goto retry;
734 }
735 break;
736 }
737 }
738
739 /* Push clears to the back to void any unused components */
740
2/2
✓ Branch 0 taken 735733 times.
✓ Branch 1 taken 70469 times.
806202 for (int n = 0; n < ops->num_ops - 1; n++) {
741 735733 SwsOp *op = &ops->ops[n];
742 735733 SwsOp *next = &ops->ops[n + 1];
743
744
2/2
✓ Branch 0 taken 51904 times.
✓ Branch 1 taken 683829 times.
735733 switch (op->op) {
745 51904 case SWS_OP_CLEAR:
746
2/2
✓ Branch 1 taken 27350 times.
✓ Branch 2 taken 24554 times.
51904 if (op_commute_clear(op, next)) {
747 27350 FFSWAP(SwsOp, *op, *next);
748 27350 goto retry;
749 }
750 24554 break;
751 }
752 }
753
754 /* Apply any remaining preferential re-ordering optimizations; do these
755 * last because they are more likely to block other optimizations if done
756 * too aggressively */
757
2/2
✓ Branch 0 taken 403964 times.
✓ Branch 1 taken 31704 times.
435668 for (int n = 0; n < ops->num_ops - 1; n++) {
758 403964 SwsOp *op = &ops->ops[n];
759 403964 SwsOp *next = &ops->ops[n + 1];
760
761
3/3
✓ Branch 0 taken 60367 times.
✓ Branch 1 taken 24204 times.
✓ Branch 2 taken 319393 times.
403964 switch (op->op) {
762 60367 case SWS_OP_SWIZZLE: {
763 /* Try to push swizzles towards the output */
764
2/2
✓ Branch 1 taken 36941 times.
✓ Branch 2 taken 23426 times.
60367 if (op_commute_swizzle(op, next)) {
765 36941 FFSWAP(SwsOp, *op, *next);
766 36941 goto retry;
767 }
768 23426 break;
769 }
770
771 24204 case SWS_OP_SCALE:
772 /* Scaling by integer before conversion to int */
773
4/4
✓ Branch 0 taken 6362 times.
✓ Branch 1 taken 17842 times.
✓ Branch 2 taken 1824 times.
✓ Branch 3 taken 4538 times.
24204 if (op->scale.factor.den == 1 && next->op == SWS_OP_CONVERT &&
774
1/2
✓ Branch 0 taken 1824 times.
✗ Branch 1 not taken.
1824 ff_sws_pixel_type_is_int(next->convert.to))
775 {
776 1824 op->type = next->convert.to;
777 1824 FFSWAP(SwsOp, *op, *next);
778 1824 goto retry;
779 }
780 22380 break;
781 }
782 }
783
784 31704 return 0;
785 }
786
787 20440 int ff_sws_solve_shuffle(const SwsOpList *const ops, uint8_t shuffle[],
788 int size, uint8_t clear_val,
789 int *read_bytes, int *write_bytes)
790 {
791
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20440 times.
20440 if (!ops->num_ops)
792 return AVERROR(EINVAL);
793
794 20440 const SwsOp *read = ff_sws_op_list_input(ops);
795
5/6
✓ Branch 0 taken 20440 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20188 times.
✓ Branch 3 taken 252 times.
✓ Branch 4 taken 17500 times.
✓ Branch 5 taken 2688 times.
20440 if (!read || read->rw.frac || read->rw.filter ||
796
4/4
✓ Branch 0 taken 11228 times.
✓ Branch 1 taken 6272 times.
✓ Branch 2 taken 9162 times.
✓ Branch 3 taken 2066 times.
17500 (!read->rw.packed && read->rw.elems > 1))
797 12102 return AVERROR(ENOTSUP);
798
799 8338 const int read_size = ff_sws_pixel_type_size(read->type);
800 8338 uint32_t mask[4] = {0};
801
2/2
✓ Branch 0 taken 18383 times.
✓ Branch 1 taken 8338 times.
26721 for (int i = 0; i < read->rw.elems; i++)
802 18383 mask[i] = 0x01010101 * i * read_size + 0x03020100;
803
804
1/2
✓ Branch 0 taken 11590 times.
✗ Branch 1 not taken.
11590 for (int opidx = 1; opidx < ops->num_ops; opidx++) {
805 11590 const SwsOp *op = &ops->ops[opidx];
806
6/6
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 2663 times.
✓ Branch 2 taken 210 times.
✓ Branch 3 taken 4840 times.
✓ Branch 4 taken 528 times.
✓ Branch 5 taken 2970 times.
11590 switch (op->op) {
807 379 case SWS_OP_SWIZZLE: {
808 379 uint32_t orig[4] = { mask[0], mask[1], mask[2], mask[3] };
809
2/2
✓ Branch 0 taken 1516 times.
✓ Branch 1 taken 379 times.
1895 for (int i = 0; i < 4; i++)
810 1516 mask[i] = orig[op->swizzle.in[i]];
811 379 break;
812 }
813
814 2663 case SWS_OP_SWAP_BYTES:
815
2/2
✓ Branch 0 taken 10652 times.
✓ Branch 1 taken 2663 times.
13315 for (int i = 0; i < 4; i++) {
816
2/3
✓ Branch 0 taken 10172 times.
✓ Branch 1 taken 480 times.
✗ Branch 2 not taken.
10652 switch (ff_sws_pixel_type_size(op->type)) {
817 10172 case 2: mask[i] = av_bswap16(mask[i]); break;
818 480 case 4: mask[i] = av_bswap32(mask[i]); break;
819 }
820 }
821 2663 break;
822
823 210 case SWS_OP_CLEAR:
824
2/2
✓ Branch 0 taken 758 times.
✓ Branch 1 taken 54 times.
812 for (int i = 0; i < 4; i++) {
825
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 210 times.
758 if (!SWS_COMP_TEST(op->clear.mask, i))
826 548 continue;
827
3/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
210 if (op->clear.value[i].num != 0 || !clear_val)
828 156 return AVERROR(ENOTSUP);
829 54 mask[i] = 0x1010101ul * clear_val;
830 }
831 54 break;
832
833 4840 case SWS_OP_CONVERT: {
834
2/2
✓ Branch 0 taken 4684 times.
✓ Branch 1 taken 156 times.
4840 if (!op->convert.expand)
835 4684 return AVERROR(ENOTSUP);
836
2/2
✓ Branch 0 taken 624 times.
✓ Branch 1 taken 156 times.
780 for (int i = 0; i < 4; i++) {
837
1/3
✓ Branch 0 taken 624 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
624 switch (ff_sws_pixel_type_size(op->type)) {
838 624 case 1: mask[i] = 0x01010101 * (mask[i] & 0xFF); break;
839 case 2: mask[i] = 0x00010001 * (mask[i] & 0xFFFF); break;
840 }
841 }
842 156 break;
843 }
844
845 528 case SWS_OP_WRITE: {
846
3/4
✓ Branch 0 taken 514 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 514 times.
✗ Branch 3 not taken.
528 if (op->rw.frac || op->rw.filter ||
847
4/4
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 252 times.
✓ Branch 2 taken 211 times.
✓ Branch 3 taken 51 times.
514 (!op->rw.packed && op->rw.elems > 1))
848 225 return AVERROR(ENOTSUP);
849
850 /* Initialize to no-op */
851 303 memset(shuffle, clear_val, size);
852
853 303 const int write_size = ff_sws_pixel_type_size(op->type);
854 303 const int read_chunk = read->rw.elems * read_size;
855 303 const int write_chunk = op->rw.elems * write_size;
856 303 const int num_groups = size / FFMAX(read_chunk, write_chunk);
857
2/2
✓ Branch 0 taken 1166 times.
✓ Branch 1 taken 303 times.
1469 for (int n = 0; n < num_groups; n++) {
858 1166 const int base_in = n * read_chunk;
859 1166 const int base_out = n * write_chunk;
860
2/2
✓ Branch 0 taken 2898 times.
✓ Branch 1 taken 1166 times.
4064 for (int i = 0; i < op->rw.elems; i++) {
861 2898 const int offset = base_out + i * write_size;
862
2/2
✓ Branch 0 taken 4354 times.
✓ Branch 1 taken 2898 times.
7252 for (int b = 0; b < write_size; b++) {
863 4354 const uint8_t idx = mask[i] >> (b * 8);
864
2/2
✓ Branch 0 taken 4138 times.
✓ Branch 1 taken 216 times.
4354 if (idx != clear_val)
865 4138 shuffle[offset + b] = base_in + idx;
866 }
867 }
868 }
869
870 303 *read_bytes = num_groups * read_chunk;
871 303 *write_bytes = num_groups * write_chunk;
872 303 return num_groups;
873 }
874
875 2970 default:
876 2970 return AVERROR(ENOTSUP);
877 }
878 }
879
880 return AVERROR(EINVAL);
881 }
882
883 /**
884 * Determine a suitable intermediate buffer format for a given combination
885 * of pixel types and number of planes. The exact interpretation of these
886 * formats does not matter at all; since they will only ever be used as
887 * temporary intermediate buffers. We still need to pick *some* format as
888 * a consequence of ff_sws_graph_add_pass() taking an AVPixelFormat for the
889 * output buffer.
890 */
891 static enum AVPixelFormat get_planar_fmt(SwsPixelType type, int nb_planes)
892 {
893 switch (ff_sws_pixel_type_size(type)) {
894 case 1:
895 switch (nb_planes) {
896 case 1: return AV_PIX_FMT_GRAY8;
897 case 2: return AV_PIX_FMT_YUV444P; // FIXME: no 2-plane planar fmt
898 case 3: return AV_PIX_FMT_YUV444P;
899 case 4: return AV_PIX_FMT_YUVA444P;
900 }
901 break;
902 case 2:
903 switch (nb_planes) {
904 case 1: return AV_PIX_FMT_GRAY16;
905 case 2: return AV_PIX_FMT_YUV444P16; // FIXME: no 2-plane planar fmt
906 case 3: return AV_PIX_FMT_YUV444P16;
907 case 4: return AV_PIX_FMT_YUVA444P16;
908 }
909 break;
910 case 4:
911 switch (nb_planes) {
912 case 1: return AV_PIX_FMT_GRAYF32;
913 case 2: return AV_PIX_FMT_GBRPF32; // FIXME: no 2-plane planar fmt
914 case 3: return AV_PIX_FMT_GBRPF32;
915 case 4: return AV_PIX_FMT_GBRAPF32;
916 }
917 break;
918 }
919
920 av_unreachable("Invalid pixel type or number of planes?");
921 return AV_PIX_FMT_NONE;
922 }
923
924 static void get_input_size(const SwsOpList *ops, SwsFormat *fmt)
925 {
926 fmt->width = ops->src.width;
927 fmt->height = ops->src.height;
928
929 const SwsOp *read = ff_sws_op_list_input(ops);
930 if (read && read->rw.filter == SWS_OP_FILTER_V) {
931 fmt->height = read->rw.kernel->dst_size;
932 } else if (read && read->rw.filter == SWS_OP_FILTER_H) {
933 fmt->width = read->rw.kernel->dst_size;
934 }
935 }
936
937 int ff_sws_op_list_subpass(SwsOpList *ops1, SwsOpList **out_rest)
938 {
939 const SwsOp *op;
940 int ret, idx;
941
942 for (idx = 0; idx < ops1->num_ops; idx++) {
943 op = &ops1->ops[idx];
944 if (op->op == SWS_OP_FILTER_H || op->op == SWS_OP_FILTER_V)
945 break;
946 }
947
948 if (idx == ops1->num_ops) {
949 *out_rest = NULL;
950 return 0;
951 }
952
953 av_assert0(idx > 0);
954 const SwsOp *prev = &ops1->ops[idx - 1];
955
956 SwsOpList *ops2 = ff_sws_op_list_duplicate(ops1);
957 if (!ops2)
958 return AVERROR(ENOMEM);
959
960 /**
961 * Not all components may be needed; but we need the ones that *are*
962 * used to be contiguous for the write/read operations. So, first
963 * compress them into a linearly ascending list of components
964 */
965 int nb_planes = 0;
966 SwsSwizzleOp swiz_wr = SWS_SWIZZLE(0, 1, 2, 3);
967 SwsSwizzleOp swiz_rd = SWS_SWIZZLE(0, 1, 2, 3);
968 for (int i = 0; i < 4; i++) {
969 if (SWS_OP_NEEDED(prev, i)) {
970 const int o = nb_planes++;
971 swiz_wr.in[o] = i;
972 swiz_rd.in[i] = o;
973 }
974 }
975
976 /* Determine metadata for the intermediate format */
977 const SwsPixelType type = op->type;
978 ops2->src.format = get_planar_fmt(type, nb_planes);
979 ops2->src.desc = av_pix_fmt_desc_get(ops2->src.format);
980 get_input_size(ops1, &ops2->src);
981 ops1->dst = ops2->src;
982
983 for (int i = 0; i < nb_planes; i++) {
984 ops1->plane_dst[i] = ops2->plane_src[i] = i;
985 ops2->comps_src.flags[i] = prev->comps.flags[swiz_wr.in[i]];
986 }
987
988 ff_sws_op_list_remove_at(ops1, idx, ops1->num_ops - idx);
989 ff_sws_op_list_remove_at(ops2, 0, idx);
990 op = NULL; /* the above command may invalidate op */
991
992 if (swiz_wr.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
993 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
994 .op = SWS_OP_SWIZZLE,
995 .type = type,
996 .swizzle = swiz_wr,
997 });
998 if (ret < 0)
999 goto fail;
1000 }
1001
1002 ret = ff_sws_op_list_append(ops1, &(SwsOp) {
1003 .op = SWS_OP_WRITE,
1004 .type = type,
1005 .rw.elems = nb_planes,
1006 });
1007 if (ret < 0)
1008 goto fail;
1009
1010 ret = ff_sws_op_list_insert_at(ops2, 0, &(SwsOp) {
1011 .op = SWS_OP_READ,
1012 .type = type,
1013 .rw.elems = nb_planes,
1014 });
1015 if (ret < 0)
1016 goto fail;
1017
1018 if (swiz_rd.mask != SWS_SWIZZLE(0, 1, 2, 3).mask) {
1019 ret = ff_sws_op_list_insert_at(ops2, 1, &(SwsOp) {
1020 .op = SWS_OP_SWIZZLE,
1021 .type = type,
1022 .swizzle = swiz_rd,
1023 });
1024 if (ret < 0)
1025 goto fail;
1026 }
1027
1028 ret = ff_sws_op_list_optimize(ops1);
1029 if (ret < 0)
1030 goto fail;
1031
1032 ret = ff_sws_op_list_optimize(ops2);
1033 if (ret < 0)
1034 goto fail;
1035
1036 *out_rest = ops2;
1037 return 0;
1038
1039 fail:
1040 ff_sws_op_list_free(&ops2);
1041 return ret;
1042 }
1043