diff --git a/README.chromium b/README.chromium index d90c04228..8845bc851 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1685 +Version: 1686 License: BSD License File: LICENSE diff --git a/include/libyuv/convert.h b/include/libyuv/convert.h index c1574eb1b..d310f8493 100644 --- a/include/libyuv/convert.h +++ b/include/libyuv/convert.h @@ -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, diff --git a/include/libyuv/convert_from.h b/include/libyuv/convert_from.h index 8c3999bbd..b5a422903 100644 --- a/include/libyuv/convert_from.h +++ b/include/libyuv/convert_from.h @@ -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, diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h index 88b651ddc..653b06197 100644 --- a/include/libyuv/planar_functions.h +++ b/include/libyuv/planar_functions.h @@ -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, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 3e11fd6c4..358152397 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -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_ diff --git a/source/convert.cc b/source/convert.cc index 8ef06afc3..fd2066e29 100644 --- a/source/convert.cc +++ b/source/convert.cc @@ -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, diff --git a/source/convert_from.cc b/source/convert_from.cc index e57bb4bf4..9da607102 100644 --- a/source/convert_from.cc +++ b/source/convert_from.cc @@ -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 diff --git a/source/planar_functions.cc b/source/planar_functions.cc index a08cce927..c55ef7f27 100644 --- a/source/planar_functions.cc +++ b/source/planar_functions.cc @@ -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, diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index 126b6574f..c4e212e20 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -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, \ diff --git a/unit_test/planar_test.cc b/unit_test/planar_test.cc index ce1736891..a499688fe 100644 --- a/unit_test/planar_test.cc +++ b/unit_test/planar_test.cc @@ -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(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(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(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]); }