FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops_memcpy.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 66 67 98.5%
Functions: 2 2 100.0%
Branches: 55 60 91.7%

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/avassert.h"
22
23 #include "ops_backend.h"
24
25 typedef struct MemcpyPriv {
26 int num_planes;
27 int index[4]; /* or -1 to clear plane */
28 uint8_t clear_value[4];
29 } MemcpyPriv;
30
31 /**
32 * Switch to loop if total padding exceeds this number of bytes. Chosen to
33 * align with the typical L1 cache size of modern CPUs, as this avoids the
34 * risk of the implementation loading one extra unnecessary cache line.
35 */
36 #define SWS_MAX_PADDING 64
37
38 /* Memcpy backend for trivial cases */
39
40 159 static void process(const SwsOpExec *exec, const void *priv,
41 int x_start, int y_start, int x_end, int y_end)
42 {
43 159 const MemcpyPriv *p = priv;
44 159 const int lines = y_end - y_start;
45 159 const int bytes = x_end * exec->block_size_out;
46 av_assert1(x_start == 0 && x_end == exec->width);
47
48
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 159 times.
691 for (int i = 0; i < p->num_planes; i++) {
49 532 uint8_t *out = exec->out[i];
50 532 const int idx = p->index[i];
51 532 const int use_loop = exec->out_stride[i] > bytes + SWS_MAX_PADDING;
52
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 34 times.
532 if (idx < 0 && !use_loop) {
53 8 memset(out, p->clear_value[i], exec->out_stride[i] * lines);
54
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 490 times.
524 } else if (idx < 0) {
55
2/2
✓ Branch 0 taken 544 times.
✓ Branch 1 taken 34 times.
578 for (int y = y_start; y < y_end; y++) {
56 544 memset(out, p->clear_value[i], bytes);
57 544 out += exec->out_stride[i];
58 }
59
3/4
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 410 times.
490 } else if (exec->out_stride[i] == exec->in_stride[idx] && !use_loop) {
60 80 memcpy(out, exec->in[idx], exec->out_stride[i] * lines);
61 } else {
62 410 const uint8_t *in = exec->in[idx];
63
2/2
✓ Branch 0 taken 6560 times.
✓ Branch 1 taken 410 times.
6970 for (int y = y_start; y < y_end; y++) {
64 6560 memcpy(out, in, bytes);
65 6560 out += exec->out_stride[i];
66 6560 in += exec->in_stride[idx];
67 }
68 }
69 }
70 159 }
71
72 26656 static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
73 {
74 26656 MemcpyPriv p = {0};
75
76
2/2
✓ Branch 0 taken 45015 times.
✓ Branch 1 taken 1862 times.
46877 for (int n = 0; n < ops->num_ops; n++) {
77 45015 const SwsOp *op = &ops->ops[n];
78
5/5
✓ Branch 0 taken 26656 times.
✓ Branch 1 taken 1291 times.
✓ Branch 2 taken 458 times.
✓ Branch 3 taken 2116 times.
✓ Branch 4 taken 14494 times.
45015 switch (op->op) {
79 26656 case SWS_OP_READ:
80
8/8
✓ Branch 0 taken 6356 times.
✓ Branch 1 taken 20300 times.
✓ Branch 2 taken 2380 times.
✓ Branch 3 taken 3976 times.
✓ Branch 4 taken 22414 times.
✓ Branch 5 taken 266 times.
✓ Branch 6 taken 5376 times.
✓ Branch 7 taken 17038 times.
26656 if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac || op->rw.filter)
81 9618 return AVERROR(ENOTSUP);
82
2/2
✓ Branch 0 taken 48712 times.
✓ Branch 1 taken 17038 times.
65750 for (int i = 0; i < op->rw.elems; i++)
83 48712 p.index[i] = i;
84 17038 break;
85
86 1291 case SWS_OP_SWIZZLE: {
87 1291 const MemcpyPriv orig = p;
88
2/2
✓ Branch 0 taken 4732 times.
✓ Branch 1 taken 1017 times.
5749 for (int i = 0; i < 4; i++) {
89 /* Explicitly exclude swizzle masks that contain duplicates,
90 * because these are wasteful to implement as a memcpy */
91
2/2
✓ Branch 0 taken 6608 times.
✓ Branch 1 taken 4458 times.
11066 for (int j = 0; j < i; j++) {
92
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 6334 times.
6608 if (op->swizzle.in[i] == op->swizzle.in[j])
93 274 return AVERROR(ENOTSUP);
94 }
95 4458 p.index[i] = orig.index[op->swizzle.in[i]];
96 }
97 1017 break;
98 }
99
100 458 case SWS_OP_CLEAR:
101
2/2
✓ Branch 0 taken 1524 times.
✓ Branch 1 taken 304 times.
1828 for (int i = 0; i < 4; i++) {
102
2/2
✓ Branch 0 taken 827 times.
✓ Branch 1 taken 697 times.
1524 if (!SWS_COMP_TEST(op->clear.mask, i))
103 827 continue;
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 697 times.
697 if (op->clear.value[i].den != 1)
105 return AVERROR(ENOTSUP);
106
107 /* Ensure all bytes to be cleared are the same, because we
108 * can't memset on multi-byte sequences */
109 697 uint8_t val = op->clear.value[i].num & 0xFF;
110 697 uint32_t ref = val;
111
3/3
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 429 times.
697 switch (ff_sws_pixel_type_size(op->type)) {
112 252 case 2: ref *= 0x101; break;
113 16 case 4: ref *= 0x1010101; break;
114 }
115
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 543 times.
697 if (ref != op->clear.value[i].num)
116 154 return AVERROR(ENOTSUP);
117 543 p.clear_value[i] = val;
118 543 p.index[i] = -1;
119 }
120 304 break;
121
122 2116 case SWS_OP_WRITE:
123
6/8
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 1890 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 226 times.
✓ Branch 4 taken 1862 times.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1862 times.
2116 if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac || op->rw.filter)
124 254 return AVERROR(ENOTSUP);
125 1862 p.num_planes = op->rw.elems;
126 1862 break;
127
128 14494 default:
129 14494 return AVERROR(ENOTSUP);
130 }
131 }
132
133 1862 *out = (SwsCompiledOp) {
134 .slice_align = 1,
135 .block_size = 1,
136 .func = process,
137 1862 .priv = av_memdup(&p, sizeof(p)),
138 .free = av_free,
139 };
140
1/2
✓ Branch 0 taken 1862 times.
✗ Branch 1 not taken.
1862 return out->priv ? 0 : AVERROR(ENOMEM);
141 }
142
143 const SwsOpBackend backend_murder = {
144 .name = "memcpy",
145 .compile = compile,
146 .hw_format = AV_PIX_FMT_NONE,
147 };
148