diff --git a/README.chromium b/README.chromium index 76f62b66f..cfa14b1b3 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1447 +Version: 1448 License: BSD License File: LICENSE diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h index 737abcaa7..11326e5ee 100644 --- a/include/libyuv/planar_functions.h +++ b/include/libyuv/planar_functions.h @@ -85,6 +85,17 @@ int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_v, int dst_stride_v, int width, int height); +LIBYUV_API +int YUY2ToNV12(const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_y, int dst_stride_y, + uint8* dst_uv, int dst_stride_uv, + int width, int height); + +LIBYUV_API +int UYVYToNV12(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_y, int dst_stride_y, + uint8* dst_uv, int dst_stride_uv, + int width, int height); // Convert I420 to I400. (calls CopyPlane ignoring u/v). LIBYUV_API @@ -436,12 +447,6 @@ int ARGBSobelXY(const uint8* src_argb, int src_stride_argb, uint8* dst_argb, int dst_stride_argb, int width, int height); -LIBYUV_API -int UYVYToNV12(const uint8* src_uyvy, int src_stride_uyvy, - uint8* dst_y, int dst_stride_y, - uint8* dst_uv, int dst_stride_uv, - int width, int height); - #ifdef __cplusplus } // extern "C" } // namespace libyuv diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 12c319a30..b8dbe3b06 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,6 +11,6 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 1447 +#define LIBYUV_VERSION 1448 #endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT diff --git a/source/planar_functions.cc b/source/planar_functions.cc index f6a0740a1..b96bd5020 100644 --- a/source/planar_functions.cc +++ b/source/planar_functions.cc @@ -2341,7 +2341,110 @@ int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y, return 0; } -// TODO(fbarchard): YUY2ToNV12 +LIBYUV_API +int YUY2ToNV12(const uint8* src_yuy2, int src_stride_yuy2, + uint8* dst_y, int dst_stride_y, + uint8* dst_uv, int dst_stride_uv, + int width, int height) { + int y; + int halfwidth = (width + 1) >> 1; + void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) = + SplitUVRow_C; + void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride, int dst_width, + int source_y_fraction) = InterpolateRow_C; + if (!src_yuy2 || + !dst_y || !dst_uv || + width <= 0 || height == 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; + src_stride_yuy2 = -src_stride_yuy2; + } +#if defined(HAS_SPLITUVROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + SplitUVRow = SplitUVRow_Any_SSE2; + if (IS_ALIGNED(width, 16)) { + SplitUVRow = SplitUVRow_SSE2; + } + } +#endif +#if defined(HAS_SPLITUVROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + SplitUVRow = SplitUVRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + SplitUVRow = SplitUVRow_AVX2; + } + } +#endif +#if defined(HAS_SPLITUVROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + SplitUVRow = SplitUVRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + SplitUVRow = SplitUVRow_NEON; + } + } +#endif +#if defined(HAS_INTERPOLATEROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + InterpolateRow = InterpolateRow_Any_SSE2; + if (IS_ALIGNED(width, 16)) { + InterpolateRow = InterpolateRow_SSE2; + } + } +#endif +#if defined(HAS_INTERPOLATEROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + InterpolateRow = InterpolateRow_Any_SSSE3; + if (IS_ALIGNED(width, 16)) { + InterpolateRow = InterpolateRow_SSSE3; + } + } +#endif +#if defined(HAS_INTERPOLATEROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + InterpolateRow = InterpolateRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + InterpolateRow = InterpolateRow_AVX2; + } + } +#endif +#if defined(HAS_INTERPOLATEROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + InterpolateRow = InterpolateRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + InterpolateRow = InterpolateRow_NEON; + } + } +#endif + + { + int awidth = halfwidth * 2; + // 2 rows of uv + align_buffer_64(rows, awidth * 2); + + for (y = 0; y < height - 1; y += 2) { + // Split Y from UV. + SplitUVRow(src_yuy2, dst_y, rows, awidth); + SplitUVRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, + rows + awidth, awidth); + InterpolateRow(dst_uv, rows, awidth, awidth, 128); + src_yuy2 += src_stride_yuy2 * 2; + dst_y += dst_stride_y * 2; + dst_uv += dst_stride_uv; + } + if (height & 1) { + // Split Y from UV. + SplitUVRow(src_yuy2, dst_y, dst_uv, width); + } + free_aligned_buffer_64(rows); + } + return 0; +} + LIBYUV_API int UYVYToNV12(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_y, int dst_stride_y, @@ -2431,8 +2534,7 @@ int UYVYToNV12(const uint8* src_uyvy, int src_stride_uyvy, // Split Y from UV. SplitUVRow(src_uyvy, rows, dst_y, awidth); SplitUVRow(src_uyvy + src_stride_uyvy, rows + awidth, - dst_y + dst_stride_y, - awidth); + dst_y + dst_stride_y, awidth); InterpolateRow(dst_uv, rows, awidth, awidth, 128); src_uyvy += src_stride_uyvy * 2; dst_y += dst_stride_y * 2; diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index 10d73ddfc..cbe2b444f 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -796,6 +796,7 @@ TEST_F(libyuvTest, FMT_A##To##FMT_PLANAR##N) { \ TESTATOBIPLANAR(ARGB, 4, NV12, 2, 2) TESTATOBIPLANAR(ARGB, 4, NV21, 2, 2) +TESTATOBIPLANAR(YUY2, 2, NV12, 2, 2) TESTATOBIPLANAR(UYVY, 2, NV12, 2, 2) #define TESTATOBI(FMT_A, BPP_A, STRIDE_A, HEIGHT_A, \ @@ -1530,72 +1531,76 @@ TEST_F(libyuvTest, FMT_PLANAR##To##FMT_B##Dither##N) { \ TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4) -TEST_F(libyuvTest, TestUYVYToNV12) { - const int kWidth = benchmark_width_; - const int kHeight = benchmark_height_; - - align_buffer_64(orig_uyvy, - 2 * SUBSAMPLE(kWidth, 2) * kHeight); - align_buffer_64(orig_y, kWidth * kHeight); - align_buffer_64(orig_u, - SUBSAMPLE(kWidth, 2) * - SUBSAMPLE(kHeight, 2)); - align_buffer_64(orig_v, - SUBSAMPLE(kWidth, 2) * - SUBSAMPLE(kHeight, 2)); - - align_buffer_64(dst_y_orig, kWidth * kHeight); - align_buffer_64(dst_uv_orig, 2 * - SUBSAMPLE(kWidth, 2) * - SUBSAMPLE(kHeight, 2)); - - align_buffer_64(dst_y, kWidth * kHeight); - align_buffer_64(dst_uv, 2 * - SUBSAMPLE(kWidth, 2) * - SUBSAMPLE(kHeight, 2)); - - srandom(time(NULL)); - MemRandomize(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2) * kHeight); - - /* Convert UYVY to NV12 in 2 steps for reference */ - libyuv::UYVYToI420(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2), - orig_y, kWidth, - orig_u, SUBSAMPLE(kWidth, 2), - orig_v, SUBSAMPLE(kWidth, 2), - kWidth, kHeight); - libyuv::I420ToNV12(orig_y, kWidth, - orig_u, SUBSAMPLE(kWidth, 2), - orig_v, SUBSAMPLE(kWidth, 2), - dst_y_orig, kWidth, - dst_uv_orig, 2 * SUBSAMPLE(kWidth, 2), - kWidth, kHeight); - - /* Convert to NV12 */ - for (int i = 0; i < benchmark_iterations_; ++i) { - libyuv::UYVYToNV12(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2), - dst_y, kWidth, - dst_uv, 2 * SUBSAMPLE(kWidth, 2), - kWidth, kHeight); - } - - for (int i = 0; i < kWidth * kHeight; ++i) { - EXPECT_EQ(orig_y[i], dst_y[i]); - } - for (int i = 0; i < kWidth * kHeight; ++i) { - EXPECT_EQ(dst_y_orig[i], dst_y[i]); - } - for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2); ++i) { - EXPECT_EQ(dst_uv_orig[i], dst_uv[i]); - } - - free_aligned_buffer_64(orig_uyvy); - free_aligned_buffer_64(orig_y); - free_aligned_buffer_64(orig_u); - free_aligned_buffer_64(orig_v); - free_aligned_buffer_64(dst_y_orig); - free_aligned_buffer_64(dst_uv_orig); - free_aligned_buffer_64(dst_y); - free_aligned_buffer_64(dst_uv); +#define TESTPTOB(NAME, UYVYTOI420, UYVYTONV12) \ +TEST_F(libyuvTest, NAME) { \ + const int kWidth = benchmark_width_; \ + const int kHeight = benchmark_height_; \ + \ + align_buffer_64(orig_uyvy, \ + 2 * SUBSAMPLE(kWidth, 2) * kHeight); \ + align_buffer_64(orig_y, kWidth * kHeight); \ + align_buffer_64(orig_u, \ + SUBSAMPLE(kWidth, 2) * \ + SUBSAMPLE(kHeight, 2)); \ + align_buffer_64(orig_v, \ + SUBSAMPLE(kWidth, 2) * \ + SUBSAMPLE(kHeight, 2)); \ + \ + align_buffer_64(dst_y_orig, kWidth * kHeight); \ + align_buffer_64(dst_uv_orig, 2 * \ + SUBSAMPLE(kWidth, 2) * \ + SUBSAMPLE(kHeight, 2)); \ + \ + align_buffer_64(dst_y, kWidth * kHeight); \ + align_buffer_64(dst_uv, 2 * \ + SUBSAMPLE(kWidth, 2) * \ + SUBSAMPLE(kHeight, 2)); \ + \ + srandom(time(NULL)); \ + MemRandomize(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2) * kHeight); \ + \ + /* Convert UYVY to NV12 in 2 steps for reference */ \ + libyuv::UYVYTOI420(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2), \ + orig_y, kWidth, \ + orig_u, SUBSAMPLE(kWidth, 2), \ + orig_v, SUBSAMPLE(kWidth, 2), \ + kWidth, kHeight); \ + libyuv::I420ToNV12(orig_y, kWidth, \ + orig_u, SUBSAMPLE(kWidth, 2), \ + orig_v, SUBSAMPLE(kWidth, 2), \ + dst_y_orig, kWidth, \ + dst_uv_orig, 2 * SUBSAMPLE(kWidth, 2), \ + kWidth, kHeight); \ + \ + /* Convert to NV12 */ \ + for (int i = 0; i < benchmark_iterations_; ++i) { \ + libyuv::UYVYTONV12(orig_uyvy, 2 * SUBSAMPLE(kWidth, 2), \ + dst_y, kWidth, \ + dst_uv, 2 * SUBSAMPLE(kWidth, 2), \ + kWidth, kHeight); \ + } \ + \ + for (int i = 0; i < kWidth * kHeight; ++i) { \ + EXPECT_EQ(orig_y[i], dst_y[i]); \ + } \ + for (int i = 0; i < kWidth * kHeight; ++i) { \ + EXPECT_EQ(dst_y_orig[i], dst_y[i]); \ + } \ + for (int i = 0; i < 2 * SUBSAMPLE(kWidth, 2) * SUBSAMPLE(kHeight, 2); ++i) { \ + EXPECT_EQ(dst_uv_orig[i], dst_uv[i]); \ + } \ + \ + free_aligned_buffer_64(orig_uyvy); \ + free_aligned_buffer_64(orig_y); \ + free_aligned_buffer_64(orig_u); \ + free_aligned_buffer_64(orig_v); \ + free_aligned_buffer_64(dst_y_orig); \ + free_aligned_buffer_64(dst_uv_orig); \ + free_aligned_buffer_64(dst_y); \ + free_aligned_buffer_64(dst_uv); \ } +TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12) +TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12) + } // namespace libyuv