Removed unused VideoCaptureCapability parameters.
[chromium-blink-merge.git] / media / base / yuv_convert_unittest.cc
blob21a82f1ea25a588c63a287000178f4769a940a63
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.
5 #include "base/base_paths.h"
6 #include "base/cpu.h"
7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/path_service.h"
10 #include "media/base/djb2.h"
11 #include "media/base/simd/convert_rgb_to_yuv.h"
12 #include "media/base/simd/convert_yuv_to_rgb.h"
13 #include "media/base/simd/filter_yuv.h"
14 #include "media/base/yuv_convert.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "ui/gfx/rect.h"
18 // Size of raw image.
19 static const int kSourceWidth = 640;
20 static const int kSourceHeight = 360;
21 static const int kSourceYSize = kSourceWidth * kSourceHeight;
22 static const int kSourceUOffset = kSourceYSize;
23 static const int kSourceVOffset = kSourceYSize * 5 / 4;
24 static const int kScaledWidth = 1024;
25 static const int kScaledHeight = 768;
26 static const int kDownScaledWidth = 512;
27 static const int kDownScaledHeight = 320;
28 static const int kBpp = 4;
30 // Surface sizes for various test files.
31 static const int kYUV12Size = kSourceYSize * 12 / 8;
32 static const int kYUV16Size = kSourceYSize * 16 / 8;
33 static const int kYUY2Size = kSourceYSize * 16 / 8;
34 static const int kRGBSize = kSourceYSize * kBpp;
35 static const int kRGBSizeScaled = kScaledWidth * kScaledHeight * kBpp;
36 static const int kRGB24Size = kSourceYSize * 3;
37 static const int kRGBSizeConverted = kSourceYSize * kBpp;
39 // Helper for reading test data into a scoped_ptr<uint8[]>.
40 static void ReadData(const base::FilePath::CharType* filename,
41 int expected_size,
42 scoped_ptr<uint8[]>* data) {
43 data->reset(new uint8[expected_size]);
45 base::FilePath path;
46 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path));
47 path = path.Append(FILE_PATH_LITERAL("media"))
48 .Append(FILE_PATH_LITERAL("test"))
49 .Append(FILE_PATH_LITERAL("data"))
50 .Append(filename);
52 // Verify file size is correct.
53 int64 actual_size = 0;
54 file_util::GetFileSize(path, &actual_size);
55 CHECK_EQ(actual_size, expected_size);
57 // Verify bytes read are correct.
58 int bytes_read = file_util::ReadFile(
59 path, reinterpret_cast<char*>(data->get()), expected_size);
60 CHECK_EQ(bytes_read, expected_size);
63 static void ReadYV12Data(scoped_ptr<uint8[]>* data) {
64 ReadData(FILE_PATH_LITERAL("bali_640x360_P420.yuv"), kYUV12Size, data);
67 static void ReadYV16Data(scoped_ptr<uint8[]>* data) {
68 ReadData(FILE_PATH_LITERAL("bali_640x360_P422.yuv"), kYUV16Size, data);
71 static void ReadRGB24Data(scoped_ptr<uint8[]>* data) {
72 ReadData(FILE_PATH_LITERAL("bali_640x360_RGB24.rgb"), kRGB24Size, data);
75 static void ReadYUY2Data(scoped_ptr<uint8[]>* data) {
76 ReadData(FILE_PATH_LITERAL("bali_640x360_YUY2.yuv"), kYUY2Size, data);
79 #if defined(OS_ANDROID)
80 // Helper for swapping red and blue channels of RGBA or BGRA.
81 static void SwapRedAndBlueChannels(unsigned char* pixels, size_t buffer_size) {
82 for (size_t i = 0; i < buffer_size; i += 4) {
83 std::swap(pixels[i], pixels[i + 2]);
86 #endif
88 namespace media {
90 TEST(YUVConvertTest, YV12) {
91 // Allocate all surfaces.
92 scoped_ptr<uint8[]> yuv_bytes;
93 scoped_ptr<uint8[]> rgb_bytes(new uint8[kRGBSize]);
94 scoped_ptr<uint8[]> rgb_converted_bytes(new uint8[kRGBSizeConverted]);
96 // Read YUV reference data from file.
97 ReadYV12Data(&yuv_bytes);
99 // Convert a frame of YUV to 32 bit ARGB.
100 media::ConvertYUVToRGB32(yuv_bytes.get(),
101 yuv_bytes.get() + kSourceUOffset,
102 yuv_bytes.get() + kSourceVOffset,
103 rgb_converted_bytes.get(), // RGB output
104 kSourceWidth, kSourceHeight, // Dimensions
105 kSourceWidth, // YStride
106 kSourceWidth / 2, // UVStride
107 kSourceWidth * kBpp, // RGBStride
108 media::YV12);
110 #if defined(OS_ANDROID)
111 SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
112 #endif
114 uint32 rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted,
115 kDJB2HashSeed);
116 EXPECT_EQ(2413171226u, rgb_hash);
119 TEST(YUVConvertTest, YV16) {
120 // Allocate all surfaces.
121 scoped_ptr<uint8[]> yuv_bytes;
122 scoped_ptr<uint8[]> rgb_bytes(new uint8[kRGBSize]);
123 scoped_ptr<uint8[]> rgb_converted_bytes(new uint8[kRGBSizeConverted]);
125 // Read YUV reference data from file.
126 ReadYV16Data(&yuv_bytes);
128 // Convert a frame of YUV to 32 bit ARGB.
129 media::ConvertYUVToRGB32(yuv_bytes.get(), // Y
130 yuv_bytes.get() + kSourceUOffset, // U
131 yuv_bytes.get() + kSourceYSize * 3 / 2, // V
132 rgb_converted_bytes.get(), // RGB output
133 kSourceWidth, kSourceHeight, // Dimensions
134 kSourceWidth, // YStride
135 kSourceWidth / 2, // UVStride
136 kSourceWidth * kBpp, // RGBStride
137 media::YV16);
139 #if defined(OS_ANDROID)
140 SwapRedAndBlueChannels(rgb_converted_bytes.get(), kRGBSizeConverted);
141 #endif
143 uint32 rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted,
144 kDJB2HashSeed);
145 EXPECT_EQ(4222342047u, rgb_hash);
148 struct YUVScaleTestData {
149 YUVScaleTestData(media::YUVType y, media::ScaleFilter s, uint32 r)
150 : yuv_type(y),
151 scale_filter(s),
152 rgb_hash(r) {
155 media::YUVType yuv_type;
156 media::ScaleFilter scale_filter;
157 uint32 rgb_hash;
160 class YUVScaleTest : public ::testing::TestWithParam<YUVScaleTestData> {
161 public:
162 YUVScaleTest() {
163 switch (GetParam().yuv_type) {
164 case media::YV12:
165 ReadYV12Data(&yuv_bytes_);
166 break;
167 case media::YV16:
168 ReadYV16Data(&yuv_bytes_);
169 break;
172 rgb_bytes_.reset(new uint8[kRGBSizeScaled]);
175 // Helpers for getting the proper Y, U and V plane offsets.
176 uint8* y_plane() { return yuv_bytes_.get(); }
177 uint8* u_plane() { return yuv_bytes_.get() + kSourceYSize; }
178 uint8* v_plane() {
179 switch (GetParam().yuv_type) {
180 case media::YV12:
181 return yuv_bytes_.get() + kSourceVOffset;
182 case media::YV16:
183 return yuv_bytes_.get() + kSourceYSize * 3 / 2;
185 return NULL;
188 scoped_ptr<uint8[]> yuv_bytes_;
189 scoped_ptr<uint8[]> rgb_bytes_;
192 TEST_P(YUVScaleTest, NoScale) {
193 media::ScaleYUVToRGB32(y_plane(), // Y
194 u_plane(), // U
195 v_plane(), // V
196 rgb_bytes_.get(), // RGB output
197 kSourceWidth, kSourceHeight, // Dimensions
198 kSourceWidth, kSourceHeight, // Dimensions
199 kSourceWidth, // YStride
200 kSourceWidth / 2, // UvStride
201 kSourceWidth * kBpp, // RgbStride
202 GetParam().yuv_type,
203 media::ROTATE_0,
204 GetParam().scale_filter);
206 uint32 yuv_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
208 media::ConvertYUVToRGB32(y_plane(), // Y
209 u_plane(), // U
210 v_plane(), // V
211 rgb_bytes_.get(), // RGB output
212 kSourceWidth, kSourceHeight, // Dimensions
213 kSourceWidth, // YStride
214 kSourceWidth / 2, // UVStride
215 kSourceWidth * kBpp, // RGBStride
216 GetParam().yuv_type);
218 uint32 rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSize, kDJB2HashSeed);
220 EXPECT_EQ(yuv_hash, rgb_hash);
223 TEST_P(YUVScaleTest, Normal) {
224 media::ScaleYUVToRGB32(y_plane(), // Y
225 u_plane(), // U
226 v_plane(), // V
227 rgb_bytes_.get(), // RGB output
228 kSourceWidth, kSourceHeight, // Dimensions
229 kScaledWidth, kScaledHeight, // Dimensions
230 kSourceWidth, // YStride
231 kSourceWidth / 2, // UvStride
232 kScaledWidth * kBpp, // RgbStride
233 GetParam().yuv_type,
234 media::ROTATE_0,
235 GetParam().scale_filter);
237 #if defined(OS_ANDROID)
238 SwapRedAndBlueChannels(rgb_bytes_.get(), kRGBSizeScaled);
239 #endif
241 uint32 rgb_hash = DJB2Hash(rgb_bytes_.get(), kRGBSizeScaled, kDJB2HashSeed);
242 EXPECT_EQ(GetParam().rgb_hash, rgb_hash);
245 TEST_P(YUVScaleTest, ZeroSourceSize) {
246 media::ScaleYUVToRGB32(y_plane(), // Y
247 u_plane(), // U
248 v_plane(), // V
249 rgb_bytes_.get(), // RGB output
250 0, 0, // Dimensions
251 kScaledWidth, kScaledHeight, // Dimensions
252 kSourceWidth, // YStride
253 kSourceWidth / 2, // UvStride
254 kScaledWidth * kBpp, // RgbStride
255 GetParam().yuv_type,
256 media::ROTATE_0,
257 GetParam().scale_filter);
259 // Testing for out-of-bound read/writes with AddressSanitizer.
262 TEST_P(YUVScaleTest, ZeroDestinationSize) {
263 media::ScaleYUVToRGB32(y_plane(), // Y
264 u_plane(), // U
265 v_plane(), // V
266 rgb_bytes_.get(), // RGB output
267 kSourceWidth, kSourceHeight, // Dimensions
268 0, 0, // Dimensions
269 kSourceWidth, // YStride
270 kSourceWidth / 2, // UvStride
271 kScaledWidth * kBpp, // RgbStride
272 GetParam().yuv_type,
273 media::ROTATE_0,
274 GetParam().scale_filter);
276 // Testing for out-of-bound read/writes with AddressSanitizer.
279 TEST_P(YUVScaleTest, OddWidthAndHeightNotCrash) {
280 media::ScaleYUVToRGB32(y_plane(), // Y
281 u_plane(), // U
282 v_plane(), // V
283 rgb_bytes_.get(), // RGB output
284 kSourceWidth, kSourceHeight, // Dimensions
285 3, 3, // Dimensions
286 kSourceWidth, // YStride
287 kSourceWidth / 2, // UvStride
288 kScaledWidth * kBpp, // RgbStride
289 GetParam().yuv_type,
290 media::ROTATE_0,
291 GetParam().scale_filter);
294 INSTANTIATE_TEST_CASE_P(
295 YUVScaleFormats, YUVScaleTest,
296 ::testing::Values(
297 YUVScaleTestData(media::YV12, media::FILTER_NONE, 4136904952u),
298 YUVScaleTestData(media::YV16, media::FILTER_NONE, 1501777547u),
299 YUVScaleTestData(media::YV12, media::FILTER_BILINEAR, 3164274689u),
300 YUVScaleTestData(media::YV16, media::FILTER_BILINEAR, 3095878046u)));
302 // This tests a known worst case YUV value, and for overflow.
303 TEST(YUVConvertTest, Clamp) {
304 // Allocate all surfaces.
305 scoped_ptr<uint8[]> yuv_bytes(new uint8[1]);
306 scoped_ptr<uint8[]> rgb_bytes(new uint8[1]);
307 scoped_ptr<uint8[]> rgb_converted_bytes(new uint8[1]);
309 // Values that failed previously in bug report.
310 unsigned char y = 255u;
311 unsigned char u = 255u;
312 unsigned char v = 19u;
314 // Prefill extra large destination buffer to test for overflow.
315 unsigned char rgb[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
316 unsigned char expected[8] = { 255, 255, 104, 255, 4, 5, 6, 7 };
317 // Convert a frame of YUV to 32 bit ARGB.
318 media::ConvertYUVToRGB32(&y, // Y
319 &u, // U
320 &v, // V
321 &rgb[0], // RGB output
322 1, 1, // Dimensions
323 0, // YStride
324 0, // UVStride
325 0, // RGBStride
326 media::YV12);
328 #if defined(OS_ANDROID)
329 SwapRedAndBlueChannels(rgb, kBpp);
330 #endif
332 int expected_test = memcmp(rgb, expected, sizeof(expected));
333 EXPECT_EQ(0, expected_test);
336 TEST(YUVConvertTest, RGB24ToYUV) {
337 // Allocate all surfaces.
338 scoped_ptr<uint8[]> rgb_bytes;
339 scoped_ptr<uint8[]> yuv_converted_bytes(new uint8[kYUV12Size]);
341 // Read RGB24 reference data from file.
342 ReadRGB24Data(&rgb_bytes);
344 // Convert to I420.
345 media::ConvertRGB24ToYUV(rgb_bytes.get(),
346 yuv_converted_bytes.get(),
347 yuv_converted_bytes.get() + kSourceUOffset,
348 yuv_converted_bytes.get() + kSourceVOffset,
349 kSourceWidth, kSourceHeight, // Dimensions
350 kSourceWidth * 3, // RGBStride
351 kSourceWidth, // YStride
352 kSourceWidth / 2); // UVStride
354 uint32 rgb_hash = DJB2Hash(yuv_converted_bytes.get(), kYUV12Size,
355 kDJB2HashSeed);
356 EXPECT_EQ(320824432u, rgb_hash);
359 TEST(YUVConvertTest, RGB32ToYUV) {
360 // Allocate all surfaces.
361 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
362 scoped_ptr<uint8[]> rgb_bytes(new uint8[kRGBSize]);
363 scoped_ptr<uint8[]> yuv_converted_bytes(new uint8[kYUV12Size]);
364 scoped_ptr<uint8[]> rgb_converted_bytes(new uint8[kRGBSize]);
366 // Read YUV reference data from file.
367 base::FilePath yuv_url;
368 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
369 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
370 .Append(FILE_PATH_LITERAL("test"))
371 .Append(FILE_PATH_LITERAL("data"))
372 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
373 EXPECT_EQ(static_cast<int>(kYUV12Size),
374 file_util::ReadFile(yuv_url,
375 reinterpret_cast<char*>(yuv_bytes.get()),
376 static_cast<int>(kYUV12Size)));
378 // Convert a frame of YUV to 32 bit ARGB.
379 media::ConvertYUVToRGB32(yuv_bytes.get(),
380 yuv_bytes.get() + kSourceUOffset,
381 yuv_bytes.get() + kSourceVOffset,
382 rgb_bytes.get(), // RGB output
383 kSourceWidth, kSourceHeight, // Dimensions
384 kSourceWidth, // YStride
385 kSourceWidth / 2, // UVStride
386 kSourceWidth * kBpp, // RGBStride
387 media::YV12);
389 // Convert RGB32 to YV12.
390 media::ConvertRGB32ToYUV(rgb_bytes.get(),
391 yuv_converted_bytes.get(),
392 yuv_converted_bytes.get() + kSourceUOffset,
393 yuv_converted_bytes.get() + kSourceVOffset,
394 kSourceWidth, kSourceHeight, // Dimensions
395 kSourceWidth * 4, // RGBStride
396 kSourceWidth, // YStride
397 kSourceWidth / 2); // UVStride
399 // Convert YV12 back to RGB32.
400 media::ConvertYUVToRGB32(yuv_converted_bytes.get(),
401 yuv_converted_bytes.get() + kSourceUOffset,
402 yuv_converted_bytes.get() + kSourceVOffset,
403 rgb_converted_bytes.get(), // RGB output
404 kSourceWidth, kSourceHeight, // Dimensions
405 kSourceWidth, // YStride
406 kSourceWidth / 2, // UVStride
407 kSourceWidth * kBpp, // RGBStride
408 media::YV12);
410 int error = 0;
411 for (int i = 0; i < kRGBSize; ++i) {
412 int diff = rgb_converted_bytes[i] - rgb_bytes[i];
413 if (diff < 0)
414 diff = -diff;
415 error += diff;
418 // Make sure error is within bound.
419 DVLOG(1) << "Average error per channel: " << error / kRGBSize;
420 EXPECT_GT(5, error / kRGBSize);
423 TEST(YUVConvertTest, YUY2ToYUV) {
424 // Allocate all surfaces.
425 scoped_ptr<uint8[]> yuy_bytes;
426 scoped_ptr<uint8[]> yuv_converted_bytes(new uint8[kYUV12Size]);
428 // Read YUY reference data from file.
429 ReadYUY2Data(&yuy_bytes);
431 // Convert to I420.
432 media::ConvertYUY2ToYUV(yuy_bytes.get(),
433 yuv_converted_bytes.get(),
434 yuv_converted_bytes.get() + kSourceUOffset,
435 yuv_converted_bytes.get() + kSourceVOffset,
436 kSourceWidth, kSourceHeight);
438 uint32 yuy_hash = DJB2Hash(yuv_converted_bytes.get(), kYUV12Size,
439 kDJB2HashSeed);
440 EXPECT_EQ(666823187u, yuy_hash);
443 TEST(YUVConvertTest, DownScaleYUVToRGB32WithRect) {
444 // Read YUV reference data from file.
445 base::FilePath yuv_url;
446 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url));
447 yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media"))
448 .Append(FILE_PATH_LITERAL("test"))
449 .Append(FILE_PATH_LITERAL("data"))
450 .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv"));
451 const size_t size_of_yuv = kSourceYSize * 12 / 8; // 12 bpp.
452 scoped_ptr<uint8[]> yuv_bytes(new uint8[size_of_yuv]);
453 EXPECT_EQ(static_cast<int>(size_of_yuv),
454 file_util::ReadFile(yuv_url,
455 reinterpret_cast<char*>(yuv_bytes.get()),
456 static_cast<int>(size_of_yuv)));
458 // Scale the full frame of YUV to 32 bit ARGB.
459 // The API currently only supports down-scaling, so we don't test up-scaling.
460 const size_t size_of_rgb_scaled = kDownScaledWidth * kDownScaledHeight * kBpp;
461 scoped_ptr<uint8[]> rgb_scaled_bytes(new uint8[size_of_rgb_scaled]);
462 gfx::Rect sub_rect(0, 0, kDownScaledWidth, kDownScaledHeight);
464 // We can't compare with the full-frame scaler because it uses slightly
465 // different sampling coordinates.
466 media::ScaleYUVToRGB32WithRect(
467 yuv_bytes.get(), // Y
468 yuv_bytes.get() + kSourceUOffset, // U
469 yuv_bytes.get() + kSourceVOffset, // V
470 rgb_scaled_bytes.get(), // Rgb output
471 kSourceWidth, kSourceHeight, // Dimensions
472 kDownScaledWidth, kDownScaledHeight, // Dimensions
473 sub_rect.x(), sub_rect.y(), // Dest rect
474 sub_rect.right(), sub_rect.bottom(), // Dest rect
475 kSourceWidth, // YStride
476 kSourceWidth / 2, // UvStride
477 kDownScaledWidth * kBpp); // RgbStride
479 uint32 rgb_hash_full_rect = DJB2Hash(rgb_scaled_bytes.get(),
480 size_of_rgb_scaled,
481 kDJB2HashSeed);
483 // Re-scale sub-rectangles and verify the results are the same.
484 int next_sub_rect = 0;
485 while (!sub_rect.IsEmpty()) {
486 // Scale a partial rectangle.
487 media::ScaleYUVToRGB32WithRect(
488 yuv_bytes.get(), // Y
489 yuv_bytes.get() + kSourceUOffset, // U
490 yuv_bytes.get() + kSourceVOffset, // V
491 rgb_scaled_bytes.get(), // Rgb output
492 kSourceWidth, kSourceHeight, // Dimensions
493 kDownScaledWidth, kDownScaledHeight, // Dimensions
494 sub_rect.x(), sub_rect.y(), // Dest rect
495 sub_rect.right(), sub_rect.bottom(), // Dest rect
496 kSourceWidth, // YStride
497 kSourceWidth / 2, // UvStride
498 kDownScaledWidth * kBpp); // RgbStride
499 uint32 rgb_hash_sub_rect = DJB2Hash(rgb_scaled_bytes.get(),
500 size_of_rgb_scaled,
501 kDJB2HashSeed);
503 EXPECT_EQ(rgb_hash_full_rect, rgb_hash_sub_rect);
505 // Now pick choose a quarter rect of this sub-rect.
506 if (next_sub_rect & 1)
507 sub_rect.set_x(sub_rect.x() + sub_rect.width() / 2);
508 if (next_sub_rect & 2)
509 sub_rect.set_y(sub_rect.y() + sub_rect.height() / 2);
510 sub_rect.set_width(sub_rect.width() / 2);
511 sub_rect.set_height(sub_rect.height() / 2);
512 next_sub_rect++;
516 #if !defined(ARCH_CPU_ARM_FAMILY) && !defined(ARCH_CPU_MIPS_FAMILY)
517 TEST(YUVConvertTest, RGB32ToYUV_SSE2_MatchReference) {
518 base::CPU cpu;
519 if (!cpu.has_sse2()) {
520 LOG(WARNING) << "System doesn't support SSE2, test not executed.";
521 return;
524 // Allocate all surfaces.
525 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
526 scoped_ptr<uint8[]> rgb_bytes(new uint8[kRGBSize]);
527 scoped_ptr<uint8[]> yuv_converted_bytes(new uint8[kYUV12Size]);
528 scoped_ptr<uint8[]> yuv_reference_bytes(new uint8[kYUV12Size]);
530 ReadYV12Data(&yuv_bytes);
532 // Convert a frame of YUV to 32 bit ARGB.
533 media::ConvertYUVToRGB32(
534 yuv_bytes.get(),
535 yuv_bytes.get() + kSourceUOffset,
536 yuv_bytes.get() + kSourceVOffset,
537 rgb_bytes.get(), // RGB output
538 kSourceWidth, kSourceHeight, // Dimensions
539 kSourceWidth, // YStride
540 kSourceWidth / 2, // UVStride
541 kSourceWidth * kBpp, // RGBStride
542 media::YV12);
544 // Convert RGB32 to YV12 with SSE2 version.
545 media::ConvertRGB32ToYUV_SSE2(
546 rgb_bytes.get(),
547 yuv_converted_bytes.get(),
548 yuv_converted_bytes.get() + kSourceUOffset,
549 yuv_converted_bytes.get() + kSourceVOffset,
550 kSourceWidth, kSourceHeight, // Dimensions
551 kSourceWidth * 4, // RGBStride
552 kSourceWidth, // YStride
553 kSourceWidth / 2); // UVStride
555 // Convert RGB32 to YV12 with reference version.
556 media::ConvertRGB32ToYUV_SSE2_Reference(
557 rgb_bytes.get(),
558 yuv_reference_bytes.get(),
559 yuv_reference_bytes.get() + kSourceUOffset,
560 yuv_reference_bytes.get() + kSourceVOffset,
561 kSourceWidth, kSourceHeight, // Dimensions
562 kSourceWidth * 4, // RGBStride
563 kSourceWidth, // YStride
564 kSourceWidth / 2); // UVStride
566 // Now convert a odd width and height, this overrides part of the buffer
567 // generated above but that is fine because the point of this test is to
568 // match the result with the reference code.
570 // Convert RGB32 to YV12 with SSE2 version.
571 media::ConvertRGB32ToYUV_SSE2(
572 rgb_bytes.get(),
573 yuv_converted_bytes.get(),
574 yuv_converted_bytes.get() + kSourceUOffset,
575 yuv_converted_bytes.get() + kSourceVOffset,
576 7, 7, // Dimensions
577 kSourceWidth * 4, // RGBStride
578 kSourceWidth, // YStride
579 kSourceWidth / 2); // UVStride
581 // Convert RGB32 to YV12 with reference version.
582 media::ConvertRGB32ToYUV_SSE2_Reference(
583 rgb_bytes.get(),
584 yuv_reference_bytes.get(),
585 yuv_reference_bytes.get() + kSourceUOffset,
586 yuv_reference_bytes.get() + kSourceVOffset,
587 7, 7, // Dimensions
588 kSourceWidth * 4, // RGBStride
589 kSourceWidth, // YStride
590 kSourceWidth / 2); // UVStride
592 int error = 0;
593 for (int i = 0; i < kYUV12Size; ++i) {
594 int diff = yuv_reference_bytes[i] - yuv_converted_bytes[i];
595 if (diff < 0)
596 diff = -diff;
597 error += diff;
600 // Make sure there's no difference from the reference.
601 EXPECT_EQ(0, error);
604 TEST(YUVConvertTest, ConvertYUVToRGB32Row_MMX) {
605 base::CPU cpu;
606 if (!cpu.has_mmx()) {
607 LOG(WARNING) << "System not supported. Test skipped.";
608 return;
611 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
612 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
613 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
614 ReadYV12Data(&yuv_bytes);
616 const int kWidth = 167;
617 ConvertYUVToRGB32Row_C(yuv_bytes.get(),
618 yuv_bytes.get() + kSourceUOffset,
619 yuv_bytes.get() + kSourceVOffset,
620 rgb_bytes_reference.get(),
621 kWidth);
622 ConvertYUVToRGB32Row_MMX(yuv_bytes.get(),
623 yuv_bytes.get() + kSourceUOffset,
624 yuv_bytes.get() + kSourceVOffset,
625 rgb_bytes_converted.get(),
626 kWidth);
627 media::EmptyRegisterState();
628 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
629 rgb_bytes_converted.get(),
630 kWidth * kBpp));
633 TEST(YUVConvertTest, ConvertYUVToRGB32Row_SSE) {
634 base::CPU cpu;
635 if (!cpu.has_sse()) {
636 LOG(WARNING) << "System not supported. Test skipped.";
637 return;
640 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
641 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
642 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
643 ReadYV12Data(&yuv_bytes);
645 const int kWidth = 167;
646 ConvertYUVToRGB32Row_C(yuv_bytes.get(),
647 yuv_bytes.get() + kSourceUOffset,
648 yuv_bytes.get() + kSourceVOffset,
649 rgb_bytes_reference.get(),
650 kWidth);
651 ConvertYUVToRGB32Row_SSE(yuv_bytes.get(),
652 yuv_bytes.get() + kSourceUOffset,
653 yuv_bytes.get() + kSourceVOffset,
654 rgb_bytes_converted.get(),
655 kWidth);
656 media::EmptyRegisterState();
657 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
658 rgb_bytes_converted.get(),
659 kWidth * kBpp));
662 TEST(YUVConvertTest, ScaleYUVToRGB32Row_MMX) {
663 base::CPU cpu;
664 if (!cpu.has_mmx()) {
665 LOG(WARNING) << "System not supported. Test skipped.";
666 return;
669 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
670 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
671 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
672 ReadYV12Data(&yuv_bytes);
674 const int kWidth = 167;
675 const int kSourceDx = 80000; // This value means a scale down.
676 ScaleYUVToRGB32Row_C(yuv_bytes.get(),
677 yuv_bytes.get() + kSourceUOffset,
678 yuv_bytes.get() + kSourceVOffset,
679 rgb_bytes_reference.get(),
680 kWidth,
681 kSourceDx);
682 ScaleYUVToRGB32Row_MMX(yuv_bytes.get(),
683 yuv_bytes.get() + kSourceUOffset,
684 yuv_bytes.get() + kSourceVOffset,
685 rgb_bytes_converted.get(),
686 kWidth,
687 kSourceDx);
688 media::EmptyRegisterState();
689 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
690 rgb_bytes_converted.get(),
691 kWidth * kBpp));
694 TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE) {
695 base::CPU cpu;
696 if (!cpu.has_sse()) {
697 LOG(WARNING) << "System not supported. Test skipped.";
698 return;
701 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
702 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
703 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
704 ReadYV12Data(&yuv_bytes);
706 const int kWidth = 167;
707 const int kSourceDx = 80000; // This value means a scale down.
708 ScaleYUVToRGB32Row_C(yuv_bytes.get(),
709 yuv_bytes.get() + kSourceUOffset,
710 yuv_bytes.get() + kSourceVOffset,
711 rgb_bytes_reference.get(),
712 kWidth,
713 kSourceDx);
714 ScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
715 yuv_bytes.get() + kSourceUOffset,
716 yuv_bytes.get() + kSourceVOffset,
717 rgb_bytes_converted.get(),
718 kWidth,
719 kSourceDx);
720 media::EmptyRegisterState();
721 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
722 rgb_bytes_converted.get(),
723 kWidth * kBpp));
726 TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_MMX) {
727 base::CPU cpu;
728 if (!cpu.has_mmx()) {
729 LOG(WARNING) << "System not supported. Test skipped.";
730 return;
733 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
734 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
735 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
736 ReadYV12Data(&yuv_bytes);
738 const int kWidth = 167;
739 const int kSourceDx = 80000; // This value means a scale down.
740 LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
741 yuv_bytes.get() + kSourceUOffset,
742 yuv_bytes.get() + kSourceVOffset,
743 rgb_bytes_reference.get(),
744 kWidth,
745 kSourceDx);
746 LinearScaleYUVToRGB32Row_MMX(yuv_bytes.get(),
747 yuv_bytes.get() + kSourceUOffset,
748 yuv_bytes.get() + kSourceVOffset,
749 rgb_bytes_converted.get(),
750 kWidth,
751 kSourceDx);
752 media::EmptyRegisterState();
753 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
754 rgb_bytes_converted.get(),
755 kWidth * kBpp));
758 TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_SSE) {
759 base::CPU cpu;
760 if (!cpu.has_sse()) {
761 LOG(WARNING) << "System not supported. Test skipped.";
762 return;
765 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
766 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
767 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
768 ReadYV12Data(&yuv_bytes);
770 const int kWidth = 167;
771 const int kSourceDx = 80000; // This value means a scale down.
772 LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
773 yuv_bytes.get() + kSourceUOffset,
774 yuv_bytes.get() + kSourceVOffset,
775 rgb_bytes_reference.get(),
776 kWidth,
777 kSourceDx);
778 LinearScaleYUVToRGB32Row_SSE(yuv_bytes.get(),
779 yuv_bytes.get() + kSourceUOffset,
780 yuv_bytes.get() + kSourceVOffset,
781 rgb_bytes_converted.get(),
782 kWidth,
783 kSourceDx);
784 media::EmptyRegisterState();
785 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
786 rgb_bytes_converted.get(),
787 kWidth * kBpp));
790 TEST(YUVConvertTest, FilterYUVRows_C_OutOfBounds) {
791 scoped_ptr<uint8[]> src(new uint8[16]);
792 scoped_ptr<uint8[]> dst(new uint8[16]);
794 memset(src.get(), 0xff, 16);
795 memset(dst.get(), 0, 16);
797 media::FilterYUVRows_C(dst.get(), src.get(), src.get(), 1, 255);
799 EXPECT_EQ(255u, dst[0]);
800 for (int i = 1; i < 16; ++i) {
801 EXPECT_EQ(0u, dst[i]) << " not equal at " << i;
805 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
806 TEST(YUVConvertTest, FilterYUVRows_MMX_OutOfBounds) {
807 base::CPU cpu;
808 if (!cpu.has_mmx()) {
809 LOG(WARNING) << "System not supported. Test skipped.";
810 return;
813 scoped_ptr<uint8[]> src(new uint8[16]);
814 scoped_ptr<uint8[]> dst(new uint8[16]);
816 memset(src.get(), 0xff, 16);
817 memset(dst.get(), 0, 16);
819 media::FilterYUVRows_MMX(dst.get(), src.get(), src.get(), 1, 255);
820 media::EmptyRegisterState();
822 EXPECT_EQ(255u, dst[0]);
823 for (int i = 1; i < 16; ++i) {
824 EXPECT_EQ(0u, dst[i]);
827 #endif // defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
829 TEST(YUVConvertTest, FilterYUVRows_SSE2_OutOfBounds) {
830 base::CPU cpu;
831 if (!cpu.has_sse2()) {
832 LOG(WARNING) << "System not supported. Test skipped.";
833 return;
836 scoped_ptr<uint8[]> src(new uint8[16]);
837 scoped_ptr<uint8[]> dst(new uint8[16]);
839 memset(src.get(), 0xff, 16);
840 memset(dst.get(), 0, 16);
842 media::FilterYUVRows_SSE2(dst.get(), src.get(), src.get(), 1, 255);
844 EXPECT_EQ(255u, dst[0]);
845 for (int i = 1; i < 16; ++i) {
846 EXPECT_EQ(0u, dst[i]);
850 #if defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
851 TEST(YUVConvertTest, FilterYUVRows_MMX_UnalignedDestination) {
852 base::CPU cpu;
853 if (!cpu.has_mmx()) {
854 LOG(WARNING) << "System not supported. Test skipped.";
855 return;
858 const int kSize = 32;
859 scoped_ptr<uint8[]> src(new uint8[kSize]);
860 scoped_ptr<uint8[]> dst_sample(new uint8[kSize]);
861 scoped_ptr<uint8[]> dst(new uint8[kSize]);
863 memset(dst_sample.get(), 0, kSize);
864 memset(dst.get(), 0, kSize);
865 for (int i = 0; i < kSize; ++i)
866 src[i] = 100 + i;
868 media::FilterYUVRows_C(dst_sample.get(),
869 src.get(), src.get(), 17, 128);
871 // Generate an unaligned output address.
872 uint8* dst_ptr =
873 reinterpret_cast<uint8*>(
874 (reinterpret_cast<uintptr_t>(dst.get() + 8) & ~7) + 1);
875 media::FilterYUVRows_MMX(dst_ptr, src.get(), src.get(), 17, 128);
876 media::EmptyRegisterState();
878 EXPECT_EQ(0, memcmp(dst_sample.get(), dst_ptr, 17));
880 #endif // defined(MEDIA_MMX_INTRINSICS_AVAILABLE)
882 TEST(YUVConvertTest, FilterYUVRows_SSE2_UnalignedDestination) {
883 base::CPU cpu;
884 if (!cpu.has_sse2()) {
885 LOG(WARNING) << "System not supported. Test skipped.";
886 return;
889 const int kSize = 64;
890 scoped_ptr<uint8[]> src(new uint8[kSize]);
891 scoped_ptr<uint8[]> dst_sample(new uint8[kSize]);
892 scoped_ptr<uint8[]> dst(new uint8[kSize]);
894 memset(dst_sample.get(), 0, kSize);
895 memset(dst.get(), 0, kSize);
896 for (int i = 0; i < kSize; ++i)
897 src[i] = 100 + i;
899 media::FilterYUVRows_C(dst_sample.get(),
900 src.get(), src.get(), 37, 128);
902 // Generate an unaligned output address.
903 uint8* dst_ptr =
904 reinterpret_cast<uint8*>(
905 (reinterpret_cast<uintptr_t>(dst.get() + 16) & ~15) + 1);
906 media::FilterYUVRows_SSE2(dst_ptr, src.get(), src.get(), 37, 128);
907 media::EmptyRegisterState();
909 EXPECT_EQ(0, memcmp(dst_sample.get(), dst_ptr, 37));
912 #if defined(ARCH_CPU_X86_64)
914 TEST(YUVConvertTest, ScaleYUVToRGB32Row_SSE2_X64) {
915 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
916 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
917 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
918 ReadYV12Data(&yuv_bytes);
920 const int kWidth = 167;
921 const int kSourceDx = 80000; // This value means a scale down.
922 ScaleYUVToRGB32Row_C(yuv_bytes.get(),
923 yuv_bytes.get() + kSourceUOffset,
924 yuv_bytes.get() + kSourceVOffset,
925 rgb_bytes_reference.get(),
926 kWidth,
927 kSourceDx);
928 ScaleYUVToRGB32Row_SSE2_X64(yuv_bytes.get(),
929 yuv_bytes.get() + kSourceUOffset,
930 yuv_bytes.get() + kSourceVOffset,
931 rgb_bytes_converted.get(),
932 kWidth,
933 kSourceDx);
934 media::EmptyRegisterState();
935 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
936 rgb_bytes_converted.get(),
937 kWidth * kBpp));
940 TEST(YUVConvertTest, LinearScaleYUVToRGB32Row_MMX_X64) {
941 scoped_ptr<uint8[]> yuv_bytes(new uint8[kYUV12Size]);
942 scoped_ptr<uint8[]> rgb_bytes_reference(new uint8[kRGBSize]);
943 scoped_ptr<uint8[]> rgb_bytes_converted(new uint8[kRGBSize]);
944 ReadYV12Data(&yuv_bytes);
946 const int kWidth = 167;
947 const int kSourceDx = 80000; // This value means a scale down.
948 LinearScaleYUVToRGB32Row_C(yuv_bytes.get(),
949 yuv_bytes.get() + kSourceUOffset,
950 yuv_bytes.get() + kSourceVOffset,
951 rgb_bytes_reference.get(),
952 kWidth,
953 kSourceDx);
954 LinearScaleYUVToRGB32Row_MMX_X64(yuv_bytes.get(),
955 yuv_bytes.get() + kSourceUOffset,
956 yuv_bytes.get() + kSourceVOffset,
957 rgb_bytes_converted.get(),
958 kWidth,
959 kSourceDx);
960 media::EmptyRegisterState();
961 EXPECT_EQ(0, memcmp(rgb_bytes_reference.get(),
962 rgb_bytes_converted.get(),
963 kWidth * kBpp));
966 #endif // defined(ARCH_CPU_X86_64)
968 #endif // defined(ARCH_CPU_X86_FAMILY)
970 } // namespace media