Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/base_paths.h" | 5 #include "base/base_paths.h" |
| 6 #include "base/file_util.h" | 6 #include "base/file_util.h" |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
| 9 #include "base/stringprintf.h" | |
| 9 #include "media/base/djb2.h" | 10 #include "media/base/djb2.h" |
| 10 #include "media/base/yuv_convert.h" | 11 #include "media/base/yuv_convert.h" |
| 11 #include "media/base/yuv_row.h" | 12 #include "media/base/yuv_row.h" |
| 12 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 13 | 14 |
| 15 namespace { | |
| 16 | |
| 17 // Reference code that converts RGB pixels to YUV pixels. | |
| 18 int ConvertRGBToY(const uint8* rgb) { | |
| 19 int y = 25 * rgb[0] + 129 * rgb[1] + 66 * rgb[2]; | |
| 20 y = ((y + 128) >> 8) + 16; | |
| 21 return std::max(0, std::min(255, y)); | |
| 22 } | |
| 23 | |
| 24 int ConvertRGBToU(const uint8* rgb, int size, bool subsampling) { | |
| 25 int u = 0; | |
| 26 if (!subsampling) { | |
| 27 u = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2]; | |
| 28 } else { | |
| 29 int u0 = 112 * rgb[0] - 74 * rgb[1] - 38 * rgb[2]; | |
| 30 int u1 = 112 * rgb[size] - 74 * rgb[size + 1] - 38 * rgb[size + 2]; | |
| 31 u = (u0 + u1 + 1) / 2; | |
| 32 } | |
| 33 u = ((u + 128) >> 8) + 128; | |
| 34 return std::max(0, std::min(255, u)); | |
| 35 } | |
| 36 | |
| 37 int ConvertRGBToV(const uint8* rgb, int size, bool subsampling) { | |
| 38 int v = 0; | |
| 39 if (!subsampling) { | |
| 40 v = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2]; | |
| 41 } else { | |
| 42 int v0 = -18 * rgb[0] - 94 * rgb[1] + 112 * rgb[2]; | |
| 43 int v1 = -18 * rgb[size] - 94 * rgb[size + 1] + 112 * rgb[size + 2]; | |
| 44 v = (v0 + v1 + 1) / 2; | |
| 45 } | |
| 46 v = ((v + 128) >> 8) + 128; | |
| 47 return std::max(0, std::min(255, v)); | |
| 48 } | |
| 49 | |
| 50 // Reference code that converts YUV pixels to RGB pixels. | |
| 51 int ConvertYUVToR(uint8 y, uint8 u, uint8 v) { | |
| 52 int r = 298 * (y - 16) + 409 * (v - 128); | |
| 53 r = (r + 128) >> 8; | |
| 54 return std::max(0, std::min(255, r)); | |
| 55 } | |
| 56 | |
| 57 int ConvertYUVToG(uint8 y, uint8 u, uint8 v) { | |
| 58 int g = 298 * (y - 16) - 100 * (u - 128) - 208 * (v - 128); | |
| 59 g = (g + 128) >> 8; | |
| 60 return std::max(0, std::min(255, g)); | |
| 61 } | |
| 62 | |
| 63 int ConvertYUVToB(uint8 y, uint8 u, uint8 v) { | |
| 64 int b = 298 * (y - 16) + 516 * (u - 128); | |
| 65 b = (b + 128) >> 8; | |
| 66 return std::max(0, std::min(255, b)); | |
| 67 } | |
| 68 | |
| 69 } // namespace | |
| 70 | |
| 14 // Size of raw image. | 71 // Size of raw image. |
| 15 static const int kSourceWidth = 640; | 72 static const int kSourceWidth = 640; |
| 16 static const int kSourceHeight = 360; | 73 static const int kSourceHeight = 360; |
| 17 static const int kSourceYSize = kSourceWidth * kSourceHeight; | 74 static const int kSourceYSize = kSourceWidth * kSourceHeight; |
| 18 static const int kScaledWidth = 1024; | 75 static const int kScaledWidth = 1024; |
| 19 static const int kScaledHeight = 768; | 76 static const int kScaledHeight = 768; |
| 20 static const int kBpp = 4; | 77 static const int kBpp = 4; |
| 21 | 78 |
| 22 // Surface sizes for various test files. | 79 // Surface sizes for various test files. |
| 23 static const int kYUV12Size = kSourceYSize * 12 / 8; | 80 static const int kYUV12Size = kSourceYSize * 12 / 8; |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 media::ConvertYUY2ToYUV(yuy_bytes.get(), | 344 media::ConvertYUY2ToYUV(yuy_bytes.get(), |
| 288 yuv_converted_bytes.get(), | 345 yuv_converted_bytes.get(), |
| 289 yuv_converted_bytes.get() + kSourceYSize, | 346 yuv_converted_bytes.get() + kSourceYSize, |
| 290 yuv_converted_bytes.get() + kSourceYSize * 5 / 4, | 347 yuv_converted_bytes.get() + kSourceYSize * 5 / 4, |
| 291 kSourceWidth, kSourceHeight); | 348 kSourceWidth, kSourceHeight); |
| 292 | 349 |
| 293 uint32 yuy_hash = DJB2Hash(yuv_converted_bytes.get(), kYUV12Size, | 350 uint32 yuy_hash = DJB2Hash(yuv_converted_bytes.get(), kYUV12Size, |
| 294 kDJB2HashSeed); | 351 kDJB2HashSeed); |
| 295 EXPECT_EQ(666823187u, yuy_hash); | 352 EXPECT_EQ(666823187u, yuy_hash); |
| 296 } | 353 } |
| 354 | |
| 355 // A side-by-side test that verifies our ASM functions that convert RGB pixels | |
| 356 // to YUV pixels can output the expected results. This test converts RGB pixels | |
| 357 // to YUV pixels with our ASM functions (which use SSE, SSE2, SSE3, and SSSE3) | |
| 358 // and compare the output YUV pixels with the ones calculated with out reference | |
| 359 // functions implemented in C++. | |
| 360 TEST(YUVConvertTest, SideBySideRGB) { | |
|
Alpha Left Google
2011/09/01 13:26:41
One more comment on these tests, since they test C
| |
| 361 // This test checks a subset of all RGB values so this test does not take so | |
| 362 // long time. | |
| 363 const int kStep = 8; | |
| 364 const int kWidth = 256 / kStep; | |
| 365 | |
| 366 #ifdef ENABLE_SUBSAMPLING | |
| 367 const bool kSubsampling = true; | |
| 368 #else | |
| 369 const bool kSubsampling = false; | |
| 370 #endif | |
| 371 | |
| 372 for (int size = 3; size <= 4; ++size) { | |
| 373 // Create the output buffers. | |
| 374 scoped_array<uint8> rgb(new uint8[kWidth * size]); | |
| 375 scoped_array<uint8> y(new uint8[kWidth]); | |
| 376 scoped_array<uint8> u(new uint8[kWidth / 2]); | |
| 377 scoped_array<uint8> v(new uint8[kWidth / 2]); | |
| 378 | |
| 379 // Choose the function that converts from RGB pixels to YUV ones. | |
| 380 void (*convert)(const uint8*, uint8*, uint8*, uint8*, | |
| 381 int, int, int, int, int) = NULL; | |
| 382 if (size == 3) | |
| 383 convert = media::ConvertRGB24ToYUV; | |
| 384 else | |
| 385 convert = media::ConvertRGB32ToYUV; | |
| 386 | |
| 387 for (int r = 0; r < kWidth; ++r) { | |
| 388 for (int g = 0; g < kWidth; ++g) { | |
| 389 | |
| 390 // Fill the input pixels. | |
| 391 for (int b = 0; b < kWidth; ++b) { | |
| 392 rgb[b * size + 0] = b * kStep; | |
| 393 rgb[b * size + 1] = g * kStep; | |
| 394 rgb[b * size + 2] = r * kStep; | |
| 395 if (size == 4) | |
| 396 rgb[b * size + 3] = 255; | |
| 397 } | |
| 398 | |
| 399 // Convert the input RGB pixels to YUV ones. | |
| 400 convert(rgb.get(), y.get(), u.get(), v.get(), kWidth, 1, kWidth * size, | |
| 401 kWidth, kWidth / 2); | |
| 402 | |
| 403 // Check the output Y pixels. | |
| 404 for (int i = 0; i < kWidth; ++i) { | |
| 405 const uint8* p = &rgb[i * size]; | |
| 406 SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); | |
| 407 EXPECT_EQ(ConvertRGBToY(p), y[i]); | |
| 408 } | |
| 409 | |
| 410 // Check the output U pixels. | |
| 411 for (int i = 0; i < kWidth / 2; ++i) { | |
| 412 const uint8* p = &rgb[i * 2 * size]; | |
| 413 SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); | |
| 414 EXPECT_EQ(ConvertRGBToU(p, size, kSubsampling), u[i]); | |
| 415 } | |
| 416 | |
| 417 // Check the output V pixels. | |
| 418 for (int i = 0; i < kWidth / 2; ++i) { | |
| 419 const uint8* p = &rgb[i * 2 * size]; | |
| 420 SCOPED_TRACE(base::StringPrintf("r=%d,g=%d,b=%d", p[2], p[1], p[0])); | |
| 421 EXPECT_EQ(ConvertRGBToV(p, size, kSubsampling), v[i]); | |
| 422 } | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 // Another side-by-side test for our ASM functions that convert YUV pixels | |
| 429 // to RGB pixels. | |
| 430 TEST(YUVConvertTest, SideBySideYUV) { | |
| 431 const int kStep = 4; | |
| 432 const int kWidth = 256 / kStep; | |
| 433 | |
| 434 // Create the output buffers. | |
| 435 scoped_array<uint8> rgb(new uint8[kWidth * 4]); | |
| 436 scoped_array<uint8> y(new uint8[kWidth]); | |
| 437 scoped_array<uint8> u(new uint8[kWidth / 2]); | |
| 438 scoped_array<uint8> v(new uint8[kWidth / 2]); | |
| 439 | |
| 440 for (int y0 = 0; y0 < kWidth; ++y0) { | |
| 441 for (int i = 0; i < kWidth; ++i) | |
| 442 y[i] = y0 * kStep; | |
| 443 | |
| 444 for (int u0 = 0; u0 < kWidth / 2; ++u0) { | |
| 445 for (int i = 0; i < kWidth / 2; ++i) | |
| 446 u[i] = u0 * kStep * 2; | |
| 447 | |
| 448 for (int v0 = 0; v0 < kWidth / 2; ++v0) | |
| 449 v[v0] = v0 * kStep * 2; | |
| 450 | |
| 451 // Convert the input YUV pixels to RGB ones. | |
| 452 media::ConvertYUVToRGB32(y.get(), u.get(), v.get(), rgb.get(), kWidth, 1, | |
| 453 kWidth, kWidth / 2, kWidth * 4, media::YV12); | |
| 454 | |
| 455 for (int i = 0; i < kWidth; ++i) { | |
| 456 SCOPED_TRACE( | |
| 457 base::StringPrintf("y=%d,u=%d,v=%d", y[i], u[i / 2], v[i / 2])); | |
| 458 EXPECT_EQ(255, rgb[i * 4 + 3]); | |
| 459 EXPECT_EQ(ConvertYUVToR(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 2]); | |
| 460 EXPECT_EQ(ConvertYUVToG(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 1]); | |
| 461 EXPECT_EQ(ConvertYUVToB(y[i], u[i / 2], v[i / 2]), rgb[i * 4 + 0]); | |
| 462 } | |
| 463 } | |
| 464 } | |
| 465 } | |
| OLD | NEW |