Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: media/base/yuv_convert_unittest.cc

Issue 2694113002: Delete media/base/yuv_convert and dependents. Prefer libyuv. (Closed)
Patch Set: Fix media_unittests. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/yuv_convert_perftest.cc ('k') | media/renderers/skcanvas_video_renderer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/yuv_convert.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11
12 #include "base/base_paths.h"
13 #include "base/cpu.h"
14 #include "base/files/file_util.h"
15 #include "base/logging.h"
16 #include "base/path_service.h"
17 #include "build/build_config.h"
18 #include "media/base/djb2.h"
19 #include "media/base/simd/convert_rgb_to_yuv.h"
20 #include "media/base/simd/convert_yuv_to_rgb.h"
21 #include "media/base/simd/filter_yuv.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "ui/gfx/geometry/rect.h"
24
25 // Size of raw image.
26 static const int kSourceWidth = 640;
27 static const int kSourceHeight = 360;
28 static const int kSourceYSize = kSourceWidth * kSourceHeight;
29 static const int kSourceUOffset = kSourceYSize;
30 static const int kSourceVOffset = kSourceYSize * 5 / 4;
31 static const int kScaledWidth = 1024;
32 static const int kScaledHeight = 768;
33 static const int kDownScaledWidth = 512;
34 static const int kDownScaledHeight = 320;
35 static const int kBpp = 4;
36
37 // Surface sizes for various test files.
38 static const int kYUV12Size = kSourceYSize * 12 / 8;
39 static const int kYUV16Size = kSourceYSize * 16 / 8;
40 static const int kRGBSize = kSourceYSize * kBpp;
41 static const int kRGBSizeScaled = kScaledWidth * kScaledHeight * kBpp;
42 static const int kRGB24Size = kSourceYSize * 3;
43 static const int kRGBSizeConverted = kSourceYSize * kBpp;
44
45 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) && \
46 !defined(OS_ANDROID)
47 static const int kSourceAOffset = kSourceYSize * 12 / 8;
48 static const int kYUVA12Size = kSourceYSize * 20 / 8;
49 #endif
50
51 // Helper for reading test data into a std::unique_ptr<uint8_t[]>.
52 static void ReadData(const base::FilePath::CharType* filename,
53 int expected_size,
54 std::unique_ptr<uint8_t[]>* data) {
55 data->reset(new uint8_t[expected_size]);
56
57 base::FilePath path;
58 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path));
59 path = path.Append(FILE_PATH_LITERAL("media"))
60 .Append(FILE_PATH_LITERAL("test"))
61 .Append(FILE_PATH_LITERAL("data"))
62 .Append(filename);
63
64 // Verify file size is correct.
65 int64_t actual_size = 0;
66 base::GetFileSize(path, &actual_size);
67 CHECK_EQ(actual_size, expected_size);
68
69 // Verify bytes read are correct.
70 int bytes_read = base::ReadFile(
71 path, reinterpret_cast<char*>(data->get()), expected_size);
72 CHECK_EQ(bytes_read, expected_size);
73 }
74
75 static void ReadYV12Data(std::unique_ptr<uint8_t[]>* data) {
76 ReadData(FILE_PATH_LITERAL("bali_640x360_P420.yuv"), kYUV12Size, data);
77 }
78
79 static void ReadYV16Data(std::unique_ptr<uint8_t[]>* data) {
80 ReadData(FILE_PATH_LITERAL("bali_640x360_P422.yuv"), kYUV16Size, data);
81 }
82
83 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY) && \
84 !defined(OS_ANDROID)
85 static void ReadYV12AData(std::unique_ptr<uint8_t[]>* data) {
86 ReadData(FILE_PATH_LITERAL("bali_640x360_P420_alpha.yuv"), kYUVA12Size, data);
87 }
88 #endif
89
90 static void ReadRGB24Data(std::unique_ptr<uint8_t[]>* data) {
91 ReadData(FILE_PATH_LITERAL("bali_640x360_RGB24.rgb"), kRGB24Size, data);
92 }
93
94 #if defined(OS_ANDROID)
95 // Helper for swapping red and blue channels of RGBA or BGRA.
96 static void SwapRedAndBlueChannels(unsigned char* pixels, size_t buffer_size) {
97 for (size_t i = 0; i < buffer_size; i += 4) {
98 std::swap(pixels[i], pixels[i + 2]);
99 }
100 }
101 #endif
102
103 namespace media {
104
105 TEST(YUVConvertTest, YV12) {
106 // Allocate all surfaces.
107 std::unique_ptr<uint8_t[]> yuv_bytes;
108 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
109 std::unique_ptr<uint8_t[]> rgb_converted_bytes(
110 new uint8_t[kRGBSizeConverted]);
111
112 // Read YUV reference data from file.
113 ReadYV12Data(&yuv_bytes);
114
115 // Convert a frame of YUV to 32 bit ARGB.
116 media::ConvertYUVToRGB32(yuv_bytes.get(),
117 yuv_bytes.get() + kSourceUOffset,
118 yuv_bytes.get() + kSourceVOffset,
119 rgb_converted_bytes.get(), // RGB output
120 kSourceWidth, kSourceHeight, // Dimensions
121 kSourceWidth, // YStride
122 kSourceWidth / 2, // UVStride
123 kSourceWidth * kBpp, // RGBStride
124 media::YV12);
125
126 #if defined(OS_ANDROID)
127 SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
128 #endif
129
130 uint32_t rgb_hash =
131 DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, kDJB2HashSeed);
132 EXPECT_EQ(2413171226u, rgb_hash);
133 }
134
135 TEST(YUVConvertTest, YV16) {
136 // Allocate all surfaces.
137 std::unique_ptr<uint8_t[]> yuv_bytes;
138 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
139 std::unique_ptr<uint8_t[]> rgb_converted_bytes(
140 new uint8_t[kRGBSizeConverted]);
141
142 // Read YUV reference data from file.
143 ReadYV16Data(&yuv_bytes);
144
145 // Convert a frame of YUV to 32 bit ARGB.
146 media::ConvertYUVToRGB32(yuv_bytes.get(), // Y
147 yuv_bytes.get() + kSourceUOffset, // U
148 yuv_bytes.get() + kSourceYSize * 3 / 2, // V
149 rgb_converted_bytes.get(), // RGB output
150 kSourceWidth, kSourceHeight, // Dimensions
151 kSourceWidth, // YStride
152 kSourceWidth / 2, // UVStride
153 kSourceWidth * kBpp, // RGBStride
154 media::YV16);
155
156 #if defined(OS_ANDROID)
157 SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
158 #endif
159
160 uint32_t rgb_hash =
161 DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, kDJB2HashSeed);
162 EXPECT_EQ(4222342047u, rgb_hash);
163 }
164
165 struct YUVScaleTestData {
166 YUVScaleTestData(media::YUVType y, media::ScaleFilter s, uint32_t r)
167 : yuv_type(y), scale_filter(s), rgb_hash(r) {}
168
169 media::YUVType yuv_type;
170 media::ScaleFilter scale_filter;
171 uint32_t rgb_hash;
172 };
173
174 class YUVScaleTest : public ::testing::TestWithParam<YUVScaleTestData> {
175 public:
176 YUVScaleTest() {
177 switch (GetParam().yuv_type) {
178 case media::YV12:
179 case media::YV12J:
180 case media::YV12HD:
181 ReadYV12Data(&yuv_bytes_);
182 break;
183 case media::YV16:
184 ReadYV16Data(&yuv_bytes_);
185 break;
186 }
187
188 rgb_bytes_.reset(new uint8_t[kRGBSizeScaled]);
189 }
190
191 // Helpers for getting the proper Y, U and V plane offsets.
192 uint8_t* y_plane() { return yuv_bytes_.get(); }
193 uint8_t* u_plane() { return yuv_bytes_.get() + kSourceYSize; }
194 uint8_t* v_plane() {
195 switch (GetParam().yuv_type) {
196 case media::YV12:
197 case media::YV12J:
198 case media::YV12HD:
199 return yuv_bytes_.get() + kSourceVOffset;
200 case media::YV16:
201 return yuv_bytes_.get() + kSourceYSize * 3 / 2;
202 }
203 return NULL;
204 }
205
206 std::unique_ptr<uint8_t[]> yuv_bytes_;
207 std::unique_ptr<uint8_t[]> rgb_bytes_;
208 };
209
210 TEST_P(YUVScaleTest, NoScale) {
211 media::ScaleYUVToRGB32(y_plane(), // Y
212 u_plane(), // U
213 v_plane(), // V
214 rgb_bytes_.get(), // RGB output
215 kSourceWidth, kSourceHeight, // Dimensions
216 kSourceWidth, kSourceHeight, // Dimensions
217 kSourceWidth, // YStride
218 kSourceWidth / 2, // UvStride
219 kSourceWidth * kBpp, // RgbStride
220 GetParam().yuv_type,
221 media::ROTATE_0,
222 GetParam().scale_filter);
223
224 uint32_t yuv_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
225
226 media::ConvertYUVToRGB32(y_plane(), // Y
227 u_plane(), // U
228 v_plane(), // V
229 rgb_bytes_.get(), // RGB output
230 kSourceWidth, kSourceHeight, // Dimensions
231 kSourceWidth, // YStride
232 kSourceWidth / 2, // UVStride
233 kSourceWidth * kBpp, // RGBStride
234 GetParam().yuv_type);
235
236 uint32_t rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
237
238 EXPECT_EQ(yuv_hash, rgb_hash);
239 }
240
241 TEST_P(YUVScaleTest, Normal) {
242 media::ScaleYUVToRGB32(y_plane(), // Y
243 u_plane(), // U
244 v_plane(), // V
245 rgb_bytes_.get(), // RGB output
246 kSourceWidth, kSourceHeight, // Dimensions
247 kScaledWidth, kScaledHeight, // Dimensions
248 kSourceWidth, // YStride
249 kSourceWidth / 2, // UvStride
250 kScaledWidth * kBpp, // RgbStride
251 GetParam().yuv_type,
252 media::ROTATE_0,
253 GetParam().scale_filter);
254
255 #if defined(OS_ANDROID)
256 SwapRedAndBlueChannels(rgb_bytes_.get(), kRGBSizeScaled);
257 #endif
258
259 uint32_t rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSizeScaled, kDJB2HashSeed);
260 EXPECT_EQ(GetParam().rgb_hash, rgb_hash);
261 }
262
263 TEST_P(YUVScaleTest, ZeroSourceSize) {
264 media::ScaleYUVToRGB32(y_plane(), // Y
265 u_plane(), // U
266 v_plane(), // V
267 rgb_bytes_.get(), // RGB output
268 0, 0, // Dimensions
269 kScaledWidth, kScaledHeight, // Dimensions
270 kSourceWidth, // YStride
271 kSourceWidth / 2, // UvStride
272 kScaledWidth * kBpp, // RgbStride
273 GetParam().yuv_type,
274 media::ROTATE_0,
275 GetParam().scale_filter);
276
277 // Testing for out-of-bound read/writes with AddressSanitizer.
278 }
279
280 TEST_P(YUVScaleTest, ZeroDestinationSize) {
281 media::ScaleYUVToRGB32(y_plane(), // Y
282 u_plane(), // U
283 v_plane(), // V
284 rgb_bytes_.get(), // RGB output
285 kSourceWidth, kSourceHeight, // Dimensions
286 0, 0, // Dimensions
287 kSourceWidth, // YStride
288 kSourceWidth / 2, // UvStride
289 kScaledWidth * kBpp, // RgbStride
290 GetParam().yuv_type,
291 media::ROTATE_0,
292 GetParam().scale_filter);
293
294 // Testing for out-of-bound read/writes with AddressSanitizer.
295 }
296
297 TEST_P(YUVScaleTest, OddWidthAndHeightNotCrash) {
298 media::ScaleYUVToRGB32(y_plane(), // Y
299 u_plane(), // U
300 v_plane(), // V
301 rgb_bytes_.get(), // RGB output
302 kSourceWidth, kSourceHeight, // Dimensions
303 3, 3, // Dimensions
304 kSourceWidth, // YStride
305 kSourceWidth / 2, // UvStride
306 kScaledWidth * kBpp, // RgbStride
307 GetParam().yuv_type,
308 media::ROTATE_0,
309 GetParam().scale_filter);
310 }
311
312 INSTANTIATE_TEST_CASE_P(
313 YUVScaleFormats, YUVScaleTest,
314 ::testing::Values(
315 YUVScaleTestData(media::YV12, media::FILTER_NONE, 4136904952u),
316 YUVScaleTestData(media::YV16, media::FILTER_NONE, 1501777547u),
317 YUVScaleTestData(media::YV12, media::FILTER_BILINEAR, 3164274689u),
318 YUVScaleTestData(media::YV16, media::FILTER_BILINEAR, 3095878046u)));
319
320 // This tests a known worst case YUV value, and for overflow.
321 TEST(YUVConvertTest, Clamp) {
322 // Allocate all surfaces.
323 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[1]);
324 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[1]);
325 std::unique_ptr<uint8_t[]> rgb_converted_bytes(new uint8_t[1]);
326
327 // Values that failed previously in bug report.
328 unsigned char y = 255u;
329 unsigned char u = 255u;
330 unsigned char v = 19u;
331
332 // Prefill extra large destination buffer to test for overflow.
333 unsigned char rgb[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
334 unsigned char expected[8] = { 255, 255, 104, 255, 4, 5, 6, 7 };
335 // Convert a frame of YUV to 32 bit ARGB.
336 media::ConvertYUVToRGB32(&y, // Y
337 &u, // U
338 &v, // V
339 &rgb[0], // RGB output
340 1, 1, // Dimensions
341 0, // YStride
342 0, // UVStride
343 0, // RGBStride
344 media::YV12);
345
346 #if defined(OS_ANDROID)
347 SwapRedAndBlueChannels(rgb, kBpp);
348 #endif
349
350 int expected_test = memcmp(rgb, expected, sizeof(expected));
351 EXPECT_EQ(0, expected_test);
352 }
353
354 TEST(YUVConvertTest, RGB24ToYUV) {
355 // Allocate all surfaces.
356 std::unique_ptr<uint8_t[]> rgb_bytes;
357 std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
358
359 // Read RGB24 reference data from file.
360 ReadRGB24Data(&rgb_bytes);
361
362 // Convert to I420.
363 media::ConvertRGB24ToYUV(rgb_bytes.get(),
364 yuv_converted_bytes.get(),
365 yuv_converted_bytes.get() + kSourceUOffset,
366 yuv_converted_bytes.get() + kSourceVOffset,
367 kSourceWidth, kSourceHeight, // Dimensions
368 kSourceWidth * 3, // RGBStride
369 kSourceWidth, // YStride
370 kSourceWidth / 2); // UVStride
371
372 uint32_t rgb_hash =
373 DJB2Hash(yuv_converted_bytes.get(), kYUV12Size, kDJB2HashSeed);
374 EXPECT_EQ(320824432u, rgb_hash);
375 }
376
377 TEST(YUVConvertTest, RGB32ToYUV) {
378 // Allocate all surfaces.
379 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
380 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
381 std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
382 std::unique_ptr<uint8_t[]> rgb_converted_bytes(new uint8_t[kRGBSize]);
383
384 // Read YUV reference data from file.
385 base::FilePath yuv_url;
386 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
387 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
388 .Append(FILE_PATH_LITERAL("test"))
389 .Append(FILE_PATH_LITERAL("data"))
390 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
391 EXPECT_EQ(static_cast<int>(kYUV12Size),
392 base::ReadFile(yuv_url,
393 reinterpret_cast<char*>(yuv_bytes.get()),
394 static_cast<int>(kYUV12Size)));
395
396 // Convert a frame of YUV to 32 bit ARGB.
397 media::ConvertYUVToRGB32(yuv_bytes.get(),
398 yuv_bytes.get() + kSourceUOffset,
399 yuv_bytes.get() + kSourceVOffset,
400 rgb_bytes.get(), // RGB output
401 kSourceWidth, kSourceHeight, // Dimensions
402 kSourceWidth, // YStride
403 kSourceWidth / 2, // UVStride
404 kSourceWidth * kBpp, // RGBStride
405 media::YV12);
406
407 // Convert RGB32 to YV12.
408 media::ConvertRGB32ToYUV(rgb_bytes.get(),
409 yuv_converted_bytes.get(),
410 yuv_converted_bytes.get() + kSourceUOffset,
411 yuv_converted_bytes.get() + kSourceVOffset,
412 kSourceWidth, kSourceHeight, // Dimensions
413 kSourceWidth * 4, // RGBStride
414 kSourceWidth, // YStride
415 kSourceWidth / 2); // UVStride
416
417 // Convert YV12 back to RGB32.
418 media::ConvertYUVToRGB32(yuv_converted_bytes.get(),
419 yuv_converted_bytes.get() + kSourceUOffset,
420 yuv_converted_bytes.get() + kSourceVOffset,
421 rgb_converted_bytes.get(), // RGB output
422 kSourceWidth, kSourceHeight, // Dimensions
423 kSourceWidth, // YStride
424 kSourceWidth / 2, // UVStride
425 kSourceWidth * kBpp, // RGBStride
426 media::YV12);
427
428 int error = 0;
429 for (int i = 0; i < kRGBSize; ++i) {
430 int diff = rgb_converted_bytes[i] - rgb_bytes[i];
431 if (diff < 0)
432 diff = -diff;
433 error += diff;
434 }
435
436 // Make sure error is within bound.
437 DVLOG(1) << "Average error per channel: " << error / kRGBSize;
438 EXPECT_GT(5, error / kRGBSize);
439 }
440
441 TEST(YUVConvertTest, DownScaleYUVToRGB32WithRect) {
442 // Read YUV reference data from file.
443 base::FilePath yuv_url;
444 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
445 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
446 .Append(FILE_PATH_LITERAL("test"))
447 .Append(FILE_PATH_LITERAL("data"))
448 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
449 const size_t size_of_yuv = kSourceYSize * 12 / 8; // 12 bpp.
450 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[size_of_yuv]);
451 EXPECT_EQ(static_cast<int>(size_of_yuv),
452 base::ReadFile(yuv_url,
453 reinterpret_cast<char*>(yuv_bytes.get()),
454 static_cast<int>(size_of_yuv)));
455
456 // Scale the full frame of YUV to 32 bit ARGB.
457 // The API currently only supports down-scaling, so we don't test up-scaling.
458 const size_t size_of_rgb_scaled = kDownScaledWidth * kDownScaledHeight * kBpp;
459 std::unique_ptr<uint8_t[]> rgb_scaled_bytes(new uint8_t[size_of_rgb_scaled]);
460 gfx::Rect sub_rect(0, 0, kDownScaledWidth, kDownScaledHeight);
461
462 // We can't compare with the full-frame scaler because it uses slightly
463 // different sampling coordinates.
464 media::ScaleYUVToRGB32WithRect(
465 yuv_bytes.get(), // Y
466 yuv_bytes.get() + kSourceUOffset, // U
467 yuv_bytes.get() + kSourceVOffset, // V
468 rgb_scaled_bytes.get(), // Rgb output
469 kSourceWidth, kSourceHeight, // Dimensions
470 kDownScaledWidth, kDownScaledHeight, // Dimensions
471 sub_rect.x(), sub_rect.y(), // Dest rect
472 sub_rect.right(), sub_rect.bottom(), // Dest rect
473 kSourceWidth, // YStride
474 kSourceWidth / 2, // UvStride
475 kDownScaledWidth * kBpp); // RgbStride
476
477 uint32_t rgb_hash_full_rect =
478 DJB2Hash(rgb_scaled_bytes.get(), size_of_rgb_scaled, kDJB2HashSeed);
479
480 // Re-scale sub-rectangles and verify the results are the same.
481 int next_sub_rect = 0;
482 while (!sub_rect.IsEmpty()) {
483 // Scale a partial rectangle.
484 media::ScaleYUVToRGB32WithRect(
485 yuv_bytes.get(), // Y
486 yuv_bytes.get() + kSourceUOffset, // U
487 yuv_bytes.get() + kSourceVOffset, // V
488 rgb_scaled_bytes.get(), // Rgb output
489 kSourceWidth, kSourceHeight, // Dimensions
490 kDownScaledWidth, kDownScaledHeight, // Dimensions
491 sub_rect.x(), sub_rect.y(), // Dest rect
492 sub_rect.right(), sub_rect.bottom(), // Dest rect
493 kSourceWidth, // YStride
494 kSourceWidth / 2, // UvStride
495 kDownScaledWidth * kBpp); // RgbStride
496 uint32_t rgb_hash_sub_rect =
497 DJB2Hash(rgb_scaled_bytes.get(), size_of_rgb_scaled, kDJB2HashSeed);
498
499 EXPECT_EQ(rgb_hash_full_rect, rgb_hash_sub_rect);
500
501 // Now pick choose a quarter rect of this sub-rect.
502 if (next_sub_rect & 1)
503 sub_rect.set_x(sub_rect.x() + sub_rect.width() / 2);
504 if (next_sub_rect & 2)
505 sub_rect.set_y(sub_rect.y() + sub_rect.height() / 2);
506 sub_rect.set_width(sub_rect.width() / 2);
507 sub_rect.set_height(sub_rect.height() / 2);
508 next_sub_rect++;
509 }
510 }
511
512 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
513 #if !defined(OS_ANDROID)
514 TEST(YUVConvertTest, YUVAtoARGB_MMX_MatchReference) {
515 // Allocate all surfaces.
516 std::unique_ptr<uint8_t[]> yuv_bytes;
517 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
518 std::unique_ptr<uint8_t[]> rgb_converted_bytes(
519 new uint8_t[kRGBSizeConverted]);
520 std::unique_ptr<uint8_t[]> rgb_converted_bytes_ref(
521 new uint8_t[kRGBSizeConverted]);
522
523 // Read YUV reference data from file.
524 ReadYV12AData(&yuv_bytes);
525
526 // Convert a frame of YUV to 32 bit ARGB using both C and MMX versions.
527 media::ConvertYUVAToARGB_C(yuv_bytes.get(),
528 yuv_bytes.get() + kSourceUOffset,
529 yuv_bytes.get() + kSourceVOffset,
530 yuv_bytes.get() + kSourceAOffset,
531 rgb_converted_bytes_ref.get(),
532 kSourceWidth,
533 kSourceHeight,
534 kSourceWidth,
535 kSourceWidth / 2,
536 kSourceWidth,
537 kSourceWidth * kBpp,
538 media::YV12);
539 media::ConvertYUVAToARGB_MMX(yuv_bytes.get(),
540 yuv_bytes.get() + kSourceUOffset,
541 yuv_bytes.get() + kSourceVOffset,
542 yuv_bytes.get() + kSourceAOffset,
543 rgb_converted_bytes.get(),
544 kSourceWidth,
545 kSourceHeight,
546 kSourceWidth,
547 kSourceWidth / 2,
548 kSourceWidth,
549 kSourceWidth * kBpp,
550 media::YV12);
551
552 EXPECT_EQ(0,
553 memcmp(rgb_converted_bytes.get(),
554 rgb_converted_bytes_ref.get(),
555 kRGBSizeConverted));
556 }
557 #endif // !defined(OS_ANDROID)
558
559 TEST(YUVConvertTest, RGB32ToYUV_SSE2_MatchReference) {
560 base::CPU cpu;
561 if (!cpu.has_sse2()) {
562 LOG(WARNING) << "System doesn't support SSE2, test not executed.";
563 return;
564 }
565
566 // Allocate all surfaces.
567 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
568 std::unique_ptr<uint8_t[]> rgb_bytes(new uint8_t[kRGBSize]);
569 std::unique_ptr<uint8_t[]> yuv_converted_bytes(new uint8_t[kYUV12Size]);
570 std::unique_ptr<uint8_t[]> yuv_reference_bytes(new uint8_t[kYUV12Size]);
571
572 ReadYV12Data(&yuv_bytes);
573
574 // Convert a frame of YUV to 32 bit ARGB.
575 media::ConvertYUVToRGB32(
576 yuv_bytes.get(),
577 yuv_bytes.get() + kSourceUOffset,
578 yuv_bytes.get() + kSourceVOffset,
579 rgb_bytes.get(), // RGB output
580 kSourceWidth, kSourceHeight, // Dimensions
581 kSourceWidth, // YStride
582 kSourceWidth / 2, // UVStride
583 kSourceWidth * kBpp, // RGBStride
584 media::YV12);
585
586 // Convert RGB32 to YV12 with SSE2 version.
587 media::ConvertRGB32ToYUV_SSE2(
588 rgb_bytes.get(),
589 yuv_converted_bytes.get(),
590 yuv_converted_bytes.get() + kSourceUOffset,
591 yuv_converted_bytes.get() + kSourceVOffset,
592 kSourceWidth, kSourceHeight, // Dimensions
593 kSourceWidth * 4, // RGBStride
594 kSourceWidth, // YStride
595 kSourceWidth / 2); // UVStride
596
597 // Convert RGB32 to YV12 with reference version.
598 media::ConvertRGB32ToYUV_SSE2_Reference(
599 rgb_bytes.get(),
600 yuv_reference_bytes.get(),
601 yuv_reference_bytes.get() + kSourceUOffset,
602 yuv_reference_bytes.get() + kSourceVOffset,
603 kSourceWidth, kSourceHeight, // Dimensions
604 kSourceWidth * 4, // RGBStride
605 kSourceWidth, // YStride
606 kSourceWidth / 2); // UVStride
607
608 // Now convert a odd width and height, this overrides part of the buffer
609 // generated above but that is fine because the point of this test is to
610 // match the result with the reference code.
611
612 // Convert RGB32 to YV12 with SSE2 version.
613 media::ConvertRGB32ToYUV_SSE2(
614 rgb_bytes.get(),
615 yuv_converted_bytes.get(),
616 yuv_converted_bytes.get() + kSourceUOffset,
617 yuv_converted_bytes.get() + kSourceVOffset,
618 7, 7, // Dimensions
619 kSourceWidth * 4, // RGBStride
620 kSourceWidth, // YStride
621 kSourceWidth / 2); // UVStride
622
623 // Convert RGB32 to YV12 with reference version.
624 media::ConvertRGB32ToYUV_SSE2_Reference(
625 rgb_bytes.get(),
626 yuv_reference_bytes.get(),
627 yuv_reference_bytes.get() + kSourceUOffset,
628 yuv_reference_bytes.get() + kSourceVOffset,
629 7, 7, // Dimensions
630 kSourceWidth * 4, // RGBStride
631 kSourceWidth, // YStride
632 kSourceWidth / 2); // UVStride
633
634 int error = 0;
635 for (int i = 0; i < kYUV12Size; ++i) {
636 int diff = yuv_reference_bytes[i] - yuv_converted_bytes[i];
637 if (diff < 0)
638 diff = -diff;
639 error += diff;
640 }
641
642 // Make sure there's no difference from the reference.
643 EXPECT_EQ(0, error);
644 }
645
646 TEST(YUVConvertTest, ConvertYUVToRGB32Row_SSE) {
647 base::CPU cpu;
648 if (!cpu.has_sse()) {
649 LOG(WARNING) << "System not supported. Test skipped.";
650 return;
651 }
652
653 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
654 std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
655 std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
656 ReadYV12Data(&yuv_bytes);
657
658 const int kWidth = 167;
659 ConvertYUVToRGB32Row_C(yuv_bytes.get(),
660 yuv_bytes.get() + kSourceUOffset,
661 yuv_bytes.get() + kSourceVOffset,
662 rgb_bytes_reference.get(),
663 kWidth,
664 GetLookupTable(YV12));
665 ConvertYUVToRGB32Row_SSE(yuv_bytes.get(),
666 yuv_bytes.get() + kSourceUOffset,
667 yuv_bytes.get() + kSourceVOffset,
668 rgb_bytes_converted.get(),
669 kWidth,
670 GetLookupTable(YV12));
671 media::EmptyRegisterState();
672 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
673 rgb_bytes_converted.get(),
674 kWidth * kBpp));
675 }
676
677 // 64-bit release + component builds on Windows are too smart and optimizes
678 // away the function being tested.
679 #if defined(OS_WIN) && (defined(ARCH_CPU_X86) || !defined(COMPONENT_BUILD))
680 TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE) {
681 base::CPU cpu;
682 if (!cpu.has_sse()) {
683 LOG(WARNING) << "System not supported. Test skipped.";
684 return;
685 }
686
687 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
688 std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
689 std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
690 ReadYV12Data(&yuv_bytes);
691
692 const int kWidth = 167;
693 const int kSourceDx = 80000; // This value means a scale down.
694 ScaleYUVToRGB32Row_C(yuv_bytes.get(),
695 yuv_bytes.get() + kSourceUOffset,
696 yuv_bytes.get() + kSourceVOffset,
697 rgb_bytes_reference.get(),
698 kWidth,
699 kSourceDx,
700 GetLookupTable(YV12));
701 ScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
702 yuv_bytes.get() + kSourceUOffset,
703 yuv_bytes.get() + kSourceVOffset,
704 rgb_bytes_converted.get(),
705 kWidth,
706 kSourceDx,
707 GetLookupTable(YV12));
708 media::EmptyRegisterState();
709 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
710 rgb_bytes_converted.get(),
711 kWidth * kBpp));
712 }
713
714 TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_SSE) {
715 base::CPU cpu;
716 if (!cpu.has_sse()) {
717 LOG(WARNING) << "System not supported. Test skipped.";
718 return;
719 }
720
721 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
722 std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
723 std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
724 ReadYV12Data(&yuv_bytes);
725
726 const int kWidth = 167;
727 const int kSourceDx = 80000; // This value means a scale down.
728 LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
729 yuv_bytes.get() + kSourceUOffset,
730 yuv_bytes.get() + kSourceVOffset,
731 rgb_bytes_reference.get(),
732 kWidth,
733 kSourceDx,
734 GetLookupTable(YV12));
735 LinearScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
736 yuv_bytes.get() + kSourceUOffset,
737 yuv_bytes.get() + kSourceVOffset,
738 rgb_bytes_converted.get(),
739 kWidth,
740 kSourceDx,
741 GetLookupTable(YV12));
742 media::EmptyRegisterState();
743 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
744 rgb_bytes_converted.get(),
745 kWidth * kBpp));
746 }
747 #endif // defined(OS_WIN) && (ARCH_CPU_X86 || COMPONENT_BUILD)
748
749 TEST(YUVConvertTest, FilterYUVRows_C_OutOfBounds) {
750 std::unique_ptr<uint8_t[]> src(new uint8_t[16]);
751 std::unique_ptr<uint8_t[]> dst(new uint8_t[16]);
752
753 memset(src.get(), 0xff, 16);
754 memset(dst.get(), 0, 16);
755
756 media::FilterYUVRows_C(dst.get(), src.get(), src.get(), 1, 255);
757
758 EXPECT_EQ(255u, dst[0]);
759 for (int i = 1; i < 16; ++i) {
760 EXPECT_EQ(0u, dst[i]) << " not equal at " << i;
761 }
762 }
763
764 TEST(YUVConvertTest, FilterYUVRows_SSE2_OutOfBounds) {
765 base::CPU cpu;
766 if (!cpu.has_sse2()) {
767 LOG(WARNING) << "System not supported. Test skipped.";
768 return;
769 }
770
771 std::unique_ptr<uint8_t[]> src(new uint8_t[16]);
772 std::unique_ptr<uint8_t[]> dst(new uint8_t[16]);
773
774 memset(src.get(), 0xff, 16);
775 memset(dst.get(), 0, 16);
776
777 media::FilterYUVRows_SSE2(dst.get(), src.get(), src.get(), 1, 255);
778
779 EXPECT_EQ(255u, dst[0]);
780 for (int i = 1; i < 16; ++i) {
781 EXPECT_EQ(0u, dst[i]);
782 }
783 }
784
785 TEST(YUVConvertTest, FilterYUVRows_SSE2_UnalignedDestination) {
786 base::CPU cpu;
787 if (!cpu.has_sse2()) {
788 LOG(WARNING) << "System not supported. Test skipped.";
789 return;
790 }
791
792 const int kSize = 64;
793 std::unique_ptr<uint8_t[]> src(new uint8_t[kSize]);
794 std::unique_ptr<uint8_t[]> dst_sample(new uint8_t[kSize]);
795 std::unique_ptr<uint8_t[]> dst(new uint8_t[kSize]);
796
797 memset(dst_sample.get(), 0, kSize);
798 memset(dst.get(), 0, kSize);
799 for (int i = 0; i < kSize; ++i)
800 src[i] = 100 + i;
801
802 media::FilterYUVRows_C(dst_sample.get(),
803 src.get(), src.get(), 37, 128);
804
805 // Generate an unaligned output address.
806 uint8_t* dst_ptr = reinterpret_cast<uint8_t*>(
807 (reinterpret_cast<uintptr_t>(dst.get() + 16) & ~15) + 1);
808 media::FilterYUVRows_SSE2(dst_ptr, src.get(), src.get(), 37, 128);
809 media::EmptyRegisterState();
810
811 EXPECT_EQ(0, memcmp(dst_sample.get(), dst_ptr, 37));
812 }
813
814 #if defined(ARCH_CPU_X86_64)
815
816 TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE2_X64) {
817 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
818 std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
819 std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
820 ReadYV12Data(&yuv_bytes);
821
822 const int kWidth = 167;
823 const int kSourceDx = 80000; // This value means a scale down.
824 ScaleYUVToRGB32Row_C(yuv_bytes.get(),
825 yuv_bytes.get() + kSourceUOffset,
826 yuv_bytes.get() + kSourceVOffset,
827 rgb_bytes_reference.get(),
828 kWidth,
829 kSourceDx,
830 GetLookupTable(YV12));
831 ScaleYUVToRGB32Row_SSE2_X64(yuv_bytes.get(),
832 yuv_bytes.get() + kSourceUOffset,
833 yuv_bytes.get() + kSourceVOffset,
834 rgb_bytes_converted.get(),
835 kWidth,
836 kSourceDx,
837 GetLookupTable(YV12));
838 media::EmptyRegisterState();
839 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
840 rgb_bytes_converted.get(),
841 kWidth * kBpp));
842 }
843
844 TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_MMX_X64) {
845 std::unique_ptr<uint8_t[]> yuv_bytes(new uint8_t[kYUV12Size]);
846 std::unique_ptr<uint8_t[]> rgb_bytes_reference(new uint8_t[kRGBSize]);
847 std::unique_ptr<uint8_t[]> rgb_bytes_converted(new uint8_t[kRGBSize]);
848 ReadYV12Data(&yuv_bytes);
849
850 const int kWidth = 167;
851 const int kSourceDx = 80000; // This value means a scale down.
852 LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
853 yuv_bytes.get() + kSourceUOffset,
854 yuv_bytes.get() + kSourceVOffset,
855 rgb_bytes_reference.get(),
856 kWidth,
857 kSourceDx,
858 GetLookupTable(YV12));
859 LinearScaleYUVToRGB32Row_MMX_X64(yuv_bytes.get(),
860 yuv_bytes.get() + kSourceUOffset,
861 yuv_bytes.get() + kSourceVOffset,
862 rgb_bytes_converted.get(),
863 kWidth,
864 kSourceDx,
865 GetLookupTable(YV12));
866 media::EmptyRegisterState();
867 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
868 rgb_bytes_converted.get(),
869 kWidth * kBpp));
870 }
871
872 #endif // defined(ARCH_CPU_X86_64)
873
874 #endif // defined(ARCH_CPU_X86_FAMILY)
875
876 } // namespace media
OLDNEW
« no previous file with comments | « media/base/yuv_convert_perftest.cc ('k') | media/renderers/skcanvas_video_renderer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698