summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 08:24:32 +0000
committerfbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-04-16 08:24:32 +0000
commit433e9a1e0ba40fca511aa903932781c703caf75b (patch)
treee3721a7732026920e9949c18795d7550d0b23a78 /media
parent39ca7de68778d0987c7308d5e6c19886c2bbcfc6 (diff)
downloadchromium_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.cc3
-rw-r--r--media/base/yuv_convert_unittest.cc218
-rw-r--r--media/base/yuv_row_posix.cc24
-rw-r--r--media/base/yuv_row_win.cc9
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) {