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
This commit is contained in:
fbarchard@google.com 2015-01-20 18:21:16 +00:00
parent d586d55a53
commit 292c2286a6
4 changed files with 118 additions and 27 deletions

View File

@ -1,6 +1,6 @@
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 1230
Version: 1231
License: BSD
License File: LICENSE

View File

@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1230
#define LIBYUV_VERSION 1231
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT

View File

@ -962,15 +962,15 @@ void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width) {
// 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 UG -25 /* (int8)round(-0.391 * 64 - 0.5) */
#define UB 127 /* min(127, round(2.018 * 64)) */
#define UG -25 /* round(-0.391 * 64) */
#define UR 0
#define VB 0
#define VG -52 /* (int8)round(-0.813 * 64 - 0.5) */
#define VR 102 /* (int8)round(1.596 * 64 + 0.5) */
#define VG -52 /* round(-0.813 * 64) */
#define VR 102 /* round(1.596 * 64) */
// Bias
#define BB (UB * 128 + VB * 128 + YG * 16)

View File

@ -113,24 +113,7 @@ TEST_F(libyuvTest, TESTNAME) { \
TESTCS(TestI420, I420ToARGB, ARGBToI420, 1, 2, benchmark_width_, 7)
TESTCS(TestI422, I422ToARGB, ARGBToI422, 0, 1, 0, 7)
TESTCS(TestJ420, J420ToARGB, ARGBToJ420, 1, 2, benchmark_width_, 3)
TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, 3)
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);
}
TESTCS(TestJ422, J422ToARGB, ARGBToJ422, 0, 1, 0, 4)
void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b,
int benchmark_width_, int benchmark_height_) {
@ -164,8 +147,52 @@ void TestYUVToRGB(int y, int u, int v, int &r, int &g, int &b,
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) {
int r0, g0, b0;
// black
TestYUVToRGBReference(16, 128, 128, r0, g0, b0);
EXPECT_EQ(0, r0);
EXPECT_EQ(0, g0);
@ -177,6 +204,7 @@ TEST_F(libyuvTest, TestYUV) {
EXPECT_EQ(0, g1);
EXPECT_EQ(0, b1);
// white
TestYUVToRGBReference(240, 128, 128, r0, g0, b0);
EXPECT_EQ(255, r0);
EXPECT_EQ(255, g0);
@ -187,12 +215,75 @@ TEST_F(libyuvTest, TestYUV) {
EXPECT_EQ(255, g1);
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) {
TestYUVToRGBReference(i, 128, 128, r0, g0, b0);
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(r0, g1, 3);
EXPECT_NEAR(r0, b1, 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(g0, g1, 3);
EXPECT_NEAR(b0, b1, 5);
EXPECT_NEAR(r0, r2, 1);
EXPECT_NEAR(g0, g2, 1);
EXPECT_NEAR(b0, b2, 3);
}
}