mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2025-12-06 16:56:55 +08:00
ARGBInterpolate for blending 2 images with a fractional amount of each.
BUG=none TEST=none Review URL: https://webrtc-codereview.appspot.com/670008 git-svn-id: http://libyuv.googlecode.com/svn/trunk@300 16f28f9a-4ce2-e073-06de-1de4eb20be90
This commit is contained in:
parent
6398e1d4eb
commit
0d95d47757
@ -1,6 +1,6 @@
|
|||||||
Name: libyuv
|
Name: libyuv
|
||||||
URL: http://code.google.com/p/libyuv/
|
URL: http://code.google.com/p/libyuv/
|
||||||
Version: 299
|
Version: 300
|
||||||
License: BSD
|
License: BSD
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
|
|
||||||
|
|||||||
@ -212,6 +212,16 @@ int ARGBShade(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, uint32 value);
|
int width, int height, uint32 value);
|
||||||
|
|
||||||
|
// Interpolate between two ARGB images using specified amount of interpolation
|
||||||
|
// (0 to 255) and store to destination.
|
||||||
|
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src_argb0
|
||||||
|
// and 255 means 1% src_argb0 and 99% src_argb1.
|
||||||
|
// Internally uses ARGBScale bilinear filtering.
|
||||||
|
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
||||||
|
const uint8* src_argb1, int src_stride_argb1,
|
||||||
|
uint8* dst_argb, int dst_stride_argb,
|
||||||
|
int width, int height, int interpolation);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
} // namespace libyuv
|
} // namespace libyuv
|
||||||
|
|||||||
@ -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 299
|
#define LIBYUV_VERSION 300
|
||||||
|
|
||||||
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
|
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
|
||||||
|
|||||||
@ -1082,7 +1082,7 @@ int ARGBBlur(const uint8* src_argb, int src_stride_argb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multiply ARGB image by ARGB value.
|
// Multiply ARGB image by a specified ARGB value.
|
||||||
int ARGBShade(const uint8* src_argb, int src_stride_argb,
|
int ARGBShade(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, uint32 value) {
|
int width, int height, uint32 value) {
|
||||||
@ -1112,6 +1112,63 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(YUV_DISABLE_ASM) && (defined(_M_IX86) || \
|
||||||
|
(defined(__x86_64__) || defined(__i386__)))
|
||||||
|
#define HAS_SCALEARGBFILTERROWS_SSE2
|
||||||
|
#define HAS_SCALEARGBFILTERROWS_SSSE3
|
||||||
|
#endif
|
||||||
|
void ScaleARGBFilterRows_C(uint8* dst_ptr, const uint8* src_ptr, int src_stride,
|
||||||
|
int dst_width, int source_y_fraction);
|
||||||
|
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
|
int src_stride, int dst_width,
|
||||||
|
int source_y_fraction);
|
||||||
|
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
|
int src_stride, int dst_width,
|
||||||
|
int source_y_fraction);
|
||||||
|
|
||||||
|
// Interpolate 2 ARGB images by specified amount (0 to 255).
|
||||||
|
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
||||||
|
const uint8* src_argb1, int src_stride_argb1,
|
||||||
|
uint8* dst_argb, int dst_stride_argb,
|
||||||
|
int width, int height, int interpolation) {
|
||||||
|
if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// Negative height means invert the image.
|
||||||
|
if (height < 0) {
|
||||||
|
height = -height;
|
||||||
|
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
||||||
|
dst_stride_argb = -dst_stride_argb;
|
||||||
|
}
|
||||||
|
void (*ScaleARGBFilterRows)(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
|
int src_stride, int dst_width,
|
||||||
|
int source_y_fraction) = ScaleARGBFilterRows_C;
|
||||||
|
#if defined(HAS_SCALEARGBFILTERROWS_SSE2)
|
||||||
|
if (TestCpuFlag(kCpuHasSSE2) &&
|
||||||
|
IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
|
||||||
|
IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
|
||||||
|
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
|
||||||
|
ScaleARGBFilterRows = ScaleARGBFilterRows_SSE2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_SCALEARGBFILTERROWS_SSSE3)
|
||||||
|
if (TestCpuFlag(kCpuHasSSSE3) &&
|
||||||
|
IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
|
||||||
|
IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
|
||||||
|
IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
|
||||||
|
ScaleARGBFilterRows = ScaleARGBFilterRows_SSSE3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (int y = 0; y < height; ++y) {
|
||||||
|
ScaleARGBFilterRows(dst_argb, src_argb0, src_argb1 - src_argb0,
|
||||||
|
width, interpolation);
|
||||||
|
src_argb0 += src_stride_argb0;
|
||||||
|
src_argb1 += src_stride_argb1;
|
||||||
|
dst_argb += dst_stride_argb;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
} // namespace libyuv
|
} // namespace libyuv
|
||||||
|
|||||||
@ -184,9 +184,9 @@ static void ScaleARGBRowDownEvenInt_SSE2(const uint8* src_ptr, int src_stride,
|
|||||||
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version.
|
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version.
|
||||||
#define HAS_SCALEARGBFILTERROWS_SSE2
|
#define HAS_SCALEARGBFILTERROWS_SSE2
|
||||||
__declspec(naked) __declspec(align(16))
|
__declspec(naked) __declspec(align(16))
|
||||||
static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
|
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
int src_stride, int dst_width,
|
int src_stride, int dst_width,
|
||||||
int source_y_fraction) {
|
int source_y_fraction) {
|
||||||
__asm {
|
__asm {
|
||||||
push esi
|
push esi
|
||||||
push edi
|
push edi
|
||||||
@ -271,9 +271,9 @@ static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
|
|||||||
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version.
|
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version.
|
||||||
#define HAS_SCALEARGBFILTERROWS_SSSE3
|
#define HAS_SCALEARGBFILTERROWS_SSSE3
|
||||||
__declspec(naked) __declspec(align(16))
|
__declspec(naked) __declspec(align(16))
|
||||||
static void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
|
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
int src_stride, int dst_width,
|
int src_stride, int dst_width,
|
||||||
int source_y_fraction) {
|
int source_y_fraction) {
|
||||||
__asm {
|
__asm {
|
||||||
push esi
|
push esi
|
||||||
push edi
|
push edi
|
||||||
@ -499,9 +499,9 @@ static void ScaleARGBRowDownEvenInt_SSE2(const uint8* src_ptr, int src_stride,
|
|||||||
|
|
||||||
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version
|
// Bilinear row filtering combines 4x2 -> 4x1. SSE2 version
|
||||||
#define HAS_SCALEARGBFILTERROWS_SSE2
|
#define HAS_SCALEARGBFILTERROWS_SSE2
|
||||||
static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr,
|
void ScaleARGBFilterRows_SSE2(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
const uint8* src_ptr, int src_stride,
|
int src_stride, int dst_width,
|
||||||
int dst_width, int source_y_fraction) {
|
int source_y_fraction) {
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"sub %1,%0 \n"
|
"sub %1,%0 \n"
|
||||||
"cmp $0x0,%3 \n"
|
"cmp $0x0,%3 \n"
|
||||||
@ -570,9 +570,9 @@ static void ScaleARGBFilterRows_SSE2(uint8* dst_ptr,
|
|||||||
|
|
||||||
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version
|
// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version
|
||||||
#define HAS_SCALEARGBFILTERROWS_SSSE3
|
#define HAS_SCALEARGBFILTERROWS_SSSE3
|
||||||
static void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr,
|
void ScaleARGBFilterRows_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
const uint8* src_ptr, int src_stride,
|
int src_stride, int dst_width,
|
||||||
int dst_width, int source_y_fraction) {
|
int source_y_fraction) {
|
||||||
asm volatile (
|
asm volatile (
|
||||||
"sub %1,%0 \n"
|
"sub %1,%0 \n"
|
||||||
"shr %3 \n"
|
"shr %3 \n"
|
||||||
@ -743,9 +743,8 @@ static void ScaleARGBFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
|
|||||||
static const int kMaxInputWidth = 2560;
|
static const int kMaxInputWidth = 2560;
|
||||||
|
|
||||||
// C version 2x2 -> 2x1
|
// C version 2x2 -> 2x1
|
||||||
static void ScaleARGBFilterRows_C(uint8* dst_ptr,
|
void ScaleARGBFilterRows_C(uint8* dst_ptr, const uint8* src_ptr, int src_stride,
|
||||||
const uint8* src_ptr, int src_stride,
|
int dst_width, int source_y_fraction) {
|
||||||
int dst_width, int source_y_fraction) {
|
|
||||||
assert(dst_width > 0);
|
assert(dst_width > 0);
|
||||||
int y1_fraction = source_y_fraction;
|
int y1_fraction = source_y_fraction;
|
||||||
int y0_fraction = 256 - y1_fraction;
|
int y0_fraction = 256 - y1_fraction;
|
||||||
|
|||||||
@ -652,12 +652,10 @@ TEST_F(libyuvTest, TestShade) {
|
|||||||
SIMD_ALIGNED(uint8 orig_pixels[256][4]);
|
SIMD_ALIGNED(uint8 orig_pixels[256][4]);
|
||||||
SIMD_ALIGNED(uint8 shade_pixels[256][4]);
|
SIMD_ALIGNED(uint8 shade_pixels[256][4]);
|
||||||
|
|
||||||
// Test unattenuation clamps
|
|
||||||
orig_pixels[0][0] = 10u;
|
orig_pixels[0][0] = 10u;
|
||||||
orig_pixels[0][1] = 20u;
|
orig_pixels[0][1] = 20u;
|
||||||
orig_pixels[0][2] = 40u;
|
orig_pixels[0][2] = 40u;
|
||||||
orig_pixels[0][3] = 80u;
|
orig_pixels[0][3] = 80u;
|
||||||
// Test unattenuation transparent and opaque are unaffected
|
|
||||||
orig_pixels[1][0] = 0u;
|
orig_pixels[1][0] = 0u;
|
||||||
orig_pixels[1][1] = 0u;
|
orig_pixels[1][1] = 0u;
|
||||||
orig_pixels[1][2] = 0u;
|
orig_pixels[1][2] = 0u;
|
||||||
@ -700,4 +698,76 @@ TEST_F(libyuvTest, TestShade) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(libyuvTest, TestInterpolate) {
|
||||||
|
SIMD_ALIGNED(uint8 orig_pixels_0[256][4]);
|
||||||
|
SIMD_ALIGNED(uint8 orig_pixels_1[256][4]);
|
||||||
|
SIMD_ALIGNED(uint8 interpolate_pixels[256][4]);
|
||||||
|
|
||||||
|
orig_pixels_0[0][0] = 10u;
|
||||||
|
orig_pixels_0[0][1] = 20u;
|
||||||
|
orig_pixels_0[0][2] = 40u;
|
||||||
|
orig_pixels_0[0][3] = 80u;
|
||||||
|
orig_pixels_0[1][0] = 0u;
|
||||||
|
orig_pixels_0[1][1] = 0u;
|
||||||
|
orig_pixels_0[1][2] = 0u;
|
||||||
|
orig_pixels_0[1][3] = 255u;
|
||||||
|
orig_pixels_0[2][0] = 0u;
|
||||||
|
orig_pixels_0[2][1] = 0u;
|
||||||
|
orig_pixels_0[2][2] = 0u;
|
||||||
|
orig_pixels_0[2][3] = 0u;
|
||||||
|
orig_pixels_0[3][0] = 0u;
|
||||||
|
orig_pixels_0[3][1] = 0u;
|
||||||
|
orig_pixels_0[3][2] = 0u;
|
||||||
|
orig_pixels_0[3][3] = 0u;
|
||||||
|
|
||||||
|
orig_pixels_1[0][0] = 0u;
|
||||||
|
orig_pixels_1[0][1] = 0u;
|
||||||
|
orig_pixels_1[0][2] = 0u;
|
||||||
|
orig_pixels_1[0][3] = 0u;
|
||||||
|
orig_pixels_1[1][0] = 0u;
|
||||||
|
orig_pixels_1[1][1] = 0u;
|
||||||
|
orig_pixels_1[1][2] = 0u;
|
||||||
|
orig_pixels_1[1][3] = 0u;
|
||||||
|
orig_pixels_1[2][0] = 0u;
|
||||||
|
orig_pixels_1[2][1] = 0u;
|
||||||
|
orig_pixels_1[2][2] = 0u;
|
||||||
|
orig_pixels_1[2][3] = 0u;
|
||||||
|
orig_pixels_1[3][0] = 255u;
|
||||||
|
orig_pixels_1[3][1] = 255u;
|
||||||
|
orig_pixels_1[3][2] = 255u;
|
||||||
|
orig_pixels_1[3][3] = 255u;
|
||||||
|
|
||||||
|
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
|
||||||
|
&interpolate_pixels[0][0], 0, 4, 1, 128);
|
||||||
|
EXPECT_EQ(5u, interpolate_pixels[0][0]);
|
||||||
|
EXPECT_EQ(10u, interpolate_pixels[0][1]);
|
||||||
|
EXPECT_EQ(20u, interpolate_pixels[0][2]);
|
||||||
|
EXPECT_EQ(40u, interpolate_pixels[0][3]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[1][0]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[1][1]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[1][2]);
|
||||||
|
EXPECT_NEAR(128u, interpolate_pixels[1][3], 1); // C = 127, SSE = 128.
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[2][0]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[2][1]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[2][2]);
|
||||||
|
EXPECT_EQ(0u, interpolate_pixels[2][3]);
|
||||||
|
EXPECT_NEAR(128u, interpolate_pixels[3][0], 1);
|
||||||
|
EXPECT_NEAR(128u, interpolate_pixels[3][1], 1);
|
||||||
|
EXPECT_NEAR(128u, interpolate_pixels[3][2], 1);
|
||||||
|
EXPECT_NEAR(128u, interpolate_pixels[3][3], 1);
|
||||||
|
|
||||||
|
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
|
||||||
|
&interpolate_pixels[0][0], 0, 4, 1, 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(10u, interpolate_pixels[0][0]);
|
||||||
|
EXPECT_EQ(20u, interpolate_pixels[0][1]);
|
||||||
|
EXPECT_EQ(40u, interpolate_pixels[0][2]);
|
||||||
|
EXPECT_EQ(80u, interpolate_pixels[0][3]);
|
||||||
|
|
||||||
|
for (int i = 0; i < 1000 * 1280 * 720 / 256; ++i) {
|
||||||
|
ARGBInterpolate(&orig_pixels_0[0][0], 0, &orig_pixels_1[0][0], 0,
|
||||||
|
&interpolate_pixels[0][0], 0, 256, 1, 128);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace libyuv
|
} // namespace libyuv
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user