Commit 2ed2402f authored by Frank Barchard's avatar Frank Barchard Committed by Commit Bot

I420ToI010 for 8 to 10 bit YUV conversion.

Convert planar 8 bit formats to planar 16 bit formats.

Includes msan fix for Convert8To16Row_Opt unittest.

I420 is YUV bt.601 8 bits per channel with 420 subsampling.
I010 is YUV bt.601 10 bits per channel with 420 subsampling.
I is color space - bt.601.  The function does no color space
 conversion so H420ToI010 is aliased to this function as well.
0 = 420 subsampling.  The chroma channels are half width / height.
10 = 10 bits per channel, stored in low 10 bits of 16 bit samples.

For SSSE3 version:
out/Release/libyuv_unittest --gtest_filter=*LibYUVConvertTest.I420ToI010_Opt --libyuv_width=1280 --libyuv_height=720 --libyuv_repeat=999 --libyuv_flags=-1 --libyuv_cpu_info=-1
[ RUN      ] LibYUVConvertTest.I420ToI010_Opt
[       OK ] LibYUVConvertTest.I420ToI010_Opt (276 ms)

Bug: libyuv:751
Test: LibYUVConvertTest.I420ToI010_Opt
Change-Id: I072876ee4fd74a2b74f459b628838bc808f9bdd2
Reviewed-on: https://chromium-review.googlesource.com/846421Reviewed-by: 's avatarMiguel Casas <mcasas@chromium.org>
Commit-Queue: Frank Barchard <fbarchard@chromium.org>
parent 140fc0a2
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 1685
Version: 1686
License: BSD
License File: LICENSE
......
......@@ -97,6 +97,7 @@ int I010Copy(const uint16* src_y,
int height);
// Convert 10 bit YUV to 8 bit
#define H010ToH420 I010ToI420
LIBYUV_API
int I010ToI420(const uint16* src_y,
int src_stride_y,
......
......@@ -21,7 +21,22 @@ extern "C" {
// See Also convert.h for conversions from formats to I420.
// I420Copy in convert to I420ToI420.
// Convert 8 bit YUV to 10 bit.
#define H420ToH010 I420ToI010
int I420ToI010(const uint8* src_y,
int src_stride_y,
const uint8* src_u,
int src_stride_u,
const uint8* src_v,
int src_stride_v,
uint16* dst_y,
int dst_stride_y,
uint16* dst_u,
int dst_stride_u,
uint16* dst_v,
int dst_stride_v,
int width,
int height);
LIBYUV_API
int I420ToI422(const uint8* src_y,
......
......@@ -48,6 +48,15 @@ void Convert16To8Plane(const uint16* src_y,
int width,
int height);
LIBYUV_API
void Convert8To16Plane(const uint8* src_y,
int src_stride_y,
uint16* dst_y,
int dst_stride_y,
int scale, // 1024 for 10 bits
int width,
int height);
// Set a plane of data to a 32 bit value.
LIBYUV_API
void SetPlane(uint8* dst_y,
......
......@@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1685
#define LIBYUV_VERSION 1686
#endif // INCLUDE_LIBYUV_VERSION_H_
......@@ -62,7 +62,7 @@ static int I4xxToI420(const uint8* src_y,
return 0;
}
// Copy I420 with optional flipping
// Copy I420 with optional flipping.
// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
// is does row coalescing.
LIBYUV_API
......@@ -106,7 +106,7 @@ int I420Copy(const uint8* src_y,
return 0;
}
// Copy I010 with optional flipping
// Copy I010 with optional flipping.
LIBYUV_API
int I010Copy(const uint16* src_y,
int src_stride_y,
......@@ -148,7 +148,7 @@ int I010Copy(const uint16* src_y,
return 0;
}
// Convert 10 bit YUV to 8 bit
// Convert 10 bit YUV to 8 bit.
LIBYUV_API
int I010ToI420(const uint16* src_y,
int src_stride_y,
......
......@@ -65,6 +65,50 @@ static int I420ToI4xx(const uint8* src_y,
return 0;
}
// Convert 8 bit YUV to 10 bit.
LIBYUV_API
int I420ToI010(const uint8* src_y,
int src_stride_y,
const uint8* src_u,
int src_stride_u,
const uint8* src_v,
int src_stride_v,
uint16* dst_y,
int dst_stride_y,
uint16* dst_u,
int dst_stride_u,
uint16* dst_v,
int dst_stride_v,
int width,
int height) {
int halfwidth = (width + 1) >> 1;
int halfheight = (height + 1) >> 1;
if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
return -1;
}
// Negative height means invert the image.
if (height < 0) {
height = -height;
halfheight = (height + 1) >> 1;
src_y = src_y + (height - 1) * src_stride_y;
src_u = src_u + (halfheight - 1) * src_stride_u;
src_v = src_v + (halfheight - 1) * src_stride_v;
src_stride_y = -src_stride_y;
src_stride_u = -src_stride_u;
src_stride_v = -src_stride_v;
}
// Convert Y plane.
Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
height);
// Convert UV planes.
Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
halfheight);
Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
halfheight);
return 0;
}
// 420 chroma is 1/2 width, 1/2 height
// 422 chroma is 1/2 width, 1x height
LIBYUV_API
......
......@@ -163,7 +163,7 @@ void Convert16To8Plane(const uint16* src_y,
}
#endif
// Copy plane
// Convert plane
for (y = 0; y < height; ++y) {
Convert16To8Row(src_y, dst_y, scale, width);
src_y += src_stride_y;
......@@ -171,6 +171,56 @@ void Convert16To8Plane(const uint16* src_y,
}
}
// Convert a plane of 8 bit data to 16 bit
LIBYUV_API
void Convert8To16Plane(const uint8* src_y,
int src_stride_y,
uint16* dst_y,
int dst_stride_y,
int scale, // 16384 for 10 bits
int width,
int height) {
int y;
void (*Convert8To16Row)(const uint8* src_y, uint16* dst_y, int scale,
int width) = Convert8To16Row_C;
// Negative height means invert the image.
if (height < 0) {
height = -height;
dst_y = dst_y + (height - 1) * dst_stride_y;
dst_stride_y = -dst_stride_y;
}
// Coalesce rows.
if (src_stride_y == width && dst_stride_y == width) {
width *= height;
height = 1;
src_stride_y = dst_stride_y = 0;
}
#if defined(HAS_CONVERT8TO16ROW_SSE2)
if (TestCpuFlag(kCpuHasSSE2)) {
Convert8To16Row = Convert8To16Row_Any_SSE2;
if (IS_ALIGNED(width, 16)) {
Convert8To16Row = Convert8To16Row_SSE2;
}
}
#endif
#if defined(HAS_CONVERT8TO16ROW_AVX2)
if (TestCpuFlag(kCpuHasAVX2)) {
Convert8To16Row = Convert8To16Row_Any_AVX2;
if (IS_ALIGNED(width, 32)) {
Convert8To16Row = Convert8To16Row_AVX2;
}
}
#endif
// Convert plane
for (y = 0; y < height; ++y) {
Convert8To16Row(src_y, dst_y, scale, width);
src_y += src_stride_y;
dst_y += dst_stride_y;
}
}
// Copy I422.
LIBYUV_API
int I422Copy(const uint8* src_y,
......
......@@ -146,6 +146,10 @@ TESTPLANARTOP(I422, uint8, 1, 2, 1, I422, uint8, 1, 2, 1)
TESTPLANARTOP(I444, uint8, 1, 1, 1, I444, uint8, 1, 1, 1)
TESTPLANARTOP(I010, uint16, 2, 2, 2, I010, uint16, 2, 2, 2)
TESTPLANARTOP(I010, uint16, 2, 2, 2, I420, uint8, 1, 2, 2)
TESTPLANARTOP(I420, uint8, 1, 2, 2, I010, uint16, 2, 2, 2)
TESTPLANARTOP(H010, uint16, 2, 2, 2, H010, uint16, 2, 2, 2)
TESTPLANARTOP(H010, uint16, 2, 2, 2, H420, uint8, 1, 2, 2)
TESTPLANARTOP(H420, uint8, 1, 2, 2, H010, uint16, 2, 2, 2)
// Test Android 420 to I420
#define TESTAPLANARTOPI(SRC_FMT_PLANAR, PIXEL_STRIDE, SRC_SUBSAMP_X, \
......
......@@ -2776,6 +2776,38 @@ TEST_F(LibYUVPlanarTest, Convert16To8Row_Opt) {
}
#endif // HAS_CONVERT16TO8ROW_AVX2
TEST_F(LibYUVPlanarTest, Convert8To16Plane) {
const int kPixels = benchmark_width_ * benchmark_height_;
align_buffer_page_end(src_pixels_y, kPixels);
align_buffer_page_end(dst_pixels_y_opt, kPixels * 2);
align_buffer_page_end(dst_pixels_y_c, kPixels * 2);
MemRandomize(src_pixels_y, kPixels);
memset(dst_pixels_y_opt, 0, kPixels * 2);
memset(dst_pixels_y_c, 1, kPixels * 2);
MaskCpuFlags(disable_cpu_flags_);
Convert8To16Plane(src_pixels_y, benchmark_width_,
reinterpret_cast<uint16*>(dst_pixels_y_c), benchmark_width_,
1024, benchmark_width_, benchmark_height_);
MaskCpuFlags(benchmark_cpu_info_);
for (int i = 0; i < benchmark_iterations_; ++i) {
Convert8To16Plane(src_pixels_y, benchmark_width_,
reinterpret_cast<uint16*>(dst_pixels_y_opt),
benchmark_width_, 1024, benchmark_width_,
benchmark_height_);
}
for (int i = 0; i < kPixels * 2; ++i) {
EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
free_aligned_buffer_page_end(src_pixels_y);
free_aligned_buffer_page_end(dst_pixels_y_opt);
free_aligned_buffer_page_end(dst_pixels_y_c);
}
// TODO(fbarchard): Improve test for more platforms.
#ifdef HAS_CONVERT8TO16ROW_AVX2
TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) {
......@@ -2785,9 +2817,8 @@ TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) {
align_buffer_page_end(dst_pixels_y_c, kPixels * 2);
MemRandomize(src_pixels_y, kPixels);
memset(dst_pixels_y_opt, 0, kPixels);
memset(dst_pixels_y_c, 1, kPixels);
memset(dst_pixels_y_opt, 0, kPixels * 2);
memset(dst_pixels_y_c, 1, kPixels * 2);
Convert8To16Row_C(src_pixels_y, reinterpret_cast<uint16*>(dst_pixels_y_c),
1024, kPixels);
......@@ -2810,7 +2841,7 @@ TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) {
}
}
for (int i = 0; i < kPixels; ++i) {
for (int i = 0; i < kPixels * 2; ++i) {
EXPECT_EQ(dst_pixels_y_opt[i], dst_pixels_y_c[i]);
}
......
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