mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2025-12-07 01:06:46 +08:00
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 .
This commit is contained in:
parent
88552486f1
commit
b6f37bd8ec
@ -1,6 +1,6 @@
|
|||||||
Name: libyuv
|
Name: libyuv
|
||||||
URL: http://code.google.com/p/libyuv/
|
URL: http://code.google.com/p/libyuv/
|
||||||
Version: 1545
|
Version: 1546
|
||||||
License: BSD
|
License: BSD
|
||||||
License File: LICENSE
|
License File: LICENSE
|
||||||
|
|
||||||
|
|||||||
@ -390,18 +390,39 @@ 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
|
// Interpolate between two images using specified amount of interpolation
|
||||||
// (0 to 255) and store to destination.
|
// (0 to 255) and store to destination.
|
||||||
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src_argb0
|
// 'interpolation' is specified as 8 bit fraction where 0 means 100% src0
|
||||||
// and 255 means 1% src_argb0 and 99% src_argb1.
|
// and 255 means 1% src0 and 99% src1.
|
||||||
// Internally uses ARGBScale bilinear filtering.
|
LIBYUV_API
|
||||||
// Caveat: This function will write up to 16 bytes beyond the end of dst_argb.
|
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
|
LIBYUV_API
|
||||||
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
||||||
const uint8* src_argb1, int src_stride_argb1,
|
const uint8* src_argb1, int src_stride_argb1,
|
||||||
uint8* dst_argb, int dst_stride_argb,
|
uint8* dst_argb, int dst_stride_argb,
|
||||||
int width, int height, int interpolation);
|
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) || \
|
#if defined(__pnacl__) || defined(__CLR_VER) || \
|
||||||
(defined(__i386__) && !defined(__SSE2__))
|
(defined(__i386__) && !defined(__SSE2__))
|
||||||
#define LIBYUV_DISABLE_X86
|
#define LIBYUV_DISABLE_X86
|
||||||
|
|||||||
@ -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 1545
|
#define LIBYUV_VERSION 1546
|
||||||
|
|
||||||
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
|
#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
|
||||||
|
|||||||
@ -1681,37 +1681,37 @@ int ARGBShade(const uint8* src_argb, int src_stride_argb,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolate 2 ARGB images by specified amount (0 to 255).
|
// Interpolate 2 planes by specified amount (0 to 255).
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
int InterpolatePlane(const uint8* src0, int src_stride0,
|
||||||
const uint8* src_argb1, int src_stride_argb1,
|
const uint8* src1, int src_stride1,
|
||||||
uint8* dst_argb, int dst_stride_argb,
|
uint8* dst, int dst_stride,
|
||||||
int width, int height, int interpolation) {
|
int width, int height, int interpolation) {
|
||||||
int y;
|
int y;
|
||||||
void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
|
void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
|
||||||
ptrdiff_t src_stride, int dst_width,
|
ptrdiff_t src_stride, int dst_width,
|
||||||
int source_y_fraction) = InterpolateRow_C;
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
// Negative height means invert the image.
|
// Negative height means invert the image.
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
dst_argb = dst_argb + (height - 1) * dst_stride_argb;
|
dst = dst + (height - 1) * dst_stride;
|
||||||
dst_stride_argb = -dst_stride_argb;
|
dst_stride = -dst_stride;
|
||||||
}
|
}
|
||||||
// Coalesce rows.
|
// Coalesce rows.
|
||||||
if (src_stride_argb0 == width * 4 &&
|
if (src_stride0 == width &&
|
||||||
src_stride_argb1 == width * 4 &&
|
src_stride1 == width &&
|
||||||
dst_stride_argb == width * 4) {
|
dst_stride == width) {
|
||||||
width *= height;
|
width *= height;
|
||||||
height = 1;
|
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 defined(HAS_INTERPOLATEROW_SSE2)
|
||||||
if (TestCpuFlag(kCpuHasSSE2)) {
|
if (TestCpuFlag(kCpuHasSSE2)) {
|
||||||
InterpolateRow = InterpolateRow_Any_SSE2;
|
InterpolateRow = InterpolateRow_Any_SSE2;
|
||||||
if (IS_ALIGNED(width, 4)) {
|
if (IS_ALIGNED(width, 16)) {
|
||||||
InterpolateRow = InterpolateRow_SSE2;
|
InterpolateRow = InterpolateRow_SSE2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1719,7 +1719,7 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
|||||||
#if defined(HAS_INTERPOLATEROW_SSSE3)
|
#if defined(HAS_INTERPOLATEROW_SSSE3)
|
||||||
if (TestCpuFlag(kCpuHasSSSE3)) {
|
if (TestCpuFlag(kCpuHasSSSE3)) {
|
||||||
InterpolateRow = InterpolateRow_Any_SSSE3;
|
InterpolateRow = InterpolateRow_Any_SSSE3;
|
||||||
if (IS_ALIGNED(width, 4)) {
|
if (IS_ALIGNED(width, 16)) {
|
||||||
InterpolateRow = InterpolateRow_SSSE3;
|
InterpolateRow = InterpolateRow_SSSE3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1727,7 +1727,7 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
|||||||
#if defined(HAS_INTERPOLATEROW_AVX2)
|
#if defined(HAS_INTERPOLATEROW_AVX2)
|
||||||
if (TestCpuFlag(kCpuHasAVX2)) {
|
if (TestCpuFlag(kCpuHasAVX2)) {
|
||||||
InterpolateRow = InterpolateRow_Any_AVX2;
|
InterpolateRow = InterpolateRow_Any_AVX2;
|
||||||
if (IS_ALIGNED(width, 8)) {
|
if (IS_ALIGNED(width, 32)) {
|
||||||
InterpolateRow = InterpolateRow_AVX2;
|
InterpolateRow = InterpolateRow_AVX2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1735,30 +1735,78 @@ int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
|
|||||||
#if defined(HAS_INTERPOLATEROW_NEON)
|
#if defined(HAS_INTERPOLATEROW_NEON)
|
||||||
if (TestCpuFlag(kCpuHasNEON)) {
|
if (TestCpuFlag(kCpuHasNEON)) {
|
||||||
InterpolateRow = InterpolateRow_Any_NEON;
|
InterpolateRow = InterpolateRow_Any_NEON;
|
||||||
if (IS_ALIGNED(width, 4)) {
|
if (IS_ALIGNED(width, 16)) {
|
||||||
InterpolateRow = InterpolateRow_NEON;
|
InterpolateRow = InterpolateRow_NEON;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
|
#if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
|
||||||
if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
|
if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
|
||||||
IS_ALIGNED(src_argb0, 4) && IS_ALIGNED(src_stride_argb0, 4) &&
|
IS_ALIGNED(src0, 4) && IS_ALIGNED(src_stride0, 4) &&
|
||||||
IS_ALIGNED(src_argb1, 4) && IS_ALIGNED(src_stride_argb1, 4) &&
|
IS_ALIGNED(src1, 4) && IS_ALIGNED(src_stride1, 4) &&
|
||||||
IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
|
IS_ALIGNED(dst, 4) && IS_ALIGNED(dst_stride, 4) &&
|
||||||
|
IS_ALIGNED(width, 4)) {
|
||||||
InterpolateRow = InterpolateRow_MIPS_DSPR2;
|
InterpolateRow = InterpolateRow_MIPS_DSPR2;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
InterpolateRow(dst_argb, src_argb0, src_argb1 - src_argb0,
|
InterpolateRow(dst, src0, src1 - src0,
|
||||||
width * 4, interpolation);
|
width, interpolation);
|
||||||
src_argb0 += src_stride_argb0;
|
src0 += src_stride0;
|
||||||
src_argb1 += src_stride_argb1;
|
src1 += src_stride1;
|
||||||
dst_argb += dst_stride_argb;
|
dst += dst_stride;
|
||||||
}
|
}
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// Shuffle ARGB channel order. e.g. BGRA to ARGB.
|
// Shuffle ARGB channel order. e.g. BGRA to ARGB.
|
||||||
LIBYUV_API
|
LIBYUV_API
|
||||||
int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
|
int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
|
||||||
|
|||||||
@ -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_0[1280][4]);
|
||||||
SIMD_ALIGNED(uint8 orig_pixels_1[1280][4]);
|
SIMD_ALIGNED(uint8 orig_pixels_1[1280][4]);
|
||||||
SIMD_ALIGNED(uint8 interpolate_pixels[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, \
|
#define TESTTERP(FMT_A, BPP_A, STRIDE_A, \
|
||||||
FMT_B, BPP_B, STRIDE_B, \
|
FMT_B, BPP_B, STRIDE_B, \
|
||||||
W1280, TERP, DIFF, N, NEG, OFF) \
|
W1280, TERP, DIFF, N, NEG, OFF) \
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user