FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libswscale/ops_memcpy.c
Date: 2025-09-09 00:08:58
Exec Total Coverage
Lines: 55 62 88.7%
Functions: 2 2 100.0%
Branches: 41 48 85.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 "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 /* Memcpy backend for trivial cases */
32
33 135 static void process(const SwsOpExec *exec, const void *priv,
34 int x_start, int y_start, int x_end, int y_end)
35 {
36 135 const MemcpyPriv *p = priv;
37 135 const int lines = y_end - y_start;
38 av_assert1(x_start == 0 && x_end == exec->width);
39
40
2/2
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 135 times.
595 for (int i = 0; i < p->num_planes; i++) {
41 460 uint8_t *out = exec->out[i];
42 460 const int idx = p->index[i];
43
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 414 times.
460 if (idx < 0) {
44 46 memset(out, p->clear_value[i], exec->out_stride[i] * lines);
45
1/2
✓ Branch 0 taken 414 times.
✗ Branch 1 not taken.
414 } else if (exec->out_stride[i] == exec->in_stride[idx]) {
46 414 memcpy(out, exec->in[idx], exec->out_stride[i] * lines);
47 } else {
48 const int bytes = x_end * exec->block_size_out;
49 const uint8_t *in = exec->in[idx];
50 for (int y = y_start; y < y_end; y++) {
51 memcpy(out, in, bytes);
52 out += exec->out_stride[i];
53 in += exec->in_stride[idx];
54 }
55 }
56 }
57 135 }
58
59 6422 static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
60 {
61 6422 MemcpyPriv p = {0};
62
63
2/2
✓ Branch 0 taken 13897 times.
✓ Branch 1 taken 1755 times.
15652 for (int n = 0; n < ops->num_ops; n++) {
64 13897 const SwsOp *op = &ops->ops[n];
65
5/5
✓ Branch 0 taken 6422 times.
✓ Branch 1 taken 1144 times.
✓ Branch 2 taken 481 times.
✓ Branch 3 taken 1937 times.
✓ Branch 4 taken 3913 times.
13897 switch (op->op) {
66 6422 case SWS_OP_READ:
67
5/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 6266 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 6240 times.
6422 if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac)
68 182 return AVERROR(ENOTSUP);
69
2/2
✓ Branch 0 taken 20384 times.
✓ Branch 1 taken 6240 times.
26624 for (int i = 0; i < op->rw.elems; i++)
70 20384 p.index[i] = i;
71 6240 break;
72
73 1144 case SWS_OP_SWIZZLE: {
74 1144 const MemcpyPriv orig = p;
75
2/2
✓ Branch 0 taken 4264 times.
✓ Branch 1 taken 936 times.
5200 for (int i = 0; i < 4; i++) {
76 /* Explicitly exclude swizzle masks that contain duplicates,
77 * because these are wasteful to implement as a memcpy */
78
2/2
✓ Branch 0 taken 6032 times.
✓ Branch 1 taken 4056 times.
10088 for (int j = 0; j < i; j++) {
79
2/2
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 5824 times.
6032 if (op->swizzle.in[i] == op->swizzle.in[j])
80 208 return AVERROR(ENOTSUP);
81 }
82 4056 p.index[i] = orig.index[op->swizzle.in[i]];
83 }
84 936 break;
85 }
86
87 481 case SWS_OP_CLEAR:
88
2/2
✓ Branch 0 taken 1534 times.
✓ Branch 1 taken 299 times.
1833 for (int i = 0; i < 4; i++) {
89
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 806 times.
1534 if (!op->c.q4[i].den)
90 728 continue;
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 806 times.
806 if (op->c.q4[i].den != 1)
92 return AVERROR(ENOTSUP);
93
94 /* Ensure all bytes to be cleared are the same, because we
95 * can't memset on multi-byte sequences */
96 806 uint8_t val = op->c.q4[i].num & 0xFF;
97 806 uint32_t ref = val;
98
3/3
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 533 times.
806 switch (ff_sws_pixel_type_size(op->type)) {
99 260 case 2: ref *= 0x101; break;
100 13 case 4: ref *= 0x1010101; break;
101 }
102
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 624 times.
806 if (ref != op->c.q4[i].num)
103 182 return AVERROR(ENOTSUP);
104 624 p.clear_value[i] = val;
105 624 p.index[i] = -1;
106 }
107 299 break;
108
109 1937 case SWS_OP_WRITE:
110
5/6
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 1781 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 1755 times.
1937 if ((op->rw.packed && op->rw.elems != 1) || op->rw.frac)
111 182 return AVERROR(ENOTSUP);
112 1755 p.num_planes = op->rw.elems;
113 1755 break;
114
115 3913 default:
116 3913 return AVERROR(ENOTSUP);
117 }
118 }
119
120 1755 *out = (SwsCompiledOp) {
121 .block_size = 1,
122 .func = process,
123 1755 .priv = av_memdup(&p, sizeof(p)),
124 .free = av_free,
125 };
126
1/2
✓ Branch 0 taken 1755 times.
✗ Branch 1 not taken.
1755 return out->priv ? 0 : AVERROR(ENOMEM);
127 }
128
129 const SwsOpBackend backend_murder = {
130 .name = "memcpy",
131 .compile = compile,
132 };
133