diff options
author | fbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 08:24:32 +0000 |
---|---|---|
committer | fbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-16 08:24:32 +0000 |
commit | 433e9a1e0ba40fca511aa903932781c703caf75b (patch) | |
tree | e3721a7732026920e9949c18795d7550d0b23a78 /media | |
parent | 39ca7de68778d0987c7308d5e6c19886c2bbcfc6 (diff) | |
download | chromium_src-433e9a1e0ba40fca511aa903932781c703caf75b.zip chromium_src-433e9a1e0ba40fca511aa903932781c703caf75b.tar.gz chromium_src-433e9a1e0ba40fca511aa903932781c703caf75b.tar.bz2 |
Filter YUV scaling at half size and below with center of pixel
BUG=19113
TEST=use playerwtl and reduce size to half and turn filtering on/off. Should look better.
Review URL: http://codereview.chromium.org/1625017
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@44760 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/yuv_convert.cc | 3 | ||||
-rw-r--r-- | media/base/yuv_convert_unittest.cc | 218 | ||||
-rw-r--r-- | media/base/yuv_row_posix.cc | 24 | ||||
-rw-r--r-- | media/base/yuv_row_win.cc | 9 |
4 files changed, 156 insertions, 98 deletions
diff --git a/media/base/yuv_convert.cc b/media/base/yuv_convert.cc index b5ddf64..569f8b8 100644 --- a/media/base/yuv_convert.cc +++ b/media/base/yuv_convert.cc @@ -240,6 +240,9 @@ void ScaleYUVToRGB32(const uint8* y_buf, for (int y = 0; y < height; ++y) { uint8* dest_pixel = rgb_buf + y * rgb_pitch; int source_y_subpixel = (y * yscale_fixed); + if (yscale_fixed >= (kFractionMax * 2)) { + source_y_subpixel += kFractionMax / 2; // For 1/2 or less, center filter. + } int source_y = source_y_subpixel >> kFractionBits; const uint8* y0_ptr = y_buf + source_y * y_pitch; diff --git a/media/base/yuv_convert_unittest.cc b/media/base/yuv_convert_unittest.cc index 8a919ad..b002840 100644 --- a/media/base/yuv_convert_unittest.cc +++ b/media/base/yuv_convert_unittest.cc @@ -10,31 +10,19 @@ #include "media/base/yuv_row.h" #include "testing/gtest/include/gtest/gtest.h" -// Reference images were created with the following steps -// ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv420p -an -// bali_1280x720_P420.yuv -// yuvhalf -yv12 -skip 24 bali_1280x720_P420.yuv bali_640x360_P420.yuv - -// ffmpeg -vframes 25 -i bali.mov -vcodec rawvideo -pix_fmt yuv422p -an -// bali_1280x720_P422.yuv -// yuvhalf -yv16 -skip 24 bali_1280x720_P422.yuv bali_640x360_P422.yuv -// Size of raw image. - // Size of raw image. static const int kSourceWidth = 640; static const int kSourceHeight = 360; +static const int kSourceYSize = kSourceWidth * kSourceHeight; static const int kScaledWidth = 1024; static const int kScaledHeight = 768; static const int kBpp = 4; // Surface sizes. -static const size_t kYUV12Size = kSourceWidth * kSourceHeight * 12 / 8; -static const size_t kYUV16Size = kSourceWidth * kSourceHeight * 16 / 8; -static const size_t kRGBSize = kSourceWidth * kSourceHeight * kBpp; -static const size_t kRGBSizeConverted = kSourceWidth * kSourceHeight * kBpp; - -// Set to 100 to time ConvertYUVToRGB32. -static const int kTestTimes = 1; +static const size_t kYUV12Size = kSourceYSize * 12 / 8; +static const size_t kYUV16Size = kSourceYSize * 16 / 8; +static const size_t kRGBSize = kSourceYSize * kBpp; +static const size_t kRGBSizeConverted = kSourceYSize * kBpp; TEST(YUVConvertTest, YV12) { // Allocate all surfaces. @@ -54,25 +42,19 @@ TEST(YUVConvertTest, YV12) { reinterpret_cast<char*>(yuv_bytes.get()), static_cast<int>(kYUV12Size))); - for (int i = 0; i < kTestTimes; ++i) { - // Convert a frame of YUV to 32 bit ARGB. - media::ConvertYUVToRGB32(yuv_bytes.get(), // Y - yuv_bytes.get() + kSourceWidth * kSourceHeight, // U - yuv_bytes.get() + kSourceWidth * kSourceHeight * 5 / 4, // V - rgb_converted_bytes.get(), // RGB output - kSourceWidth, kSourceHeight, // Dimensions - kSourceWidth, // YStride - kSourceWidth / 2, // UVStride - kSourceWidth * kBpp, // RGBStride - media::YV12); - } - - unsigned int rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, - kDJB2HashSeed); - - // To get this hash value, run once and examine the following EXPECT_EQ. - // Then plug new hash value into EXPECT_EQ statements. + // Convert a frame of YUV to 32 bit ARGB. + media::ConvertYUVToRGB32(yuv_bytes.get(), + yuv_bytes.get() + kSourceYSize, + yuv_bytes.get() + kSourceYSize * 5 / 4, + rgb_converted_bytes.get(), // RGB output + kSourceWidth, kSourceHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UVStride + kSourceWidth * kBpp, // RGBStride + media::YV12); + uint32 rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, + kDJB2HashSeed); EXPECT_EQ(2413171226u, rgb_hash); } @@ -94,25 +76,19 @@ TEST(YUVConvertTest, YV16) { reinterpret_cast<char*>(yuv_bytes.get()), static_cast<int>(kYUV16Size))); - for (int i = 0; i < kTestTimes; ++i) { - // Convert a frame of YUV to 32 bit ARGB. - media::ConvertYUVToRGB32(yuv_bytes.get(), // Y - yuv_bytes.get() + kSourceWidth * kSourceHeight, // U - yuv_bytes.get() + kSourceWidth * kSourceHeight * 3 / 2, // V - rgb_converted_bytes.get(), // RGB output - kSourceWidth, kSourceHeight, // Dimensions - kSourceWidth, // YStride - kSourceWidth / 2, // UVStride - kSourceWidth * kBpp, // RGBStride - media::YV16); - } - - unsigned int rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, - kDJB2HashSeed); - - // To get this hash value, run once and examine the following EXPECT_EQ. - // Then plug new hash value into EXPECT_EQ statements. - + // Convert a frame of YUV to 32 bit ARGB. + media::ConvertYUVToRGB32(yuv_bytes.get(), // Y + yuv_bytes.get() + kSourceYSize, // U + yuv_bytes.get() + kSourceYSize * 3 / 2, // V + rgb_converted_bytes.get(), // RGB output + kSourceWidth, kSourceHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UVStride + kSourceWidth * kBpp, // RGBStride + media::YV16); + + uint32 rgb_hash = DJB2Hash(rgb_converted_bytes.get(), kRGBSizeConverted, + kDJB2HashSeed); EXPECT_EQ(4222342047u, rgb_hash); } @@ -124,7 +100,7 @@ TEST(YUVScaleTest, YV12) { .Append(FILE_PATH_LITERAL("test")) .Append(FILE_PATH_LITERAL("data")) .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv")); - const size_t size_of_yuv = kSourceWidth * kSourceHeight * 12 / 8; // 12 bpp. + const size_t size_of_yuv = kSourceYSize * 12 / 8; // 12 bpp. scoped_array<uint8> yuv_bytes(new uint8[size_of_yuv]); EXPECT_EQ(static_cast<int>(size_of_yuv), file_util::ReadFile(yuv_url, @@ -135,28 +111,59 @@ TEST(YUVScaleTest, YV12) { const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; scoped_array<uint8> rgb_source_bytes(new uint8[size_of_rgb_scaled]); - for (int i = 0; i < kTestTimes; ++i) { - media::ScaleYUVToRGB32(yuv_bytes.get(), // Y - yuv_bytes.get() + kSourceWidth * kSourceHeight, // U - yuv_bytes.get() + kSourceWidth * kSourceHeight * 5 / 4, // V - rgb_source_bytes.get(), // Rgb output + media::ScaleYUVToRGB32(yuv_bytes.get(), // Y + yuv_bytes.get() + kSourceYSize, // U + yuv_bytes.get() + kSourceYSize * 5 / 4, // V + rgb_source_bytes.get(), // Rgb output kSourceWidth, kSourceHeight, // Dimensions - kScaledWidth, kScaledHeight, // Dimensions - kSourceWidth, // YStride - kSourceWidth / 2, // UvStride - kScaledWidth * kBpp, // RgbStride + kScaledWidth, kScaledHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UvStride + kScaledWidth * kBpp, // RgbStride media::YV12, media::ROTATE_0, media::FILTER_NONE); - } - unsigned int rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, - kDJB2HashSeed); + uint32 rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, + kDJB2HashSeed); + EXPECT_EQ(4259656254u, rgb_hash); +} + +TEST(YUVFilterScaleTest, YV12) { + // Read YUV reference data from file. + FilePath yuv_url; + EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); + yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("data")) + .Append(FILE_PATH_LITERAL("bali_640x360_P420.yuv")); + const size_t size_of_yuv = kSourceYSize * 12 / 8; // 12 bpp. + scoped_array<uint8> yuv_bytes(new uint8[size_of_yuv]); + EXPECT_EQ(static_cast<int>(size_of_yuv), + file_util::ReadFile(yuv_url, + reinterpret_cast<char*>(yuv_bytes.get()), + static_cast<int>(size_of_yuv))); - // To get this hash value, run once and examine the following EXPECT_EQ. - // Then plug new hash value into EXPECT_EQ statements. + // Scale a frame of YUV to 32 bit ARGB. + const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; + scoped_array<uint8> rgb_source_bytes(new uint8[size_of_rgb_scaled]); - EXPECT_EQ(4259656254u, rgb_hash); + media::ScaleYUVToRGB32(yuv_bytes.get(), // Y + yuv_bytes.get() + kSourceYSize, // U + yuv_bytes.get() + kSourceYSize * 5 / 4, // V + rgb_source_bytes.get(), // Rgb output + kSourceWidth, kSourceHeight, // Dimensions + kScaledWidth, kScaledHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UvStride + kScaledWidth * kBpp, // RgbStride + media::YV12, + media::ROTATE_0, + media::FILTER_BILINEAR); + + uint32 rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, + kDJB2HashSeed); + EXPECT_EQ(2086305576u, rgb_hash); } TEST(YUVScaleTest, YV16) { @@ -167,7 +174,7 @@ TEST(YUVScaleTest, YV16) { .Append(FILE_PATH_LITERAL("test")) .Append(FILE_PATH_LITERAL("data")) .Append(FILE_PATH_LITERAL("bali_640x360_P422.yuv")); - const size_t size_of_yuv = kSourceWidth * kSourceHeight * 16 / 8; // 16 bpp. + const size_t size_of_yuv = kSourceYSize * 16 / 8; // 16 bpp. scoped_array<uint8> yuv_bytes(new uint8[size_of_yuv]); EXPECT_EQ(static_cast<int>(size_of_yuv), file_util::ReadFile(yuv_url, @@ -178,28 +185,59 @@ TEST(YUVScaleTest, YV16) { const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; scoped_array<uint8> rgb_source_bytes(new uint8[size_of_rgb_scaled]); - for (int i = 0; i < kTestTimes; ++i) { - media::ScaleYUVToRGB32(yuv_bytes.get(), // Y - yuv_bytes.get() + kSourceWidth * kSourceHeight, // U - yuv_bytes.get() + kSourceWidth * kSourceHeight * 3 / 2, // V - rgb_source_bytes.get(), // Rgb output - kSourceWidth, kSourceHeight, // Dimensions - kScaledWidth, kScaledHeight, // Dimensions - kSourceWidth, // YStride - kSourceWidth / 2, // UvStride - kScaledWidth * kBpp, // RgbStride + media::ScaleYUVToRGB32(yuv_bytes.get(), // Y + yuv_bytes.get() + kSourceYSize, // U + yuv_bytes.get() + kSourceYSize * 3 / 2, // V + rgb_source_bytes.get(), // Rgb output + kSourceWidth, kSourceHeight, // Dimensions + kScaledWidth, kScaledHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UvStride + kScaledWidth * kBpp, // RgbStride media::YV16, media::ROTATE_0, media::FILTER_NONE); - } - unsigned int rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, - kDJB2HashSeed); + uint32 rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, + kDJB2HashSeed); + EXPECT_EQ(974965419u, rgb_hash); +} + +TEST(YUVFilterScaleTest, YV16) { + // Read YV16 reference data from file. + FilePath yuv_url; + EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &yuv_url)); + yuv_url = yuv_url.Append(FILE_PATH_LITERAL("media")) + .Append(FILE_PATH_LITERAL("test")) + .Append(FILE_PATH_LITERAL("data")) + .Append(FILE_PATH_LITERAL("bali_640x360_P422.yuv")); + const size_t size_of_yuv = kSourceYSize * 16 / 8; // 16 bpp. + scoped_array<uint8> yuv_bytes(new uint8[size_of_yuv]); + EXPECT_EQ(static_cast<int>(size_of_yuv), + file_util::ReadFile(yuv_url, + reinterpret_cast<char*>(yuv_bytes.get()), + static_cast<int>(size_of_yuv))); + + // Scale a frame of YUV to 32 bit ARGB. + const size_t size_of_rgb_scaled = kScaledWidth * kScaledHeight * kBpp; + scoped_array<uint8> rgb_source_bytes(new uint8[size_of_rgb_scaled]); - // To get this hash value, run once and examine the following EXPECT_EQ. - // Then plug new hash value into EXPECT_EQ statements. + media::ScaleYUVToRGB32(yuv_bytes.get(), // Y + yuv_bytes.get() + kSourceYSize, // U + yuv_bytes.get() + kSourceYSize * 3 / 2, // V + rgb_source_bytes.get(), // Rgb output + kSourceWidth, kSourceHeight, // Dimensions + kScaledWidth, kScaledHeight, // Dimensions + kSourceWidth, // YStride + kSourceWidth / 2, // UvStride + kScaledWidth * kBpp, // RgbStride + media::YV16, + media::ROTATE_0, + media::FILTER_BILINEAR); - EXPECT_EQ(974965419u, rgb_hash); + uint32 rgb_hash = DJB2Hash(rgb_source_bytes.get(), size_of_rgb_scaled, + kDJB2HashSeed); + EXPECT_EQ(3857179240u, rgb_hash); } // This tests a known worst case YUV value, and for overflow. @@ -218,9 +256,9 @@ TEST(YUVConvertTest, Clamp) { unsigned char rgb[8] = { 0, 1, 2, 3, 4, 5, 6, 7 }; unsigned char expected[8] = { 255, 255, 104, 255, 4, 5, 6, 7 }; // Convert a frame of YUV to 32 bit ARGB. - media::ConvertYUVToRGB32(&y, // Y - &u, // U - &v, // V + media::ConvertYUVToRGB32(&y, // Y + &u, // U + &v, // V &rgb[0], // RGB output 1, 1, // Dimensions 0, // YStride diff --git a/media/base/yuv_row_posix.cc b/media/base/yuv_row_posix.cc index 6bd2367..c38ac1f 100644 --- a/media/base/yuv_row_posix.cc +++ b/media/base/yuv_row_posix.cc @@ -149,9 +149,13 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, int width, int source_dx) { asm( - "xor %%r11,%%r11\n" + "xor %%r11,%%r11\n" // x = 0 "sub $0x2,%4\n" "js .lscalenext\n" + "cmp $0x20000,%6\n" // if source_dx >= 2.0 + "jl .lscalehalf\n" + "mov $0x8000,%%r11\n" // x = 0.5 for 1/2 or less +".lscalehalf:" ".lscaleloop:" "mov %%r11,%%r10\n" @@ -407,14 +411,17 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, "mov 0x24(%esp),%edx\n" "mov 0x28(%esp),%edi\n" "mov 0x30(%esp),%ebp\n" - "xor %ebx,%ebx\n" // source_width = width * source_dx + ebx "mov 0x34(%esp), %ecx\n" "imull 0x38(%esp), %ecx\n" - "addl %ebx, %ecx\n" "mov %ecx, 0x34(%esp)\n" + "mov 0x38(%esp), %ecx\n" + "xor %ebx,%ebx\n" // x = 0 + "cmp $0x20000,%ecx\n" // if source_dx >= 2.0 + "jl .lscaleend\n" + "mov $0x8000,%ebx\n" // x = 0.5 for 1/2 or less "jmp .lscaleend\n" ".lscaleloop:" @@ -675,9 +682,13 @@ void PICLinearScaleYUVToRGB32Row(const uint8* y_buf, // source_width = width * source_dx + ebx "mov 0x34(%esp), %ecx\n" "imull 0x38(%esp), %ecx\n" - "addl %ebx, %ecx\n" "mov %ecx, 0x34(%esp)\n" + "mov 0x38(%esp), %ecx\n" + "xor %ebx,%ebx\n" // x = 0 + "cmp $0x20000,%ecx\n" // if source_dx >= 2.0 + "jl .lscaleend\n" + "mov $0x8000,%ebx\n" // x = 0.5 for 1/2 or less "jmp .lscaleend\n" ".lscaleloop:" @@ -775,7 +786,7 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, &kCoefficientsRgbY[0][0]); } -#else // Use C code instead of MMX/SSE2. +#else // USE_MMX // C reference code that mimic the YUV assembly. #define packuswb(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x))) @@ -887,6 +898,9 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, int width, int source_dx) { int x = 0; + if (source_dx >= 0x20000) { + x = 32768; + } for (int i = 0; i < width; i += 2) { int y0 = y_buf[x >> 16]; int y1 = y_buf[(x >> 16) + 1]; diff --git a/media/base/yuv_row_win.cc b/media/base/yuv_row_win.cc index 1315ae4..b5049a5 100644 --- a/media/base/yuv_row_win.cc +++ b/media/base/yuv_row_win.cc @@ -353,8 +353,11 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, mov ecx, [esp + 32 + 20] // width imul ecx, [esp + 32 + 24] // source_dx mov [esp + 32 + 20], ecx // source_width = width * source_dx - xor ebx, ebx // x - + mov ecx, [esp + 32 + 24] // source_dx + xor ebx, ebx // x = 0 + cmp ecx, 0x20000 + jl lscaleend + mov ebx, 0x8000 // x = 0.5 for 1/2 or less jmp lscaleend lscaleloop: mov eax, ebx @@ -552,7 +555,7 @@ void LinearScaleYUVToRGB32Row(const uint8* y_buf, int width, int source_dx) { int x = 0; - if (source_dx >= 2) { + if (source_dx >= 0x20000) { x = 32768; } for (int i = 0; i < width; i += 2) { |