FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops_tmpl_common.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 173 174 99.4%
Functions: 150 210 71.4%
Branches: 117 124 94.4%

Line Branch Exec Source
1 /**
2 * Copyright (C) 2025 Niklas Haas
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "ops_backend.h"
22
23 #ifndef BIT_DEPTH
24 # error Should only be included from ops_tmpl_*.c!
25 #endif
26
27 #define WRAP_CONVERT_UINT(N) \
28 DECL_PATTERN(convert_uint##N) \
29 { \
30 u##N##block_t xu, yu, zu, wu; \
31 \
32 SWS_LOOP \
33 for (int i = 0; i < SWS_BLOCK_SIZE; i++) { \
34 if (X) \
35 xu[i] = x[i]; \
36 if (Y) \
37 yu[i] = y[i]; \
38 if (Z) \
39 zu[i] = z[i]; \
40 if (W) \
41 wu[i] = w[i]; \
42 } \
43 \
44 CONTINUE(xu, yu, zu, wu); \
45 } \
46 \
47 WRAP_COMMON_PATTERNS(convert_uint##N, \
48 .op = SWS_OP_CONVERT, \
49 .convert.to = SWS_PIXEL_U##N, \
50 );
51
52 #if BIT_DEPTH != 8
53
9/10
✓ Branch 0 taken 1536000 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1388544 times.
✓ Branch 3 taken 147456 times.
✓ Branch 4 taken 1388544 times.
✓ Branch 5 taken 147456 times.
✓ Branch 6 taken 347136 times.
✓ Branch 7 taken 1188864 times.
✓ Branch 8 taken 1536000 times.
✓ Branch 9 taken 48000 times.
3264000 WRAP_CONVERT_UINT(8)
54 #endif
55
56 #if BIT_DEPTH != 16
57
9/10
✓ Branch 0 taken 2844672 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2088960 times.
✓ Branch 3 taken 755712 times.
✓ Branch 4 taken 2088960 times.
✓ Branch 5 taken 755712 times.
✓ Branch 6 taken 688128 times.
✓ Branch 7 taken 2156544 times.
✓ Branch 8 taken 2844672 times.
✓ Branch 9 taken 88896 times.
6044928 WRAP_CONVERT_UINT(16)
58 #endif
59
60 #if BIT_DEPTH != 32 || defined(IS_FLOAT)
61
9/10
✓ Branch 0 taken 4140032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3587072 times.
✓ Branch 3 taken 552960 times.
✓ Branch 4 taken 3587072 times.
✓ Branch 5 taken 552960 times.
✓ Branch 6 taken 1421312 times.
✓ Branch 7 taken 2718720 times.
✓ Branch 8 taken 4140032 times.
✓ Branch 9 taken 129376 times.
8797568 WRAP_CONVERT_UINT(32)
62 #endif
63
64 322816 DECL_PATTERN(clear)
65 {
66 SWS_LOOP
67
2/2
✓ Branch 0 taken 5165056 times.
✓ Branch 1 taken 161408 times.
10652928 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
68
2/2
✓ Branch 0 taken 2716672 times.
✓ Branch 1 taken 2448384 times.
10330112 if (X)
69 5433344 x[i] = impl->priv.px[0];
70
2/2
✓ Branch 0 taken 356352 times.
✓ Branch 1 taken 4808704 times.
10330112 if (Y)
71 712704 y[i] = impl->priv.px[1];
72
2/2
✓ Branch 0 taken 245760 times.
✓ Branch 1 taken 4919296 times.
10330112 if (Z)
73 491520 z[i] = impl->priv.px[2];
74
2/2
✓ Branch 0 taken 2654208 times.
✓ Branch 1 taken 2510848 times.
10330112 if (W)
75 5308416 w[i] = impl->priv.px[3];
76 }
77
78 322816 CONTINUE(x, y, z, w);
79 322816 }
80
81 #define WRAP_CLEAR(X, Y, Z, W) \
82 DECL_IMPL(clear, clear##_##X##Y##Z##W, X, Y, Z, W) \
83 \
84 DECL_ENTRY(clear##_##X##Y##Z##W, SWS_COMP_ALL, \
85 .setup = ff_sws_setup_clear, \
86 .op = SWS_OP_CLEAR, \
87 .clear.mask = SWS_COMP_MASK(X, Y, Z, W), \
88 );
89
90 141056 WRAP_CLEAR(0, 0, 0, 1) /* rgba alpha */
91 145792 WRAP_CLEAR(1, 0, 0, 0) /* argb alpha */
92 6912 WRAP_CLEAR(0, 1, 0, 0) /* ya alpha */
93
94 832 WRAP_CLEAR(1, 1, 0, 0) /* vuya chroma */
95 832 WRAP_CLEAR(0, 1, 1, 0) /* yuva chroma */
96 832 WRAP_CLEAR(0, 0, 1, 1) /* ayuv chroma */
97 2560 WRAP_CLEAR(1, 0, 1, 0) /* uyva chroma */
98 2560 WRAP_CLEAR(0, 1, 0, 1) /* xvyu chroma */
99
100 832 WRAP_CLEAR(0, 1, 1, 1) /* gray -> yuva */
101 10304 WRAP_CLEAR(1, 0, 1, 1) /* gray -> ayuv */
102 10304 WRAP_CLEAR(1, 1, 0, 1) /* gray -> vuya */
103
104 293504 DECL_PATTERN(min)
105 {
106 SWS_LOOP
107
2/2
✓ Branch 0 taken 4696064 times.
✓ Branch 1 taken 146752 times.
9685632 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
108
1/2
✓ Branch 0 taken 4696064 times.
✗ Branch 1 not taken.
9392128 if (X)
109 9392128 x[i] = FFMIN(x[i], impl->priv.px[0]);
110
2/2
✓ Branch 0 taken 4014080 times.
✓ Branch 1 taken 681984 times.
9392128 if (Y)
111 8028160 y[i] = FFMIN(y[i], impl->priv.px[1]);
112
2/2
✓ Branch 0 taken 4014080 times.
✓ Branch 1 taken 681984 times.
9392128 if (Z)
113 8028160 z[i] = FFMIN(z[i], impl->priv.px[2]);
114
2/2
✓ Branch 0 taken 1387520 times.
✓ Branch 1 taken 3308544 times.
9392128 if (W)
115 2775040 w[i] = FFMIN(w[i], impl->priv.px[3]);
116 }
117
118 293504 CONTINUE(x, y, z, w);
119 293504 }
120
121 148352 DECL_PATTERN(max)
122 {
123 SWS_LOOP
124
2/2
✓ Branch 0 taken 2373632 times.
✓ Branch 1 taken 74176 times.
4895616 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
125
1/2
✓ Branch 0 taken 2373632 times.
✗ Branch 1 not taken.
4747264 if (X)
126 4747264 x[i] = FFMAX(x[i], impl->priv.px[0]);
127
2/2
✓ Branch 0 taken 2004992 times.
✓ Branch 1 taken 368640 times.
4747264 if (Y)
128 4009984 y[i] = FFMAX(y[i], impl->priv.px[1]);
129
2/2
✓ Branch 0 taken 2004992 times.
✓ Branch 1 taken 368640 times.
4747264 if (Z)
130 4009984 z[i] = FFMAX(z[i], impl->priv.px[2]);
131
2/2
✓ Branch 0 taken 401408 times.
✓ Branch 1 taken 1972224 times.
4747264 if (W)
132 802816 w[i] = FFMAX(w[i], impl->priv.px[3]);
133 }
134
135 148352 CONTINUE(x, y, z, w);
136 148352 }
137
138 293504 WRAP_COMMON_PATTERNS(min,
139 .op = SWS_OP_MIN,
140 .setup = ff_sws_setup_clamp,
141 .flexible = true,
142 );
143
144 148352 WRAP_COMMON_PATTERNS(max,
145 .op = SWS_OP_MAX,
146 .setup = ff_sws_setup_clamp,
147 .flexible = true,
148 );
149
150 241280 DECL_PATTERN(scale)
151 {
152 241280 const pixel_t scale = impl->priv.px[0];
153
154 SWS_LOOP
155
2/2
✓ Branch 0 taken 3860480 times.
✓ Branch 1 taken 120640 times.
7962240 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
156
1/2
✓ Branch 0 taken 3860480 times.
✗ Branch 1 not taken.
7720960 if (X)
157 7720960 x[i] *= scale;
158
2/2
✓ Branch 0 taken 3325952 times.
✓ Branch 1 taken 534528 times.
7720960 if (Y)
159 6651904 y[i] *= scale;
160
2/2
✓ Branch 0 taken 3325952 times.
✓ Branch 1 taken 534528 times.
7720960 if (Z)
161 6651904 z[i] *= scale;
162
2/2
✓ Branch 0 taken 1141760 times.
✓ Branch 1 taken 2718720 times.
7720960 if (W)
163 2283520 w[i] *= scale;
164 }
165
166 241280 CONTINUE(x, y, z, w);
167 241280 }
168
169 241280 WRAP_COMMON_PATTERNS(scale,
170 .op = SWS_OP_SCALE,
171 .setup = ff_sws_setup_scale,
172 .flexible = true,
173 );
174
175 4480 DECL_SETUP(setup_filter_v, params, out)
176 {
177 4480 const SwsFilterWeights *filter = params->op->rw.kernel;
178 static_assert(sizeof(out->priv.ptr) <= sizeof(int32_t[2]),
179 ">8 byte pointers not supported");
180
181 /* Pre-convert weights to float */
182 4480 float *weights = av_calloc(filter->num_weights, sizeof(float));
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2240 times.
4480 if (!weights)
184 return AVERROR(ENOMEM);
185
186
2/2
✓ Branch 0 taken 129024 times.
✓ Branch 1 taken 2240 times.
262528 for (int i = 0; i < filter->num_weights; i++)
187 258048 weights[i] = (float) filter->weights[i] / SWS_FILTER_SCALE;
188
189 4480 out->priv.ptr = weights;
190 4480 out->priv.i32[2] = filter->filter_size;
191 4480 out->free = ff_op_priv_free;
192 4480 return 0;
193 }
194
195 /* Fully general vertical planar filter case */
196 48640 DECL_READ(filter_v, const int elems)
197 {
198 48640 const SwsOpExec *exec = iter->exec;
199 48640 const float *restrict weights = impl->priv.ptr;
200 48640 const int filter_size = impl->priv.i32[2];
201 48640 weights += filter_size * iter->y;
202
203 f32block_t xs, ys, zs, ws;
204 48640 memset(xs, 0, sizeof(xs));
205
2/2
✓ Branch 0 taken 18240 times.
✓ Branch 1 taken 6080 times.
48640 if (elems > 1)
206 36480 memset(ys, 0, sizeof(ys));
207
2/2
✓ Branch 0 taken 12160 times.
✓ Branch 1 taken 12160 times.
48640 if (elems > 2)
208 24320 memset(zs, 0, sizeof(zs));
209
2/2
✓ Branch 0 taken 6080 times.
✓ Branch 1 taken 18240 times.
48640 if (elems > 3)
210 12160 memset(ws, 0, sizeof(ws));
211
212
2/2
✓ Branch 0 taken 87552 times.
✓ Branch 1 taken 24320 times.
223744 for (int j = 0; j < filter_size; j++) {
213 175104 const float weight = weights[j];
214
215 SWS_LOOP
216
2/2
✓ Branch 0 taken 2801664 times.
✓ Branch 1 taken 87552 times.
5778432 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
217 5603328 xs[i] += weight * in0[i];
218
2/2
✓ Branch 0 taken 2101248 times.
✓ Branch 1 taken 700416 times.
5603328 if (elems > 1)
219 4202496 ys[i] += weight * in1[i];
220
2/2
✓ Branch 0 taken 1400832 times.
✓ Branch 1 taken 1400832 times.
5603328 if (elems > 2)
221 2801664 zs[i] += weight * in2[i];
222
2/2
✓ Branch 0 taken 700416 times.
✓ Branch 1 taken 2101248 times.
5603328 if (elems > 3)
223 1400832 ws[i] += weight * in3[i];
224 }
225
226 175104 in0 = bump_ptr(in0, exec->in_stride[0]);
227
2/2
✓ Branch 0 taken 65664 times.
✓ Branch 1 taken 21888 times.
175104 if (elems > 1)
228 131328 in1 = bump_ptr(in1, exec->in_stride[1]);
229
2/2
✓ Branch 0 taken 43776 times.
✓ Branch 1 taken 43776 times.
175104 if (elems > 2)
230 87552 in2 = bump_ptr(in2, exec->in_stride[2]);
231
2/2
✓ Branch 0 taken 21888 times.
✓ Branch 1 taken 65664 times.
175104 if (elems > 3)
232 43776 in3 = bump_ptr(in3, exec->in_stride[3]);
233 }
234
235
2/2
✓ Branch 0 taken 60800 times.
✓ Branch 1 taken 24320 times.
170240 for (int i = 0; i < elems; i++)
236 121600 iter->in[i] += sizeof(block_t);
237
238 48640 CONTINUE(xs, ys, zs, ws);
239 48640 }
240
241 6272 DECL_SETUP(setup_filter_h, params, out)
242 {
243 6272 SwsFilterWeights *filter = params->op->rw.kernel;
244 6272 out->priv.ptr = av_refstruct_ref(filter->weights);
245 6272 out->priv.i32[2] = filter->filter_size;
246 6272 out->free = ff_op_priv_unref;
247 6272 return 0;
248 }
249
250 /* Fully general horizontal planar filter case */
251 68096 DECL_READ(filter_h, const int elems)
252 {
253 68096 const SwsOpExec *exec = iter->exec;
254 68096 const int *restrict weights = impl->priv.ptr;
255 68096 const int filter_size = impl->priv.i32[2];
256 68096 const float scale = 1.0f / SWS_FILTER_SCALE;
257 68096 const int xpos = iter->x;
258 68096 weights += filter_size * iter->x;
259
260 f32block_t xs, ys, zs, ws;
261
2/2
✓ Branch 0 taken 1089536 times.
✓ Branch 1 taken 34048 times.
2247168 for (int i = 0; i < SWS_BLOCK_SIZE; i++) {
262 2179072 const int offset = exec->in_offset_x[xpos + i];
263 2179072 pixel_t *start0 = bump_ptr(in0, offset);
264 2179072 pixel_t *start1 = bump_ptr(in1, offset);
265 2179072 pixel_t *start2 = bump_ptr(in2, offset);
266 2179072 pixel_t *start3 = bump_ptr(in3, offset);
267
268 2179072 inter_t sx = 0, sy = 0, sz = 0, sw = 0;
269
2/2
✓ Branch 0 taken 6070272 times.
✓ Branch 1 taken 1089536 times.
14319616 for (int j = 0; j < filter_size; j++) {
270 12140544 const int weight = weights[j];
271 12140544 sx += weight * start0[j];
272
2/2
✓ Branch 0 taken 4552704 times.
✓ Branch 1 taken 1517568 times.
12140544 if (elems > 1)
273 9105408 sy += weight * start1[j];
274
2/2
✓ Branch 0 taken 3035136 times.
✓ Branch 1 taken 3035136 times.
12140544 if (elems > 2)
275 6070272 sz += weight * start2[j];
276
2/2
✓ Branch 0 taken 1517568 times.
✓ Branch 1 taken 4552704 times.
12140544 if (elems > 3)
277 3035136 sw += weight * start3[j];
278 }
279
280 2179072 xs[i] = (float) sx * scale;
281
2/2
✓ Branch 0 taken 817152 times.
✓ Branch 1 taken 272384 times.
2179072 if (elems > 1)
282 1634304 ys[i] = (float) sy * scale;
283
2/2
✓ Branch 0 taken 544768 times.
✓ Branch 1 taken 544768 times.
2179072 if (elems > 2)
284 1089536 zs[i] = (float) sz * scale;
285
2/2
✓ Branch 0 taken 272384 times.
✓ Branch 1 taken 817152 times.
2179072 if (elems > 3)
286 544768 ws[i] = (float) sw * scale;
287
288 2179072 weights += filter_size;
289 }
290
291 68096 CONTINUE(xs, ys, zs, ws);
292 68096 }
293
294 #define WRAP_FILTER(FUNC, DIR, ELEMS, SUFFIX) \
295 static av_flatten void fn(FUNC##ELEMS##SUFFIX)(SwsOpIter *restrict iter, \
296 const SwsOpImpl *restrict impl, \
297 void *restrict x, void *restrict y,\
298 void *restrict z, void *restrict w)\
299 { \
300 CALL_READ(FUNC##SUFFIX, ELEMS); \
301 } \
302 \
303 DECL_ENTRY(FUNC##ELEMS##SUFFIX, SWS_COMP_ELEMS(ELEMS), \
304 .op = SWS_OP_READ, \
305 .setup = fn(setup_filter##SUFFIX), \
306 .rw.elems = ELEMS, \
307 .rw.filter = SWS_OP_FILTER_##DIR, \
308 );
309
310 12160 WRAP_FILTER(filter, V, 1, _v)
311 12160 WRAP_FILTER(filter, V, 2, _v)
312 12160 WRAP_FILTER(filter, V, 3, _v)
313 12160 WRAP_FILTER(filter, V, 4, _v)
314
315 17024 WRAP_FILTER(filter, H, 1, _h)
316 17024 WRAP_FILTER(filter, H, 2, _h)
317 17024 WRAP_FILTER(filter, H, 3, _h)
318 17024 WRAP_FILTER(filter, H, 4, _h)
319
320 11062 static void fn(process)(const SwsOpExec *exec, const void *priv,
321 const int bx_start, const int y_start,
322 int bx_end, int y_end)
323 {
324 11062 const SwsOpChain *chain = priv;
325 11062 const SwsOpImpl *impl = chain->impl;
326 u32block_t x, y, z, w; /* allocate enough space for any intermediate */
327
328 SwsOpIter iterdata;
329 11062 SwsOpIter *iter = &iterdata; /* for CONTINUE() macro to work */
330 11062 iter->exec = exec;
331
2/2
✓ Branch 0 taken 22124 times.
✓ Branch 1 taken 5531 times.
55310 for (int i = 0; i < 4; i++) {
332 44248 iter->in[i] = (uintptr_t) exec->in[i];
333 44248 iter->out[i] = (uintptr_t) exec->out[i];
334 }
335
336
2/2
✓ Branch 0 taken 170496 times.
✓ Branch 1 taken 5531 times.
352054 for (iter->y = y_start; iter->y < y_end; iter->y++) {
337
2/2
✓ Branch 0 taken 439392 times.
✓ Branch 1 taken 170496 times.
1219776 for (int block = bx_start; block < bx_end; block++) {
338 878784 iter->x = block * SWS_BLOCK_SIZE;
339 878784 CONTINUE(x, y, z, w);
340 }
341
342
2/2
✓ Branch 0 taken 12160 times.
✓ Branch 1 taken 158336 times.
340992 const int y_bump = exec->in_bump_y ? exec->in_bump_y[iter->y] : 0;
343
2/2
✓ Branch 0 taken 681984 times.
✓ Branch 1 taken 170496 times.
1704960 for (int i = 0; i < 4; i++) {
344 1363968 iter->in[i] += exec->in_bump[i] + y_bump * exec->in_stride[i];
345 1363968 iter->out[i] += exec->out_bump[i];
346 }
347 }
348 11062 }
349