Commit b6f37bd8 authored by Frank Barchard's avatar Frank Barchard

Interpolate plane initial implementation.

YUV version of interpolation between two images.

R=dhrosa@google.com, harryjin@google.com
BUG=libyuv:526

Review URL: https://codereview.chromium.org/1479593002 .
parent 88552486
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 1545
Version: 1546
License: BSD
License File: LICENSE
......
......@@ -390,18 +390,39 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
uint8* dst_argb, int dst_stride_argb,
int width, int height, uint32 value);
// Interpolate between two ARGB images using specified amount of interpolation
// Interpolate between two 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.
// Caveat: This function will write up to 16 bytes beyond the end of dst_argb.
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src0
// and 255 means 1% src0 and 99% src1.
LIBYUV_API
int InterpolatePlane(const uint8* src0, int src_stride0,
const uint8* src1, int src_stride1,
uint8* dst, int dst_stride,
int width, int height, int interpolation);
// Interpolate between two ARGB images using specified amount of interpolation
// Internally calls InterpolatePlane with width * 4 (bpp).
LIBYUV_API
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);
// Interpolate between two YUV images using specified amount of interpolation
// Internally calls InterpolatePlane on each plane where the U and V planes
// are half width and half height.
LIBYUV_API
int I420Interpolate(const uint8* src0_y, int src0_stride_y,
const uint8* src0_u, int src0_stride_u,
const uint8* src0_v, int src0_stride_v,
const uint8* src1_y, int src1_stride_y,
const uint8* src1_u, int src1_stride_u,
const uint8* src1_v, int src1_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height, int interpolation);
#if defined(__pnacl__) || defined(__CLR_VER) || \
(defined(__i386__) && !defined(__SSE2__))
#define LIBYUV_DISABLE_X86
......
......@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1545
#define LIBYUV_VERSION 1546
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
......@@ -1681,37 +1681,37 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
return 0;
}
// Interpolate 2 ARGB images by specified amount (0 to 255).
// Interpolate 2 planes by specified amount (0 to 255).
LIBYUV_API
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) {
int InterpolatePlane(const uint8* src0, int src_stride0,
const uint8* src1, int src_stride1,
uint8* dst, int dst_stride,
int width, int height, int interpolation) {
int y;
void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
ptrdiff_t src_stride, int dst_width,
int source_y_fraction) = InterpolateRow_C;
if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
if (!src0 || !src1 || !dst || 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;
dst = dst + (height - 1) * dst_stride;
dst_stride = -dst_stride;
}
// Coalesce rows.
if (src_stride_argb0 == width * 4 &&
src_stride_argb1 == width * 4 &&
dst_stride_argb == width * 4) {
if (src_stride0 == width &&
src_stride1 == width &&
dst_stride == width) {
width *= height;
height = 1;
src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
src_stride0 = src_stride1 = dst_stride = 0;
}
#if defined(HAS_INTERPOLATEROW_SSE2)
if (TestCpuFlag(kCpuHasSSE2)) {
InterpolateRow = InterpolateRow_Any_SSE2;
if (IS_ALIGNED(width, 4)) {
if (IS_ALIGNED(width, 16)) {
InterpolateRow = InterpolateRow_SSE2;
}
}
......@@ -1719,7 +1719,7 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
#if defined(HAS_INTERPOLATEROW_SSSE3)
if (TestCpuFlag(kCpuHasSSSE3)) {
InterpolateRow = InterpolateRow_Any_SSSE3;
if (IS_ALIGNED(width, 4)) {
if (IS_ALIGNED(width, 16)) {
InterpolateRow = InterpolateRow_SSSE3;
}
}
......@@ -1727,7 +1727,7 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
#if defined(HAS_INTERPOLATEROW_AVX2)
if (TestCpuFlag(kCpuHasAVX2)) {
InterpolateRow = InterpolateRow_Any_AVX2;
if (IS_ALIGNED(width, 8)) {
if (IS_ALIGNED(width, 32)) {
InterpolateRow = InterpolateRow_AVX2;
}
}
......@@ -1735,27 +1735,75 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
#if defined(HAS_INTERPOLATEROW_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
InterpolateRow = InterpolateRow_Any_NEON;
if (IS_ALIGNED(width, 4)) {
if (IS_ALIGNED(width, 16)) {
InterpolateRow = InterpolateRow_NEON;
}
}
#endif
#if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
IS_ALIGNED(src_argb0, 4) && IS_ALIGNED(src_stride_argb0, 4) &&
IS_ALIGNED(src_argb1, 4) && IS_ALIGNED(src_stride_argb1, 4) &&
IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
IS_ALIGNED(src0, 4) && IS_ALIGNED(src_stride0, 4) &&
IS_ALIGNED(src1, 4) && IS_ALIGNED(src_stride1, 4) &&
IS_ALIGNED(dst, 4) && IS_ALIGNED(dst_stride, 4) &&
IS_ALIGNED(width, 4)) {
InterpolateRow = InterpolateRow_MIPS_DSPR2;
}
#endif
for (y = 0; y < height; ++y) {
InterpolateRow(dst_argb, src_argb0, src_argb1 - src_argb0,
width * 4, interpolation);
src_argb0 += src_stride_argb0;
src_argb1 += src_stride_argb1;
dst_argb += dst_stride_argb;
InterpolateRow(dst, src0, src1 - src0,
width, interpolation);
src0 += src_stride0;
src1 += src_stride1;
dst += dst_stride;
}
return 0;
}
// Interpolate 2 ARGB images by specified amount (0 to 255).
LIBYUV_API
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) {
return InterpolatePlane(src_argb0, src_stride_argb0,
src_argb1, src_stride_argb1,
dst_argb, dst_stride_argb,
width * 4, height, interpolation);
}
// Interpolate 2 YUV images by specified amount (0 to 255).
LIBYUV_API
int I420Interpolate(const uint8* src0_y, int src0_stride_y,
const uint8* src0_u, int src0_stride_u,
const uint8* src0_v, int src0_stride_v,
const uint8* src1_y, int src1_stride_y,
const uint8* src1_u, int src1_stride_u,
const uint8* src1_v, int src1_stride_v,
uint8* dst_y, int dst_stride_y,
uint8* dst_u, int dst_stride_u,
uint8* dst_v, int dst_stride_v,
int width, int height, int interpolation) {
int halfwidth = (width + 1) >> 1;
int halfheight = (height + 1) >> 1;
if (!src0_y || !src0_u || !src0_v ||
!src1_y || !src1_u || !src1_v ||
!dst_y || !dst_u || !dst_v ||
width <= 0 || height == 0) {
return -1;
}
InterpolatePlane(src0_y, src0_stride_y,
src1_y, src1_stride_y,
dst_y, dst_stride_y,
width, height, interpolation);
InterpolatePlane(src0_u, src0_stride_u,
src1_u, src1_stride_u,
dst_u, dst_stride_u,
halfwidth, halfheight, interpolation);
InterpolatePlane(src0_v, src0_stride_v,
src1_v, src1_stride_v,
dst_v, dst_stride_v,
halfwidth, halfheight, interpolation);
return 0;
}
......
......@@ -859,7 +859,7 @@ TEST_F(LibYUVPlanarTest, TestShade) {
}
}
TEST_F(LibYUVPlanarTest, TestInterpolate) {
TEST_F(LibYUVPlanarTest, TestARGBInterpolate) {
SIMD_ALIGNED(uint8 orig_pixels_0[1280][4]);
SIMD_ALIGNED(uint8 orig_pixels_1[1280][4]);
SIMD_ALIGNED(uint8 interpolate_pixels[1280][4]);
......@@ -940,6 +940,88 @@ TEST_F(LibYUVPlanarTest, TestInterpolate) {
}
}
TEST_F(LibYUVPlanarTest, TestInterpolatePlane) {
SIMD_ALIGNED(uint8 orig_pixels_0[1280]);
SIMD_ALIGNED(uint8 orig_pixels_1[1280]);
SIMD_ALIGNED(uint8 interpolate_pixels[1280]);
memset(orig_pixels_0, 0, sizeof(orig_pixels_0));
memset(orig_pixels_1, 0, sizeof(orig_pixels_1));
orig_pixels_0[0] = 16u;
orig_pixels_0[1] = 32u;
orig_pixels_0[2] = 64u;
orig_pixels_0[3] = 128u;
orig_pixels_0[4] = 0u;
orig_pixels_0[5] = 0u;
orig_pixels_0[6] = 0u;
orig_pixels_0[7] = 255u;
orig_pixels_0[8] = 0u;
orig_pixels_0[9] = 0u;
orig_pixels_0[10] = 0u;
orig_pixels_0[11] = 0u;
orig_pixels_0[12] = 0u;
orig_pixels_0[13] = 0u;
orig_pixels_0[14] = 0u;
orig_pixels_0[15] = 0u;
orig_pixels_1[0] = 0u;
orig_pixels_1[1] = 0u;
orig_pixels_1[2] = 0u;
orig_pixels_1[3] = 0u;
orig_pixels_1[4] = 0u;
orig_pixels_1[5] = 0u;
orig_pixels_1[6] = 0u;
orig_pixels_1[7] = 0u;
orig_pixels_1[8] = 0u;
orig_pixels_1[9] = 0u;
orig_pixels_1[10] = 0u;
orig_pixels_1[11] = 0u;
orig_pixels_1[12] = 255u;
orig_pixels_1[13] = 255u;
orig_pixels_1[14] = 255u;
orig_pixels_1[15] = 255u;
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 128);
EXPECT_EQ(8u, interpolate_pixels[0]);
EXPECT_EQ(16u, interpolate_pixels[1]);
EXPECT_EQ(32u, interpolate_pixels[2]);
EXPECT_EQ(64u, interpolate_pixels[3]);
EXPECT_EQ(0u, interpolate_pixels[4]);
EXPECT_EQ(0u, interpolate_pixels[5]);
EXPECT_EQ(0u, interpolate_pixels[6]);
EXPECT_NEAR(128u, interpolate_pixels[7], 1); // C = 127, SSE = 128.
EXPECT_EQ(0u, interpolate_pixels[8]);
EXPECT_EQ(0u, interpolate_pixels[9]);
EXPECT_EQ(0u, interpolate_pixels[10]);
EXPECT_EQ(0u, interpolate_pixels[11]);
EXPECT_NEAR(128u, interpolate_pixels[12], 1);
EXPECT_NEAR(128u, interpolate_pixels[13], 1);
EXPECT_NEAR(128u, interpolate_pixels[14], 1);
EXPECT_NEAR(128u, interpolate_pixels[15], 1);
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 0);
EXPECT_EQ(16u, interpolate_pixels[0]);
EXPECT_EQ(32u, interpolate_pixels[1]);
EXPECT_EQ(64u, interpolate_pixels[2]);
EXPECT_EQ(128u, interpolate_pixels[3]);
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 16, 1, 192);
EXPECT_EQ(4u, interpolate_pixels[0]);
EXPECT_EQ(8u, interpolate_pixels[1]);
EXPECT_EQ(16u,interpolate_pixels[2]);
EXPECT_EQ(32u, interpolate_pixels[3]);
for (int i = 0; i < benchmark_pixels_div1280_; ++i) {
InterpolatePlane(&orig_pixels_0[0], 0, &orig_pixels_1[0], 0,
&interpolate_pixels[0], 0, 1280, 1, 128);
}
}
#define TESTTERP(FMT_A, BPP_A, STRIDE_A, \
FMT_B, BPP_B, STRIDE_B, \
W1280, TERP, DIFF, N, NEG, OFF) \
......
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