FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/tests/checkasm/sw_yuv2rgb.c
Date: 2026-09-27 22:20:00
Exec Total Coverage
Lines: 116 129 89.9%
Functions: 5 5 100.0%
Branches: 91 122 74.6%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <string.h>
20
21 #include "libavutil/common.h"
22 #include "libavutil/imgutils.h"
23 #include "libavutil/intreadwrite.h"
24 #include "libavutil/mem_internal.h"
25 #include "libavutil/pixdesc.h"
26
27 #include "libswscale/swscale.h"
28 #include "libswscale/swscale_internal.h"
29
30 #include "checkasm.h"
31
32 #define randomize_buffers(buf, size) \
33 do { \
34 for (int j = 0; j < size; j += 4) \
35 AV_WN32(buf + j, rnd()); \
36 } while (0)
37
38 static const int dst_fmts[] = {
39 // AV_PIX_FMT_BGR48BE,
40 // AV_PIX_FMT_BGR48LE,
41 // AV_PIX_FMT_RGB48BE,
42 // AV_PIX_FMT_RGB48LE,
43 AV_PIX_FMT_ARGB,
44 AV_PIX_FMT_ABGR,
45 AV_PIX_FMT_RGBA,
46 AV_PIX_FMT_BGRA,
47 AV_PIX_FMT_RGB24,
48 AV_PIX_FMT_BGR24,
49 AV_PIX_FMT_RGB565LE,
50 AV_PIX_FMT_BGR565LE,
51 AV_PIX_FMT_RGB555LE,
52 AV_PIX_FMT_BGR555LE,
53 AV_PIX_FMT_RGB565BE,
54 AV_PIX_FMT_BGR565BE,
55 AV_PIX_FMT_RGB555BE,
56 AV_PIX_FMT_BGR555BE,
57 // AV_PIX_FMT_RGB444,
58 // AV_PIX_FMT_BGR444,
59 // AV_PIX_FMT_RGB8,
60 // AV_PIX_FMT_BGR8,
61 // AV_PIX_FMT_RGB4,
62 // AV_PIX_FMT_BGR4,
63 // AV_PIX_FMT_RGB4_BYTE,
64 // AV_PIX_FMT_BGR4_BYTE,
65 // AV_PIX_FMT_MONOBLACK,
66 AV_PIX_FMT_GBRP,
67 };
68
69 768 static int cmp_off_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy)
70 {
71
2/2
✓ Branch 0 taken 1580544 times.
✓ Branch 1 taken 768 times.
1581312 for (size_t i = 0; i < n; i++) {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1580544 times.
1580544 if (abs(ref[i] - test[i]) > accuracy)
73 ✗ return 1;
74 }
75 768 return 0;
76 }
77
78 240 static int cmp_555_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy, int is_be)
79 {
80
2/2
✓ Branch 0 taken 188160 times.
✓ Branch 1 taken 240 times.
188400 for (size_t i = 0; i < n; i++) {
81
2/2
✓ Branch 0 taken 75264 times.
✓ Branch 1 taken 112896 times.
188160 uint16_t r = is_be ? AV_RB16(ref + i * 2) : AV_RL16(ref + i * 2);
82
2/2
✓ Branch 0 taken 75264 times.
✓ Branch 1 taken 112896 times.
188160 uint16_t t = is_be ? AV_RB16(test + i * 2) : AV_RL16(test + i * 2);
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(( r & 0x1f) - ( t & 0x1f)) > accuracy)
84 ✗ return 1;
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(((r >> 5) & 0x1f) - ((t >> 5) & 0x1f)) > accuracy)
86 ✗ return 1;
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(((r >> 10) & 0x1f) - ((t >> 10) & 0x1f)) > accuracy)
88 ✗ return 1;
89 }
90 240 return 0;
91 }
92
93 240 static int cmp_565_by_n(const uint8_t *ref, const uint8_t *test, size_t n, int accuracy, int is_be)
94 {
95
2/2
✓ Branch 0 taken 188160 times.
✓ Branch 1 taken 240 times.
188400 for (size_t i = 0; i < n; i++) {
96
2/2
✓ Branch 0 taken 75264 times.
✓ Branch 1 taken 112896 times.
188160 uint16_t r = is_be ? AV_RB16(ref + i * 2) : AV_RL16(ref + i * 2);
97
2/2
✓ Branch 0 taken 75264 times.
✓ Branch 1 taken 112896 times.
188160 uint16_t t = is_be ? AV_RB16(test + i * 2) : AV_RL16(test + i * 2);
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(( r & 0x1f) - ( t & 0x1f)) > accuracy)
99 ✗ return 1;
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(((r >> 5) & 0x3f) - ((t >> 5) & 0x3f)) > accuracy)
101 ✗ return 1;
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188160 times.
188160 if (abs(((r >> 11) & 0x1f) - ((t >> 11) & 0x1f)) > accuracy)
103 ✗ return 1;
104 }
105 240 return 0;
106 }
107
108 70 static void check_yuv2rgb(int src_pix_fmt)
109 {
110 70 const AVPixFmtDescriptor *src_desc = av_pix_fmt_desc_get(src_pix_fmt);
111 #define MAX_LINE_SIZE 1920
112 #define SRC_STRIDE_PAD 32
113 #define NUM_LINES 4
114 static const int input_sizes[] = {8, 128, 1080, MAX_LINE_SIZE};
115
116 70 declare_func(int, SwsInternal *c, const uint8_t *const src[],
117 const int srcStride[], int srcSliceY, int srcSliceH,
118 uint8_t *const dst[], const int dstStride[]);
119
120 70 LOCAL_ALIGNED_8(uint8_t, src_y, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
121 70 LOCAL_ALIGNED_8(uint8_t, src_u, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
122 70 LOCAL_ALIGNED_8(uint8_t, src_v, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
123 70 LOCAL_ALIGNED_8(uint8_t, src_a, [(MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES]);
124 70 const uint8_t *src[4] = { src_y, src_u, src_v, src_a };
125
126 70 LOCAL_ALIGNED_8(uint8_t, dst0_0, [NUM_LINES * MAX_LINE_SIZE * 6]);
127 70 LOCAL_ALIGNED_8(uint8_t, dst0_1, [NUM_LINES * MAX_LINE_SIZE]);
128 70 LOCAL_ALIGNED_8(uint8_t, dst0_2, [NUM_LINES * MAX_LINE_SIZE]);
129 70 uint8_t *dst0[4] = { dst0_0, dst0_1, dst0_2 };
130
131 70 LOCAL_ALIGNED_8(uint8_t, dst1_0, [NUM_LINES * MAX_LINE_SIZE * 6]);
132 70 LOCAL_ALIGNED_8(uint8_t, dst1_1, [NUM_LINES * MAX_LINE_SIZE]);
133 70 LOCAL_ALIGNED_8(uint8_t, dst1_2, [NUM_LINES * MAX_LINE_SIZE]);
134 70 uint8_t *dst1[4] = { dst1_0, dst1_1, dst1_2 };
135
136
2/2
✓ Branch 1 taken 136640 times.
✓ Branch 2 taken 70 times.
136710 randomize_buffers(src_y, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES);
137
2/2
✓ Branch 1 taken 136640 times.
✓ Branch 2 taken 70 times.
136710 randomize_buffers(src_u, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES);
138
2/2
✓ Branch 1 taken 136640 times.
✓ Branch 2 taken 70 times.
136710 randomize_buffers(src_v, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES);
139
2/2
✓ Branch 1 taken 136640 times.
✓ Branch 2 taken 70 times.
136710 randomize_buffers(src_a, (MAX_LINE_SIZE + SRC_STRIDE_PAD) * NUM_LINES);
140
141
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 70 times.
1120 for (int dfi = 0; dfi < FF_ARRAY_ELEMS(dst_fmts); dfi++) {
142 1050 int dst_pix_fmt = dst_fmts[dfi];
143 1050 const AVPixFmtDescriptor *dst_desc = av_pix_fmt_desc_get(dst_pix_fmt);
144 1050 int sample_size = av_get_padded_bits_per_pixel(dst_desc) >> 3;
145
2/2
✓ Branch 0 taken 4200 times.
✓ Branch 1 taken 1050 times.
5250 for (int isi = 0; isi < FF_ARRAY_ELEMS(input_sizes); isi++) {
146 SwsContext *sws;
147 SwsInternal *c;
148 int log_level;
149 4200 int width = input_sizes[isi];
150 4200 int srcSliceY = 0;
151 4200 int srcSliceH = NUM_LINES;
152 /* Use av_image_get_linesize so that semi-planar formats (NV12,
153 * NV21) get the correct interleaved-UV stride (= width bytes),
154 * not (width >> log2_chroma_w) which would only count UV pairs. */
155 4200 int chroma_linesize = av_image_get_linesize(src_pix_fmt, width, 1);
156 4200 int srcStride[4] = {
157 4200 width + SRC_STRIDE_PAD,
158 4200 chroma_linesize + SRC_STRIDE_PAD,
159 4200 chroma_linesize + SRC_STRIDE_PAD,
160 4200 width + SRC_STRIDE_PAD,
161 };
162 4200 int dstStride[4] = {
163 MAX_LINE_SIZE * 6,
164 MAX_LINE_SIZE,
165 MAX_LINE_SIZE,
166 };
167
168 // override log level to prevent spamming of the message
169 // "No accelerated colorspace conversion found from %s to %s"
170 4200 log_level = av_log_get_level();
171 4200 av_log_set_level(AV_LOG_ERROR);
172 4200 sws = sws_getContext(width, srcSliceH, src_pix_fmt,
173 width, srcSliceH, dst_pix_fmt,
174 0, NULL, NULL, NULL);
175 4200 av_log_set_level(log_level);
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4200 times.
4200 if (!sws)
177 ✗ fail();
178
179 4200 c = sws_internal(sws);
180
2/2
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 3936 times.
4200 if (check_func(c->convert_unscaled, "%s_%s_%d", src_desc->name, dst_desc->name, width)) {
181 264 memset(dst0_0, 0xFF, NUM_LINES * MAX_LINE_SIZE * 6);
182 264 memset(dst1_0, 0xFF, NUM_LINES * MAX_LINE_SIZE * 6);
183
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 240 times.
264 if (dst_pix_fmt == AV_PIX_FMT_GBRP) {
184 24 memset(dst0_1, 0xFF, NUM_LINES * MAX_LINE_SIZE);
185 24 memset(dst0_2, 0xFF, NUM_LINES * MAX_LINE_SIZE);
186 24 memset(dst1_1, 0xFF, NUM_LINES * MAX_LINE_SIZE);
187 24 memset(dst1_2, 0xFF, NUM_LINES * MAX_LINE_SIZE);
188 }
189
190
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 264 times.
264 call_ref(c, src, srcStride, srcSliceY,
191 srcSliceH, dst0, dstStride);
192 264 call_new(c, src, srcStride, srcSliceY,
193 srcSliceH, dst1, dstStride);
194
195
4/4
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 240 times.
✓ Branch 3 taken 12 times.
264 if (dst_pix_fmt == AV_PIX_FMT_ARGB ||
196
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 24 times.
240 dst_pix_fmt == AV_PIX_FMT_ABGR ||
197
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 24 times.
216 dst_pix_fmt == AV_PIX_FMT_RGBA ||
198
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 24 times.
192 dst_pix_fmt == AV_PIX_FMT_BGRA ||
199
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 144 times.
168 dst_pix_fmt == AV_PIX_FMT_RGB24 ||
200 dst_pix_fmt == AV_PIX_FMT_BGR24) {
201
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 120 times.
600 for (int row = 0; row < srcSliceH; row++)
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 480 times.
480 if (cmp_off_by_n(dst0_0 + row * dstStride[0],
203 480 dst1_0 + row * dstStride[0],
204 480 width * sample_size, 3))
205 ✗ fail();
206
4/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 12 times.
144 } else if (dst_pix_fmt == AV_PIX_FMT_RGB565LE ||
207
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 12 times.
108 dst_pix_fmt == AV_PIX_FMT_BGR565LE ||
208
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84 times.
96 dst_pix_fmt == AV_PIX_FMT_RGB565BE ||
209 60 dst_pix_fmt == AV_PIX_FMT_BGR565BE) {
210
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 36 times.
60 int is_be = dst_pix_fmt == AV_PIX_FMT_RGB565BE ||
211 dst_pix_fmt == AV_PIX_FMT_BGR565BE;
212
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 for (int row = 0; row < srcSliceH; row++)
213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (cmp_565_by_n(dst0_0 + row * dstStride[0],
214 240 dst1_0 + row * dstStride[0],
215 width, 2, is_be))
216 ✗ fail();
217
4/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 12 times.
84 } else if (dst_pix_fmt == AV_PIX_FMT_RGB555LE ||
218
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
48 dst_pix_fmt == AV_PIX_FMT_BGR555LE ||
219
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 dst_pix_fmt == AV_PIX_FMT_RGB555BE ||
220 60 dst_pix_fmt == AV_PIX_FMT_BGR555BE) {
221
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 36 times.
60 int is_be = dst_pix_fmt == AV_PIX_FMT_RGB555BE ||
222 dst_pix_fmt == AV_PIX_FMT_BGR555BE;
223
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 60 times.
300 for (int row = 0; row < srcSliceH; row++)
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 240 times.
240 if (cmp_555_by_n(dst0_0 + row * dstStride[0],
225 240 dst1_0 + row * dstStride[0],
226 width, 2, is_be))
227 ✗ fail();
228
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if (dst_pix_fmt == AV_PIX_FMT_GBRP) {
229
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 24 times.
96 for (int p = 0; p < 3; p++)
230
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 72 times.
360 for (int row = 0; row < srcSliceH; row++)
231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
288 if (cmp_off_by_n(dst0[p] + row * dstStride[p],
232 288 dst1[p] + row * dstStride[p],
233 width, 3))
234 ✗ fail();
235 } else {
236 ✗ fail();
237 }
238
239
1/18
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
264 bench_new(c, src, srcStride, srcSliceY,
240 srcSliceH, dst0, dstStride);
241 }
242 4200 sws_freeContext(sws);
243 }
244 }
245 70 }
246
247 #undef NUM_LINES
248 #undef SRC_STRIDE_PAD
249 #undef MAX_LINE_SIZE
250
251 14 void checkasm_check_sw_yuv2rgb(void)
252 {
253 14 check_yuv2rgb(AV_PIX_FMT_YUV420P);
254 14 report("yuv420p");
255 14 check_yuv2rgb(AV_PIX_FMT_YUV422P);
256 14 report("yuv422p");
257 14 check_yuv2rgb(AV_PIX_FMT_YUVA420P);
258 14 report("yuva420p");
259 14 check_yuv2rgb(AV_PIX_FMT_NV12);
260 14 report("nv12");
261 14 check_yuv2rgb(AV_PIX_FMT_NV21);
262 14 report("nv21");
263 14 }
264