OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2015 The LibYuv Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include <stdlib.h> | |
12 | |
13 #include "libyuv/convert.h" | |
14 #include "libyuv/convert_argb.h" | |
15 #include "libyuv/convert_from.h" | |
16 #include "libyuv/convert_from_argb.h" | |
17 #include "libyuv/cpu_id.h" | |
18 #include "libyuv/row.h" // For Sobel | |
19 #include "../unit_test/unit_test.h" | |
20 | |
21 namespace libyuv { | |
22 | |
23 // TODO(fbarchard): Port high accuracy YUV to RGB to Neon. | |
24 #if !defined(LIBYUV_DISABLE_NEON) && \ | |
25 (defined(__aarch64__) || defined(__ARM_NEON__) || defined(LIBYUV_NEON)) | |
26 #define ERROR_R 1 | |
27 #define ERROR_G 1 | |
28 #define ERROR_B 3 | |
29 #define ERROR_FULL 6 | |
30 #define ERROR_J420 4 | |
31 #else | |
32 #define ERROR_R 1 | |
33 #define ERROR_G 1 | |
34 #define ERROR_B 3 | |
35 #define ERROR_FULL 5 | |
36 #define ERROR_J420 3 | |
37 #endif | |
38 | |
39 #define TESTCS(TESTNAME, YUVTOARGB, ARGBTOYUV, HS1, HS, HN, DIFF) \ | |
40 TEST_F(LibYUVScaleTest, DISABLED_ ## TESTNAME) { \ | |
41 const int kPixels = benchmark_width_ * benchmark_height_; \ | |
42 const int kHalfPixels = ((benchmark_width_ + 1) / 2) * \ | |
43 ((benchmark_height_ + HS1) / HS); \ | |
44 align_buffer_64(orig_y, kPixels); \ | |
45 align_buffer_64(orig_u, kHalfPixels); \ | |
46 align_buffer_64(orig_v, kHalfPixels); \ | |
47 align_buffer_64(orig_pixels, kPixels * 4); \ | |
48 align_buffer_64(temp_y, kPixels); \ | |
49 align_buffer_64(temp_u, kHalfPixels); \ | |
50 align_buffer_64(temp_v, kHalfPixels); \ | |
51 align_buffer_64(dst_pixels_opt, kPixels * 4); \ | |
52 align_buffer_64(dst_pixels_c, kPixels * 4); \ | |
53 \ | |
54 MemRandomize(orig_pixels, kPixels * 4); \ | |
55 MemRandomize(orig_y, kPixels); \ | |
56 MemRandomize(orig_u, kHalfPixels); \ | |
57 MemRandomize(orig_v, kHalfPixels); \ | |
58 MemRandomize(temp_y, kPixels); \ | |
59 MemRandomize(temp_u, kHalfPixels); \ | |
60 MemRandomize(temp_v, kHalfPixels); \ | |
61 MemRandomize(dst_pixels_opt, kPixels * 4); \ | |
62 MemRandomize(dst_pixels_c, kPixels * 4); \ | |
63 \ | |
64 /* The test is overall for color conversion matrix being reversible, so */ \ | |
65 /* this initializes the pixel with 2x2 blocks to eliminate subsampling. */ \ | |
66 uint8* p = orig_y; \ | |
67 for (int y = 0; y < benchmark_height_ - HS1; y += HS) { \ | |
68 for (int x = 0; x < benchmark_width_ - 1; x += 2) { \ | |
69 uint8 r = static_cast<uint8>(fastrand()); \ | |
70 p[0] = r; \ | |
71 p[1] = r; \ | |
72 p[HN] = r; \ | |
73 p[HN + 1] = r; \ | |
74 p += 2; \ | |
75 } \ | |
76 if (benchmark_width_ & 1) { \ | |
77 uint8 r = static_cast<uint8>(fastrand()); \ | |
78 p[0] = r; \ | |
79 p[HN] = r; \ | |
80 p += 1; \ | |
81 } \ | |
82 p += HN; \ | |
83 } \ | |
84 \ | |
85 /* Start with YUV converted to ARGB. */ \ | |
86 YUVTOARGB(orig_y, benchmark_width_, \ | |
87 orig_u, (benchmark_width_ + 1) / 2, \ | |
88 orig_v, (benchmark_width_ + 1) / 2, \ | |
89 orig_pixels, benchmark_width_ * 4, \ | |
90 benchmark_width_, benchmark_height_); \ | |
91 \ | |
92 ARGBTOYUV(orig_pixels, benchmark_width_ * 4, \ | |
93 temp_y, benchmark_width_, \ | |
94 temp_u, (benchmark_width_ + 1) / 2, \ | |
95 temp_v, (benchmark_width_ + 1) / 2, \ | |
96 benchmark_width_, benchmark_height_); \ | |
97 \ | |
98 MaskCpuFlags(disable_cpu_flags_); \ | |
99 YUVTOARGB(temp_y, benchmark_width_, \ | |
100 temp_u, (benchmark_width_ + 1) / 2, \ | |
101 temp_v, (benchmark_width_ + 1) / 2, \ | |
102 dst_pixels_c, benchmark_width_ * 4, \ | |
103 benchmark_width_, benchmark_height_); \ | |
104 MaskCpuFlags(-1); \ | |
105 \ | |
106 for (int i = 0; i < benchmark_iterations_; ++i) { \ | |
107 YUVTOARGB(temp_y, benchmark_width_, \ | |
108 temp_u, (benchmark_width_ + 1) / 2, \ | |
109 temp_v, (benchmark_width_ + 1) / 2, \ | |
110 dst_pixels_opt, benchmark_width_ * 4, \ | |
111 benchmark_width_, benchmark_height_); \ | |
112 } \ | |
113 /* Test C and SIMD match. */ \ | |
114 for (int i = 0; i < kPixels * 4; ++i) { \ | |
115 EXPECT_EQ(dst_pixels_c[i], dst_pixels_opt[i]); \ | |
116 } \ | |
117 /* Test SIMD is close to original. */ \ | |
118 for (int i = 0; i < kPixels * 4; ++i) { \ | |
119 EXPECT_NEAR(static_cast<int>(orig_pixels[i]), \ | |
120 static_cast<int>(dst_pixels_opt[i]), DIFF); \ | |
121 } \ | |
122 \ | |
123 free_aligned_buffer_64(orig_pixels); \ | |
124 free_aligned_buffer_64(orig_y); \ | |
125 free_aligned_buffer_64(orig_u); \ | |
126 free_aligned_buffer_64(orig_v); \ | |
127 free_aligned_buffer_64(temp_y); \ | |
128 free_aligned_buffer_64(temp_u); \ | |
129 free_aligned_buffer_64(temp_v); \ | |
130 free_aligned_buffer_64(dst_pixels_opt); \ | |
131 free_aligned_buffer_64(dst_pixels_c); \ | |
132 } \ | |
133 | |
134 TESTCS(ScaleTestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, | |
135 ERROR_FULL) | |
136 TESTCS(ScaleTestI422, I422ToARGB, ARGBToI422, 0, 1, 0, ERROR_FULL) | |
137 TESTCS(ScaleTestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, | |
138 ERROR_J420) | |
139 TESTCS(ScaleTestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, 3) | |
140 | |
141 static void YUVToRGB(int y, int u, int v, int* r, int* g, int* b) { | |
142 const int kWidth = 16; | |
143 const int kHeight = 1; | |
144 const int kPixels = kWidth * kHeight; | |
145 const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); | |
146 | |
147 SIMD_ALIGNED(uint8 orig_y[16]); | |
148 SIMD_ALIGNED(uint8 orig_u[8]); | |
149 SIMD_ALIGNED(uint8 orig_v[8]); | |
150 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); | |
151 memset(orig_y, y, kPixels); | |
152 memset(orig_u, u, kHalfPixels); | |
153 memset(orig_v, v, kHalfPixels); | |
154 | |
155 /* YUV converted to ARGB. */ | |
156 I422ToARGB(orig_y, kWidth, | |
157 orig_u, (kWidth + 1) / 2, | |
158 orig_v, (kWidth + 1) / 2, | |
159 orig_pixels, kWidth * 4, | |
160 kWidth, kHeight); | |
161 | |
162 *b = orig_pixels[0]; | |
163 *g = orig_pixels[1]; | |
164 *r = orig_pixels[2]; | |
165 } | |
166 | |
167 static void YUVJToRGB(int y, int u, int v, int* r, int* g, int* b) { | |
168 const int kWidth = 16; | |
169 const int kHeight = 1; | |
170 const int kPixels = kWidth * kHeight; | |
171 const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2); | |
172 | |
173 SIMD_ALIGNED(uint8 orig_y[16]); | |
174 SIMD_ALIGNED(uint8 orig_u[8]); | |
175 SIMD_ALIGNED(uint8 orig_v[8]); | |
176 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); | |
177 memset(orig_y, y, kPixels); | |
178 memset(orig_u, u, kHalfPixels); | |
179 memset(orig_v, v, kHalfPixels); | |
180 | |
181 /* YUV converted to ARGB. */ | |
182 J422ToARGB(orig_y, kWidth, | |
183 orig_u, (kWidth + 1) / 2, | |
184 orig_v, (kWidth + 1) / 2, | |
185 orig_pixels, kWidth * 4, | |
186 kWidth, kHeight); | |
187 | |
188 *b = orig_pixels[0]; | |
189 *g = orig_pixels[1]; | |
190 *r = orig_pixels[2]; | |
191 } | |
192 | |
193 static void YToRGB(int y, int* r, int* g, int* b) { | |
194 const int kWidth = 16; | |
195 const int kHeight = 1; | |
196 const int kPixels = kWidth * kHeight; | |
197 | |
198 SIMD_ALIGNED(uint8 orig_y[16]); | |
199 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); | |
200 memset(orig_y, y, kPixels); | |
201 | |
202 /* YUV converted to ARGB. */ | |
203 I400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight); | |
204 | |
205 *b = orig_pixels[0]; | |
206 *g = orig_pixels[1]; | |
207 *r = orig_pixels[2]; | |
208 } | |
209 | |
210 static void YJToRGB(int y, int* r, int* g, int* b) { | |
211 const int kWidth = 16; | |
212 const int kHeight = 1; | |
213 const int kPixels = kWidth * kHeight; | |
214 | |
215 SIMD_ALIGNED(uint8 orig_y[16]); | |
216 SIMD_ALIGNED(uint8 orig_pixels[16 * 4]); | |
217 memset(orig_y, y, kPixels); | |
218 | |
219 /* YUV converted to ARGB. */ | |
220 J400ToARGB(orig_y, kWidth, orig_pixels, kWidth * 4, kWidth, kHeight); | |
221 | |
222 *b = orig_pixels[0]; | |
223 *g = orig_pixels[1]; | |
224 *r = orig_pixels[2]; | |
225 } | |
226 | |
227 // Pick a method for rounding. | |
228 #define ROUND(f) static_cast<int>(f + 0.5) | |
229 static int RoundToByte(float f) { | |
230 int i = ROUND(f); | |
231 if (i < 0) { | |
232 i = 0; | |
233 } | |
234 if (i > 255) { | |
235 i = 255; | |
236 } | |
237 return i; | |
238 } | |
239 | |
240 #define RANDOM256(s) ((s & 1) ? ((s >> 1) ^ 0xb8) : (s >> 1)) | |
241 | |
242 static void YUVToRGBReference(int y, int u, int v, int* r, int* g, int* b) { | |
243 *r = RoundToByte((y - 16) * 1.164 - (v - 128) * -1.596); | |
244 *g = RoundToByte((y - 16) * 1.164 - (u - 128) * 0.391 - (v - 128) * 0.813); | |
245 *b = RoundToByte((y - 16) * 1.164 - (u - 128) * -2.018); | |
246 } | |
247 | |
248 static void YUVJToRGBReference(int y, int u, int v, int* r, int* g, int* b) { | |
249 *r = RoundToByte(y - (v - 128) * -1.40200); | |
250 *g = RoundToByte(y - (u - 128) * 0.34414 - (v - 128) * 0.71414); | |
251 *b = RoundToByte(y - (u - 128) * -1.77200); | |
252 } | |
253 | |
254 TEST_F(LibYUVScaleTest, DISABLED_ScaleTestYUV) { | |
255 int r0, g0, b0, r1, g1, b1; | |
256 | |
257 // cyan (less red) | |
258 YUVToRGBReference(240, 255, 0, &r0, &g0, &b0); | |
259 EXPECT_EQ(56, r0); | |
260 EXPECT_EQ(255, g0); | |
261 EXPECT_EQ(255, b0); | |
262 | |
263 YUVToRGB(240, 255, 0, &r1, &g1, &b1); | |
264 EXPECT_EQ(57, r1); | |
265 EXPECT_EQ(255, g1); | |
266 EXPECT_EQ(255, b1); | |
267 | |
268 // green (less red and blue) | |
269 YUVToRGBReference(240, 0, 0, &r0, &g0, &b0); | |
270 EXPECT_EQ(56, r0); | |
271 EXPECT_EQ(255, g0); | |
272 EXPECT_EQ(2, b0); | |
273 | |
274 YUVToRGB(240, 0, 0, &r1, &g1, &b1); | |
275 EXPECT_EQ(57, r1); | |
276 EXPECT_EQ(255, g1); | |
277 EXPECT_EQ(5, b1); | |
278 | |
279 for (int i = 0; i < 256; ++i) { | |
280 YUVToRGBReference(i, 128, 128, &r0, &g0, &b0); | |
281 YUVToRGB(i, 128, 128, &r1, &g1, &b1); | |
282 EXPECT_NEAR(r0, r1, ERROR_R); | |
283 EXPECT_NEAR(g0, g1, ERROR_G); | |
284 EXPECT_NEAR(b0, b1, ERROR_B); | |
285 | |
286 YUVToRGBReference(i, 0, 0, &r0, &g0, &b0); | |
287 YUVToRGB(i, 0, 0, &r1, &g1, &b1); | |
288 EXPECT_NEAR(r0, r1, ERROR_R); | |
289 EXPECT_NEAR(g0, g1, ERROR_G); | |
290 EXPECT_NEAR(b0, b1, ERROR_B); | |
291 | |
292 YUVToRGBReference(i, 0, 255, &r0, &g0, &b0); | |
293 YUVToRGB(i, 0, 255, &r1, &g1, &b1); | |
294 EXPECT_NEAR(r0, r1, ERROR_R); | |
295 EXPECT_NEAR(g0, g1, ERROR_G); | |
296 EXPECT_NEAR(b0, b1, ERROR_B); | |
297 } | |
298 } | |
299 | |
300 TEST_F(LibYUVScaleTest, DISABLED_ScaleTestGreyYUV) { | |
301 int r0, g0, b0, r1, g1, b1, r2, g2, b2; | |
302 | |
303 // black | |
304 YUVToRGBReference(16, 128, 128, &r0, &g0, &b0); | |
305 EXPECT_EQ(0, r0); | |
306 EXPECT_EQ(0, g0); | |
307 EXPECT_EQ(0, b0); | |
308 | |
309 YUVToRGB(16, 128, 128, &r1, &g1, &b1); | |
310 EXPECT_EQ(0, r1); | |
311 EXPECT_EQ(0, g1); | |
312 EXPECT_EQ(0, b1); | |
313 | |
314 // white | |
315 YUVToRGBReference(240, 128, 128, &r0, &g0, &b0); | |
316 EXPECT_EQ(255, r0); | |
317 EXPECT_EQ(255, g0); | |
318 EXPECT_EQ(255, b0); | |
319 | |
320 YUVToRGB(240, 128, 128, &r1, &g1, &b1); | |
321 EXPECT_EQ(255, r1); | |
322 EXPECT_EQ(255, g1); | |
323 EXPECT_EQ(255, b1); | |
324 | |
325 // grey | |
326 YUVToRGBReference(128, 128, 128, &r0, &g0, &b0); | |
327 EXPECT_EQ(130, r0); | |
328 EXPECT_EQ(130, g0); | |
329 EXPECT_EQ(130, b0); | |
330 | |
331 YUVToRGB(128, 128, 128, &r1, &g1, &b1); | |
332 EXPECT_EQ(130, r1); | |
333 EXPECT_EQ(130, g1); | |
334 EXPECT_EQ(130, b1); | |
335 | |
336 | |
337 for (int y = 0; y < 256; ++y) { | |
338 YUVToRGBReference(y, 128, 128, &r0, &g0, &b0); | |
339 YUVToRGB(y, 128, 128, &r1, &g1, &b1); | |
340 YToRGB(y, &r2, &g2, &b2); | |
341 EXPECT_EQ(r0, r1); | |
342 EXPECT_EQ(g0, g1); | |
343 EXPECT_EQ(b0, b1); | |
344 EXPECT_EQ(r0, r2); | |
345 EXPECT_EQ(g0, g2); | |
346 EXPECT_EQ(b0, b2); | |
347 } | |
348 } | |
349 | |
350 static void ScalePrintHistogram(int rh[256], int gh[256], int bh[256]) { | |
351 int i; | |
352 printf("hist"); | |
353 for (i = 0; i < 256; ++i) { | |
354 if (rh[i] || gh[i] || bh[i]) { | |
355 printf("\t%8d", i - 128); | |
356 } | |
357 } | |
358 printf("\nred"); | |
359 for (i = 0; i < 256; ++i) { | |
360 if (rh[i] || gh[i] || bh[i]) { | |
361 printf("\t%8d", rh[i]); | |
362 } | |
363 } | |
364 printf("\ngreen"); | |
365 for (i = 0; i < 256; ++i) { | |
366 if (rh[i] || gh[i] || bh[i]) { | |
367 printf("\t%8d", gh[i]); | |
368 } | |
369 } | |
370 printf("\nblue"); | |
371 for (i = 0; i < 256; ++i) { | |
372 if (rh[i] || gh[i] || bh[i]) { | |
373 printf("\t%8d", bh[i]); | |
374 } | |
375 } | |
376 printf("\n"); | |
377 } | |
378 | |
379 TEST_F(LibYUVScaleTest, DISABLED_ScaleTestFullYUV) { | |
380 int rh[256] = { 0, }, gh[256] = { 0, }, bh[256] = { 0, }; | |
381 for (int u = 0; u < 256; ++u) { | |
382 for (int v = 0; v < 256; ++v) { | |
383 for (int y2 = 0; y2 < 256; ++y2) { | |
384 int r0, g0, b0, r1, g1, b1; | |
385 int y = RANDOM256(y2); | |
386 YUVToRGBReference(y, u, v, &r0, &g0, &b0); | |
387 YUVToRGB(y, u, v, &r1, &g1, &b1); | |
388 EXPECT_NEAR(r0, r1, ERROR_R); | |
389 EXPECT_NEAR(g0, g1, ERROR_G); | |
390 EXPECT_NEAR(b0, b1, ERROR_B); | |
391 ++rh[r1 - r0 + 128]; | |
392 ++gh[g1 - g0 + 128]; | |
393 ++bh[b1 - b0 + 128]; | |
394 } | |
395 } | |
396 } | |
397 ScalePrintHistogram(rh, gh, bh); | |
398 } | |
399 | |
400 TEST_F(LibYUVScaleTest, DISABLED_ScaleTestFullYUVJ) { | |
401 int rh[256] = { 0, }, gh[256] = { 0, }, bh[256] = { 0, }; | |
402 for (int u = 0; u < 256; ++u) { | |
403 for (int v = 0; v < 256; ++v) { | |
404 for (int y2 = 0; y2 < 256; ++y2) { | |
405 int r0, g0, b0, r1, g1, b1; | |
406 int y = RANDOM256(y2); | |
407 YUVJToRGBReference(y, u, v, &r0, &g0, &b0); | |
408 YUVJToRGB(y, u, v, &r1, &g1, &b1); | |
409 EXPECT_NEAR(r0, r1, 1); | |
410 EXPECT_NEAR(g0, g1, 1); | |
411 EXPECT_NEAR(b0, b1, 1); | |
412 ++rh[r1 - r0 + 128]; | |
413 ++gh[g1 - g0 + 128]; | |
414 ++bh[b1 - b0 + 128]; | |
415 } | |
416 } | |
417 } | |
418 ScalePrintHistogram(rh, gh, bh); | |
419 } | |
420 | |
421 TEST_F(LibYUVScaleTest, DISABLED_ScaleTestGreyYUVJ) { | |
422 int r0, g0, b0, r1, g1, b1, r2, g2, b2; | |
423 | |
424 // black | |
425 YUVJToRGBReference(0, 128, 128, &r0, &g0, &b0); | |
426 EXPECT_EQ(0, r0); | |
427 EXPECT_EQ(0, g0); | |
428 EXPECT_EQ(0, b0); | |
429 | |
430 YUVJToRGB(0, 128, 128, &r1, &g1, &b1); | |
431 EXPECT_EQ(0, r1); | |
432 EXPECT_EQ(0, g1); | |
433 EXPECT_EQ(0, b1); | |
434 | |
435 // white | |
436 YUVJToRGBReference(255, 128, 128, &r0, &g0, &b0); | |
437 EXPECT_EQ(255, r0); | |
438 EXPECT_EQ(255, g0); | |
439 EXPECT_EQ(255, b0); | |
440 | |
441 YUVJToRGB(255, 128, 128, &r1, &g1, &b1); | |
442 EXPECT_EQ(255, r1); | |
443 EXPECT_EQ(255, g1); | |
444 EXPECT_EQ(255, b1); | |
445 | |
446 // grey | |
447 YUVJToRGBReference(128, 128, 128, &r0, &g0, &b0); | |
448 EXPECT_EQ(128, r0); | |
449 EXPECT_EQ(128, g0); | |
450 EXPECT_EQ(128, b0); | |
451 | |
452 YUVJToRGB(128, 128, 128, &r1, &g1, &b1); | |
453 EXPECT_EQ(128, r1); | |
454 EXPECT_EQ(128, g1); | |
455 EXPECT_EQ(128, b1); | |
456 | |
457 for (int y = 0; y < 256; ++y) { | |
458 YUVJToRGBReference(y, 128, 128, &r0, &g0, &b0); | |
459 YUVJToRGB(y, 128, 128, &r1, &g1, &b1); | |
460 YJToRGB(y, &r2, &g2, &b2); | |
461 EXPECT_EQ(r0, r1); | |
462 EXPECT_EQ(g0, g1); | |
463 EXPECT_EQ(b0, b1); | |
464 EXPECT_EQ(r0, r2); | |
465 EXPECT_EQ(g0, g2); | |
466 EXPECT_EQ(b0, b2); | |
467 } | |
468 } | |
469 | |
470 } // namespace libyuv | |
OLD | NEW |