mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2025-12-06 16:56:55 +08:00
Unattenuate using a reciprocal
BUG=none TEST=none Review URL: https://webrtc-codereview.appspot.com/487006 git-svn-id: http://libyuv.googlecode.com/svn/trunk@241 16f28f9a-4ce2-e073-06de-1de4eb20be90
This commit is contained in:
parent
829e7ea402
commit
f86ba32b9d
@ -1,6 +1,6 @@
|
|||||||
Name: libyuv
|
Name: libyuv
|
||||||
URL: http://code.google.com/p/libyuv/
|
URL: http://code.google.com/p/libyuv/
|
||||||
Version: 240
|
Version: 241
|
||||||
License: BSD
|
License: BSD
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#ifndef INCLUDE_LIBYUV_VERSION_H_
|
#ifndef INCLUDE_LIBYUV_VERSION_H_
|
||||||
#define INCLUDE_LIBYUV_VERSION_H_
|
#define INCLUDE_LIBYUV_VERSION_H_
|
||||||
|
|
||||||
#define LIBYUV_VERSION 240
|
#define LIBYUV_VERSION 241
|
||||||
|
|
||||||
#endif // INCLUDE_LIBYUV_VERSION_H_
|
#endif // INCLUDE_LIBYUV_VERSION_H_
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,7 @@ static uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) {
|
|||||||
wloop:
|
wloop:
|
||||||
movdqu xmm1, [eax] // src[0-15]
|
movdqu xmm1, [eax] // src[0-15]
|
||||||
lea eax, [eax + 16]
|
lea eax, [eax + 16]
|
||||||
pmulld(0xc6) // pmulld xmm0,xmm6 hash *= 33 ^ 8
|
pmulld(0xc6) // pmulld xmm0,xmm6 hash *= 33 ^ 16
|
||||||
movdqa xmm5, kHashMul0
|
movdqa xmm5, kHashMul0
|
||||||
movdqa xmm2, xmm1
|
movdqa xmm2, xmm1
|
||||||
punpcklbw xmm2, xmm7 // src[0-7]
|
punpcklbw xmm2, xmm7 // src[0-7]
|
||||||
|
|||||||
@ -864,6 +864,7 @@ int ARGBRect(uint8* dst_argb, int dst_stride_argb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Multiply source RGB by alpha and store to destination.
|
// Multiply source RGB by alpha and store to destination.
|
||||||
|
// b = (b * a + 127) / 255;
|
||||||
static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
||||||
int width) {
|
int width) {
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
@ -871,17 +872,16 @@ static void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
|||||||
const uint32 g = src_argb[1];
|
const uint32 g = src_argb[1];
|
||||||
const uint32 r = src_argb[2];
|
const uint32 r = src_argb[2];
|
||||||
const uint32 a = src_argb[3];
|
const uint32 a = src_argb[3];
|
||||||
dst_argb[0] = (b * a + 128) / 255;
|
dst_argb[0] = (b * a + 127) / 255;
|
||||||
dst_argb[1] = (g * a + 128) / 255;
|
dst_argb[1] = (g * a + 127) / 255;
|
||||||
dst_argb[2] = (r * a + 128) / 255;
|
dst_argb[2] = (r * a + 127) / 255;
|
||||||
dst_argb[3] = a;
|
dst_argb[3] = a;
|
||||||
src_argb += 4;
|
src_argb += 4;
|
||||||
dst_argb += 4;
|
dst_argb += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert unattentuated ARGB values to preattenuated ARGB by multiplying RGB by
|
// Convert unattentuated ARGB values to preattenuated ARGB.
|
||||||
// by alpha.
|
|
||||||
// An unattenutated ARGB alpha blend uses the formula
|
// An unattenutated ARGB alpha blend uses the formula
|
||||||
// p = a * f + (1 - a) * b
|
// p = a * f + (1 - a) * b
|
||||||
// where
|
// where
|
||||||
@ -912,6 +912,10 @@ int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Divide source RGB by alpha and store to destination.
|
// Divide source RGB by alpha and store to destination.
|
||||||
|
// b = (b * 255 + (a / 2)) / a;
|
||||||
|
// g = (g * 255 + (a / 2)) / a;
|
||||||
|
// r = (r * 255 + (a / 2)) / a;
|
||||||
|
// Reciprocal method is off by 1 on some values. ie 125
|
||||||
static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
||||||
int width) {
|
int width) {
|
||||||
for (int i = 0; i < width; ++i) {
|
for (int i = 0; i < width; ++i) {
|
||||||
@ -920,15 +924,17 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
|||||||
uint32 r = src_argb[2];
|
uint32 r = src_argb[2];
|
||||||
const uint32 a = src_argb[3];
|
const uint32 a = src_argb[3];
|
||||||
if (a) {
|
if (a) {
|
||||||
b = (b * 255 + 127) / a;
|
const uint32 ia = (0x1000000 + (a >> 1)) / a; // 8.16 fixed point
|
||||||
|
b = (b * ia + 0x8000) >> 16;
|
||||||
|
g = (g * ia + 0x8000) >> 16;
|
||||||
|
r = (r * ia + 0x8000) >> 16;
|
||||||
|
// Clamping should not be necessary but is free in assembly.
|
||||||
if (b > 255) {
|
if (b > 255) {
|
||||||
b = 255;
|
b = 255;
|
||||||
}
|
}
|
||||||
g = (g * 255 + 127) / a;
|
|
||||||
if (g > 255) {
|
if (g > 255) {
|
||||||
g = 255;
|
g = 255;
|
||||||
}
|
}
|
||||||
r = (r * 255 + 127) / a;
|
|
||||||
if (r > 255) {
|
if (r > 255) {
|
||||||
r = 255;
|
r = 255;
|
||||||
}
|
}
|
||||||
@ -942,8 +948,7 @@ static void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert unattentuated ARGB values to preattenuated ARGB by multiplying RGB by
|
// Convert unattentuated ARGB values to preattenuated ARGB.
|
||||||
// by alpha.
|
|
||||||
int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
|
int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
|
||||||
uint8* dst_argb, int dst_stride_argb,
|
uint8* dst_argb, int dst_stride_argb,
|
||||||
int width, int height) {
|
int width, int height) {
|
||||||
|
|||||||
@ -115,4 +115,51 @@ TESTI420TO(ARGB)
|
|||||||
TESTI420TO(BGRA)
|
TESTI420TO(BGRA)
|
||||||
TESTI420TO(ABGR)
|
TESTI420TO(ABGR)
|
||||||
|
|
||||||
|
TEST_F (libyuvTest, TestAttenuate) {
|
||||||
|
uint8 orig_pixels[256][4];
|
||||||
|
uint8 atten_pixels[256][4];
|
||||||
|
uint8 unatten_pixels[256][4];
|
||||||
|
uint8 atten2_pixels[256][4];
|
||||||
|
for (int i = 0; i < 256; ++i) {
|
||||||
|
orig_pixels[i][0] = i;
|
||||||
|
orig_pixels[i][1] = i / 2;
|
||||||
|
orig_pixels[i][2] = i / 3;
|
||||||
|
orig_pixels[i][3] = i;
|
||||||
|
}
|
||||||
|
ARGBAttenuate(&orig_pixels[0][0], 0, &atten_pixels[0][0], 0, 256, 1);
|
||||||
|
ARGBUnattenuate(&atten_pixels[0][0], 0, &unatten_pixels[0][0], 0, 256, 1);
|
||||||
|
ARGBAttenuate(&unatten_pixels[0][0], 0, &atten2_pixels[0][0], 0, 256, 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; ++i) {
|
||||||
|
EXPECT_NEAR(atten_pixels[i][0], atten2_pixels[i][0], 1);
|
||||||
|
EXPECT_NEAR(atten_pixels[i][1], atten2_pixels[i][1], 1);
|
||||||
|
EXPECT_NEAR(atten_pixels[i][2], atten2_pixels[i][2], 1);
|
||||||
|
EXPECT_NEAR(atten_pixels[i][3], atten2_pixels[i][3], 1);
|
||||||
|
}
|
||||||
|
// Make sure transparent, 50% and opaque are fully accurate.
|
||||||
|
EXPECT_EQ(0, atten_pixels[0][0]);
|
||||||
|
EXPECT_EQ(0, atten_pixels[0][1]);
|
||||||
|
EXPECT_EQ(0, atten_pixels[0][2]);
|
||||||
|
EXPECT_EQ(0, atten_pixels[0][3]);
|
||||||
|
EXPECT_EQ(64, atten_pixels[128][0]);
|
||||||
|
EXPECT_EQ(32, atten_pixels[128][1]);
|
||||||
|
EXPECT_EQ(21, atten_pixels[128][2]);
|
||||||
|
EXPECT_EQ(128, atten_pixels[128][3]);
|
||||||
|
EXPECT_EQ(255, atten_pixels[255][0]);
|
||||||
|
EXPECT_EQ(127, atten_pixels[255][1]);
|
||||||
|
EXPECT_EQ(85, atten_pixels[255][2]);
|
||||||
|
EXPECT_EQ(255, atten_pixels[255][3]);
|
||||||
|
|
||||||
|
// Test unattenuation clamps
|
||||||
|
orig_pixels[0][0] = 200;
|
||||||
|
orig_pixels[0][1] = 129;
|
||||||
|
orig_pixels[0][2] = 127;
|
||||||
|
orig_pixels[0][3] = 128;
|
||||||
|
ARGBUnattenuate(&orig_pixels[0][0], 0, &unatten_pixels[0][0], 0, 1, 1);
|
||||||
|
EXPECT_EQ(255, unatten_pixels[0][0]);
|
||||||
|
EXPECT_EQ(255, unatten_pixels[0][1]);
|
||||||
|
EXPECT_EQ(254, unatten_pixels[0][2]);
|
||||||
|
EXPECT_EQ(128, unatten_pixels[0][3]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user