1 /*
2 * Copyright (c) 2016 Ronald S. Bultje <rsbultje@gmail.com>
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 <string.h>
22 #include "checkasm.h"
23 #include "libavfilter/colorspacedsp.h"
24 #include "libavutil/common.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/intreadwrite.h"
27
28 #define W 64
29 #define H 64
30
31 #define randomize_buffers() \
32 do { \
33 unsigned mask = bpp_mask[idepth]; \
34 int n, m; \
35 int bpp = 1 + (!!idepth); \
36 int buf_size = W * H * bpp; \
37 for (m = 0; m < 3; m++) { \
38 int ss = m ? ss_w + ss_h : 0; \
39 int plane_sz = buf_size >> ss; \
40 for (n = 0; n < plane_sz; n += 4) { \
41 unsigned r = rnd() & mask; \
42 AV_WN32A(&src[m][n], r); \
43 } \
44 } \
45 } while (0)
46
47 static const char *format_string[] = {
48 "444", "422", "420"
49 };
50
51 static const unsigned bpp_mask[] = { 0xffffffff, 0x03ff03ff, 0x0fff0fff };
52
check_yuv2yuv(void)53 static void check_yuv2yuv(void)
54 {
55 declare_func(void, uint8_t *dst[3], ptrdiff_t dst_stride[3],
56 uint8_t *src[3], ptrdiff_t src_stride[3],
57 int w, int h, const int16_t coeff[3][3][8],
58 const int16_t off[2][8]);
59 ColorSpaceDSPContext dsp;
60 int idepth, odepth, fmt, n;
61 LOCAL_ALIGNED_32(uint8_t, src_y, [W * H * 2]);
62 LOCAL_ALIGNED_32(uint8_t, src_u, [W * H * 2]);
63 LOCAL_ALIGNED_32(uint8_t, src_v, [W * H * 2]);
64 uint8_t *src[3] = { src_y, src_u, src_v };
65 LOCAL_ALIGNED_32(uint8_t, dst0_y, [W * H * 2]);
66 LOCAL_ALIGNED_32(uint8_t, dst0_u, [W * H * 2]);
67 LOCAL_ALIGNED_32(uint8_t, dst0_v, [W * H * 2]);
68 LOCAL_ALIGNED_32(uint8_t, dst1_y, [W * H * 2]);
69 LOCAL_ALIGNED_32(uint8_t, dst1_u, [W * H * 2]);
70 LOCAL_ALIGNED_32(uint8_t, dst1_v, [W * H * 2]);
71 uint8_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
72 LOCAL_ALIGNED_32(int16_t, offset_buf, [16]);
73 LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
74 int16_t (*offset)[8] = (int16_t(*)[8]) offset_buf;
75 int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
76
77 ff_colorspacedsp_init(&dsp);
78 for (n = 0; n < 8; n++) {
79 offset[0][n] = offset[1][n] = 16;
80
81 coeff[0][0][n] = (1 << 14) + (1 << 7) + 1;
82 coeff[0][1][n] = (1 << 7) - 1;
83 coeff[0][2][n] = -(1 << 8);
84 coeff[1][0][n] = coeff[2][0][n] = 0;
85 coeff[1][1][n] = (1 << 14) + (1 << 7);
86 coeff[1][2][n] = -(1 << 7);
87 coeff[2][2][n] = (1 << 14) - (1 << 6);
88 coeff[2][1][n] = 1 << 6;
89 }
90 for (idepth = 0; idepth < 3; idepth++) {
91 for (odepth = 0; odepth < 3; odepth++) {
92 for (fmt = 0; fmt < 3; fmt++) {
93 if (check_func(dsp.yuv2yuv[idepth][odepth][fmt],
94 "ff_colorspacedsp_yuv2yuv_%sp%dto%d",
95 format_string[fmt],
96 idepth * 2 + 8, odepth * 2 + 8)) {
97 int ss_w = !!fmt, ss_h = fmt == 2;
98 int y_src_stride = W << !!idepth, y_dst_stride = W << !!odepth;
99 int uv_src_stride = y_src_stride >> ss_w, uv_dst_stride = y_dst_stride >> ss_w;
100
101 randomize_buffers();
102 call_ref(dst0, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
103 src, (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
104 W, H, coeff, offset);
105 call_new(dst1, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
106 src, (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
107 W, H, coeff, offset);
108 if (memcmp(dst0[0], dst1[0], y_dst_stride * H) ||
109 memcmp(dst0[1], dst1[1], uv_dst_stride * H >> ss_h) ||
110 memcmp(dst0[2], dst1[2], uv_dst_stride * H >> ss_h)) {
111 fail();
112 }
113 }
114 }
115 }
116 }
117
118 report("yuv2yuv");
119 }
120
check_yuv2rgb(void)121 static void check_yuv2rgb(void)
122 {
123 declare_func(void, int16_t *dst[3], ptrdiff_t dst_stride,
124 uint8_t *src[3], ptrdiff_t src_stride[3],
125 int w, int h, const int16_t coeff[3][3][8],
126 const int16_t off[8]);
127 ColorSpaceDSPContext dsp;
128 int idepth, fmt, n;
129 LOCAL_ALIGNED_32(uint8_t, src_y, [W * H * 2]);
130 LOCAL_ALIGNED_32(uint8_t, src_u, [W * H * 2]);
131 LOCAL_ALIGNED_32(uint8_t, src_v, [W * H * 2]);
132 uint8_t *src[3] = { src_y, src_u, src_v };
133 LOCAL_ALIGNED_32(int16_t, dst0_y, [W * H]);
134 LOCAL_ALIGNED_32(int16_t, dst0_u, [W * H]);
135 LOCAL_ALIGNED_32(int16_t, dst0_v, [W * H]);
136 LOCAL_ALIGNED_32(int16_t, dst1_y, [W * H]);
137 LOCAL_ALIGNED_32(int16_t, dst1_u, [W * H]);
138 LOCAL_ALIGNED_32(int16_t, dst1_v, [W * H]);
139 int16_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
140 LOCAL_ALIGNED_32(int16_t, offset, [8]);
141 LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
142 int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
143
144 ff_colorspacedsp_init(&dsp);
145 for (n = 0; n < 8; n++) {
146 offset[n] = 16;
147
148 coeff[0][0][n] = coeff[1][0][n] = coeff[2][0][n] = (1 << 14) | 1;
149 coeff[0][1][n] = coeff[2][2][n] = 0;
150 coeff[0][2][n] = 1 << 13;
151 coeff[1][1][n] = -(1 << 12);
152 coeff[1][2][n] = 1 << 12;
153 coeff[2][1][n] = 1 << 11;
154 }
155 for (idepth = 0; idepth < 3; idepth++) {
156 for (fmt = 0; fmt < 3; fmt++) {
157 if (check_func(dsp.yuv2rgb[idepth][fmt],
158 "ff_colorspacedsp_yuv2rgb_%sp%d",
159 format_string[fmt], idepth * 2 + 8)) {
160 int ss_w = !!fmt, ss_h = fmt == 2;
161 int y_src_stride = W << !!idepth;
162 int uv_src_stride = y_src_stride >> ss_w;
163
164 randomize_buffers();
165 call_ref(dst0, W, src,
166 (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
167 W, H, coeff, offset);
168 call_new(dst1, W, src,
169 (ptrdiff_t[3]) { y_src_stride, uv_src_stride, uv_src_stride },
170 W, H, coeff, offset);
171 if (memcmp(dst0[0], dst1[0], W * H * sizeof(int16_t)) ||
172 memcmp(dst0[1], dst1[1], W * H * sizeof(int16_t)) ||
173 memcmp(dst0[2], dst1[2], W * H * sizeof(int16_t))) {
174 fail();
175 }
176 }
177 }
178 }
179
180 report("yuv2rgb");
181 }
182
183 #undef randomize_buffers
184 #define randomize_buffers() \
185 do { \
186 int y, x, p; \
187 for (p = 0; p < 3; p++) { \
188 for (y = 0; y < H; y++) { \
189 for (x = 0; x < W; x++) { \
190 int r = rnd() & 0x7fff; \
191 r -= (32768 - 28672) >> 1; \
192 src[p][y * W + x] = r; \
193 } \
194 } \
195 } \
196 } while (0)
197
check_rgb2yuv(void)198 static void check_rgb2yuv(void)
199 {
200 declare_func(void, uint8_t *dst[3], ptrdiff_t dst_stride[3],
201 int16_t *src[3], ptrdiff_t src_stride,
202 int w, int h, const int16_t coeff[3][3][8],
203 const int16_t off[8]);
204 ColorSpaceDSPContext dsp;
205 int odepth, fmt, n;
206 LOCAL_ALIGNED_32(int16_t, src_y, [W * H * 2]);
207 LOCAL_ALIGNED_32(int16_t, src_u, [W * H * 2]);
208 LOCAL_ALIGNED_32(int16_t, src_v, [W * H * 2]);
209 int16_t *src[3] = { src_y, src_u, src_v };
210 LOCAL_ALIGNED_32(uint8_t, dst0_y, [W * H * 2]);
211 LOCAL_ALIGNED_32(uint8_t, dst0_u, [W * H * 2]);
212 LOCAL_ALIGNED_32(uint8_t, dst0_v, [W * H * 2]);
213 LOCAL_ALIGNED_32(uint8_t, dst1_y, [W * H * 2]);
214 LOCAL_ALIGNED_32(uint8_t, dst1_u, [W * H * 2]);
215 LOCAL_ALIGNED_32(uint8_t, dst1_v, [W * H * 2]);
216 uint8_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
217 LOCAL_ALIGNED_32(int16_t, offset, [8]);
218 LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
219 int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
220
221 ff_colorspacedsp_init(&dsp);
222 for (n = 0; n < 8; n++) {
223 offset[n] = 16;
224
225 // these somewhat resemble bt601/smpte170m coefficients
226 coeff[0][0][n] = lrint(0.3 * (1 << 14));
227 coeff[0][1][n] = lrint(0.6 * (1 << 14));
228 coeff[0][2][n] = lrint(0.1 * (1 << 14));
229 coeff[1][0][n] = lrint(-0.15 * (1 << 14));
230 coeff[1][1][n] = lrint(-0.35 * (1 << 14));
231 coeff[1][2][n] = lrint(0.5 * (1 << 14));
232 coeff[2][0][n] = lrint(0.5 * (1 << 14));
233 coeff[2][1][n] = lrint(-0.42 * (1 << 14));
234 coeff[2][2][n] = lrint(-0.08 * (1 << 14));
235 }
236 for (odepth = 0; odepth < 3; odepth++) {
237 for (fmt = 0; fmt < 3; fmt++) {
238 if (check_func(dsp.rgb2yuv[odepth][fmt],
239 "ff_colorspacedsp_rgb2yuv_%sp%d",
240 format_string[fmt], odepth * 2 + 8)) {
241 int ss_w = !!fmt, ss_h = fmt == 2;
242 int y_dst_stride = W << !!odepth;
243 int uv_dst_stride = y_dst_stride >> ss_w;
244
245 randomize_buffers();
246 call_ref(dst0, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
247 src, W, W, H, coeff, offset);
248 call_new(dst1, (ptrdiff_t[3]) { y_dst_stride, uv_dst_stride, uv_dst_stride },
249 src, W, W, H, coeff, offset);
250 if (memcmp(dst0[0], dst1[0], H * y_dst_stride) ||
251 memcmp(dst0[1], dst1[1], H * uv_dst_stride >> ss_h) ||
252 memcmp(dst0[2], dst1[2], H * uv_dst_stride >> ss_h)) {
253 fail();
254 }
255 }
256 }
257 }
258
259 report("rgb2yuv");
260 }
261
check_multiply3x3(void)262 static void check_multiply3x3(void)
263 {
264 declare_func(void, int16_t *data[3], ptrdiff_t stride,
265 int w, int h, const int16_t coeff[3][3][8]);
266 ColorSpaceDSPContext dsp;
267 LOCAL_ALIGNED_32(int16_t, dst0_y, [W * H]);
268 LOCAL_ALIGNED_32(int16_t, dst0_u, [W * H]);
269 LOCAL_ALIGNED_32(int16_t, dst0_v, [W * H]);
270 LOCAL_ALIGNED_32(int16_t, dst1_y, [W * H]);
271 LOCAL_ALIGNED_32(int16_t, dst1_u, [W * H]);
272 LOCAL_ALIGNED_32(int16_t, dst1_v, [W * H]);
273 int16_t *dst0[3] = { dst0_y, dst0_u, dst0_v }, *dst1[3] = { dst1_y, dst1_u, dst1_v };
274 int16_t **src = dst0;
275 LOCAL_ALIGNED_32(int16_t, coeff_buf, [3 * 3 * 8]);
276 int16_t (*coeff)[3][8] = (int16_t(*)[3][8]) coeff_buf;
277 int n;
278
279 ff_colorspacedsp_init(&dsp);
280 for (n = 0; n < 8; n++) {
281 coeff[0][0][n] = lrint(0.85 * (1 << 14));
282 coeff[0][1][n] = lrint(0.10 * (1 << 14));
283 coeff[0][2][n] = lrint(0.05 * (1 << 14));
284 coeff[1][0][n] = lrint(-0.1 * (1 << 14));
285 coeff[1][1][n] = lrint(0.95 * (1 << 14));
286 coeff[1][2][n] = lrint(0.15 * (1 << 14));
287 coeff[2][0][n] = lrint(-0.2 * (1 << 14));
288 coeff[2][1][n] = lrint(0.30 * (1 << 14));
289 coeff[2][2][n] = lrint(0.90 * (1 << 14));
290 }
291 if (check_func(dsp.multiply3x3, "ff_colorspacedsp_multiply3x3")) {
292 randomize_buffers();
293 memcpy(dst1_y, dst0_y, W * H * sizeof(*dst1_y));
294 memcpy(dst1_u, dst0_u, W * H * sizeof(*dst1_u));
295 memcpy(dst1_v, dst0_v, W * H * sizeof(*dst1_v));
296 call_ref(dst0, W, W, H, coeff);
297 call_new(dst1, W, W, H, coeff);
298 if (memcmp(dst0[0], dst1[0], H * W * sizeof(*dst0_y)) ||
299 memcmp(dst0[1], dst1[1], H * W * sizeof(*dst0_u)) ||
300 memcmp(dst0[2], dst1[2], H * W * sizeof(*dst0_v))) {
301 fail();
302 }
303 }
304
305 report("multiply3x3");
306 }
307
checkasm_check_colorspace(void)308 void checkasm_check_colorspace(void)
309 {
310 check_yuv2yuv();
311 check_yuv2rgb();
312 check_rgb2yuv();
313 check_multiply3x3();
314 }
315