Commit 292c2286 authored by fbarchard@google.com's avatar fbarchard@google.com

prototype of a YUV to RGB function to achieve higher quality and performance at…

prototype of a YUV to RGB function to achieve higher quality and performance at the same time.  The chroma is made more accurate by using negative values that allow more range and then subtract the contributions from the luma contributes.  The luma is made more accurate using a multiply that duplicates the Y bits out to 16 bits and then does a 2.14 bit fixed point coefficient.  The replication is done for free as part of the multiply.
BUG=391
TESTED=TestYUV
R=harryjin@google.com

Review URL: https://webrtc-codereview.appspot.com/36819004

git-svn-id: http://libyuv.googlecode.com/svn/trunk@1232 16f28f9a-4ce2-e073-06de-1de4eb20be90
parent d586d55a
Name: libyuv Name: libyuv
URL: http://code.google.com/p/libyuv/ URL: http://code.google.com/p/libyuv/
Version: 1230 Version: 1231
License: BSD License: BSD
License File: LICENSE License File: LICENSE
......
...@@ -11,6 +11,6 @@ ...@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1230 #define LIBYUV_VERSION 1231
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
...@@ -962,15 +962,15 @@ void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width) { ...@@ -962,15 +962,15 @@ void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width) {
// C reference code that mimics the YUV assembly. // C reference code that mimics the YUV assembly.
#define YG 74 /* (int8)round(1.164 * 64 + 0.5) */ #define YG 74 /* round(1.164 * 64) */
#define UB 127 /* min(63,(int8)round(2.018 * 64)) */ #define UB 127 /* min(127, round(2.018 * 64)) */
#define UG -25 /* (int8)round(-0.391 * 64 - 0.5) */ #define UG -25 /* round(-0.391 * 64) */
#define UR 0 #define UR 0
#define VB 0 #define VB 0
#define VG -52 /* (int8)round(-0.813 * 64 - 0.5) */ #define VG -52 /* round(-0.813 * 64) */
#define VR 102 /* (int8)round(1.596 * 64 + 0.5) */ #define VR 102 /* round(1.596 * 64) */
// Bias // Bias
#define BB (UB * 128 + VB * 128 + YG * 16) #define BB (UB * 128 + VB * 128 + YG * 16)
......
...@@ -113,24 +113,7 @@ TEST_F(libyuvTest, TESTNAME) { \ ...@@ -113,24 +113,7 @@ TEST_F(libyuvTest, TESTNAME) { \
TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, 7) TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, 7)
TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, 7) TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, 7)
TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, 3) TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, 3)
TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, 3) TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, 4)
int Clamp(double f) {
int i = static_cast<int>(round(f));
if (i < 0) {
i = 0;
}
if (i > 255) {
i = 255;
}
return i;
}
void TestYUVToRGBReference(int y, int u, int v, int &r, int &g, int &b) {
r = Clamp((y - 16) * 1.164 + (v - 128) * 1.596);
g = Clamp((y - 16) * 1.164 + (u - 128) * -0.391 + (v - 128) * -0.813);
b = Clamp((y - 16) * 1.164 + (u - 128) * 2.018);
}
void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b, void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b,
int benchmark_width_, int benchmark_height_) { int benchmark_width_, int benchmark_height_) {
...@@ -164,8 +147,52 @@ void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b, ...@@ -164,8 +147,52 @@ void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b,
free_aligned_buffer_64(orig_v); free_aligned_buffer_64(orig_v);
} }
int Clamp(double f) {
int i = static_cast<int>(round(f));
if (i < 0) {
i = 0;
}
if (i > 255) {
i = 255;
}
return i;
}
void TestYUVToRGBReference(int y, int u, int v, int &r, int &g, int &b) {
r = Clamp((y - 16) * 1.164 + (v - 128) * 1.596);
g = Clamp((y - 16) * 1.164 + (u - 128) * -0.391 + (v - 128) * -0.813);
b = Clamp((y - 16) * 1.164 + (u - 128) * 2.018);
}
// C prototype code
#define YG 4901241 /* round(1.164 * 64 * 256 * 257) */
#define YGB 1192 /* round(1.164 * 64 * 16 ) */
#define UB -128 /* -min(128, round(2.018 * 64)) */
#define UG 25 /* -round(-0.391 * 64) */
#define UR 0
#define VB 0
#define VG 52 /* -round(-0.813 * 64) */
#define VR -102 /* -round(1.596 * 64) */
// Bias
#define BB (UB * 128 + VB * 128 - YGB)
#define BG (UG * 128 + VG * 128 - YGB)
#define BR (UR * 128 + VR * 128 - YGB)
void TestYUVToRGBInt(int y, int u, int v, int &r, int &g, int &b) {
uint32 y1 = (uint32)(y * YG) >> 16;
b = Clamp((int32)(y1 - (v * VB + u * UB) + BB) >> 6);
g = Clamp((int32)(y1 - (v * VG + u * UG) + BG) >> 6);
r = Clamp((int32)(y1 - (v * VR + u * UR) + BR) >> 6);
}
TEST_F(libyuvTest, TestYUV) { TEST_F(libyuvTest, TestYUV) {
int r0, g0, b0; int r0, g0, b0;
// black
TestYUVToRGBReference(16, 128, 128, r0, g0, b0); TestYUVToRGBReference(16, 128, 128, r0, g0, b0);
EXPECT_EQ(0, r0); EXPECT_EQ(0, r0);
EXPECT_EQ(0, g0); EXPECT_EQ(0, g0);
...@@ -177,6 +204,7 @@ TEST_F(libyuvTest, TestYUV) { ...@@ -177,6 +204,7 @@ TEST_F(libyuvTest, TestYUV) {
EXPECT_EQ(0, g1); EXPECT_EQ(0, g1);
EXPECT_EQ(0, b1); EXPECT_EQ(0, b1);
// white
TestYUVToRGBReference(240, 128, 128, r0, g0, b0); TestYUVToRGBReference(240, 128, 128, r0, g0, b0);
EXPECT_EQ(255, r0); EXPECT_EQ(255, r0);
EXPECT_EQ(255, g0); EXPECT_EQ(255, g0);
...@@ -187,12 +215,75 @@ TEST_F(libyuvTest, TestYUV) { ...@@ -187,12 +215,75 @@ TEST_F(libyuvTest, TestYUV) {
EXPECT_EQ(255, g1); EXPECT_EQ(255, g1);
EXPECT_EQ(255, b1); EXPECT_EQ(255, b1);
// cyan (less red)
TestYUVToRGBReference(240, 255, 0, r0, g0, b0);
EXPECT_EQ(56, r0);
EXPECT_EQ(255, g0);
EXPECT_EQ(255, b0);
TestYUVToRGB(240, 255, 0, r1, g1, b1, benchmark_width_, benchmark_height_);
EXPECT_EQ(55, r1);
EXPECT_EQ(255, g1);
EXPECT_EQ(255, b1);
// green (less red and blue)
TestYUVToRGBReference(240, 0, 0, r0, g0, b0);
EXPECT_EQ(56, r0);
EXPECT_EQ(255, g0);
EXPECT_EQ(2, b0);
TestYUVToRGB(240, 0, 0, r1, g1, b1, benchmark_width_, benchmark_height_);
EXPECT_EQ(55, r1);
EXPECT_EQ(255, g1);
EXPECT_EQ(5, b1);
int r2, g2, b2;
for (int i = 0; i < 255; ++i) { for (int i = 0; i < 255; ++i) {
TestYUVToRGBReference(i, 128, 128, r0, g0, b0); TestYUVToRGBReference(i, 128, 128, r0, g0, b0);
TestYUVToRGB(i, 128, 128, r1, g1, b1, benchmark_width_, benchmark_height_); TestYUVToRGB(i, 128, 128, r1, g1, b1, benchmark_width_, benchmark_height_);
TestYUVToRGBInt(i, 128, 128, r2, g2, b2);
EXPECT_NEAR(r0, r1, 3);
EXPECT_NEAR(g0, g1, 3);
EXPECT_NEAR(b0, b1, 3);
EXPECT_NEAR(r0, r2, 1);
EXPECT_NEAR(g0, g2, 1);
EXPECT_NEAR(b0, b2, 1);
TestYUVToRGBReference(i, 0, 0, r0, g0, b0);
TestYUVToRGB(i, 0, 0, r1, g1, b1, benchmark_width_, benchmark_height_);
TestYUVToRGBInt(i, 0, 0, r2, g2, b2);
EXPECT_NEAR(r0, r1, 3);
EXPECT_NEAR(g0, g1, 3);
EXPECT_NEAR(b0, b1, 3);
EXPECT_NEAR(r0, r2, 1);
EXPECT_NEAR(g0, g2, 1);
EXPECT_NEAR(b0, b2, 3);
TestYUVToRGBReference(i, 0, 255, r0, g0, b0);
TestYUVToRGB(i, 0, 255, r1, g1, b1, benchmark_width_, benchmark_height_);
TestYUVToRGBInt(i, 0, 255, r2, g2, b2);
EXPECT_NEAR(r0, r1, 3);
EXPECT_NEAR(g0, g1, 3);
EXPECT_NEAR(b0, b1, 3);
EXPECT_NEAR(r0, r2, 1);
EXPECT_NEAR(g0, g2, 1);
EXPECT_NEAR(b0, b2, 3);
}
for (int i = 0; i < 1000; ++i) {
int yr = random() & 255;
int ur = random() & 255;
int vr = random() & 255;
TestYUVToRGBReference(yr, ur, vr, r0, g0, b0);
TestYUVToRGB(yr, ur, vr, r1, g1, b1, benchmark_width_, benchmark_height_);
TestYUVToRGBInt(yr, ur, vr, r2, g2, b2);
EXPECT_NEAR(r0, r1, 3); EXPECT_NEAR(r0, r1, 3);
EXPECT_NEAR(r0, g1, 3); EXPECT_NEAR(g0, g1, 3);
EXPECT_NEAR(r0, b1, 3); EXPECT_NEAR(b0, b1, 5);
EXPECT_NEAR(r0, r2, 1);
EXPECT_NEAR(g0, g2, 1);
EXPECT_NEAR(b0, b2, 3);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment