diff --git a/README.chromium b/README.chromium index c725da45f..d9260d74a 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 276 +Version: 277 License: BSD License File: LICENSE diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h index 9fc50c31d..7337312f4 100644 --- a/include/libyuv/planar_functions.h +++ b/include/libyuv/planar_functions.h @@ -173,6 +173,13 @@ int ARGBToI400(const uint8* src_argb, int src_stride_argb, uint8* dst_y, int dst_stride_y, int width, int height); +// ARGB little endian (bgra in memory) to I422 +int ARGBToI422(const uint8* src_frame, int src_stride_frame, + 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); + // Draw a rectangle into I420. int I420Rect(uint8* dst_y, int dst_stride_y, uint8* dst_u, int dst_stride_u, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 542b8309d..c880d8fec 100644 --- a/include/libyuv/version.h +++ b/include/libyuv/version.h @@ -11,7 +11,7 @@ #ifndef INCLUDE_LIBYUV_VERSION_H_ #define INCLUDE_LIBYUV_VERSION_H_ -#define LIBYUV_VERSION 276 +#define LIBYUV_VERSION 277 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/source/planar_functions.cc b/source/planar_functions.cc index 08d8217fa..bc13604e8 100644 --- a/source/planar_functions.cc +++ b/source/planar_functions.cc @@ -432,6 +432,52 @@ int ARGBToI400(const uint8* src_argb, int src_stride_argb, return 0; } +// ARGB little endian (bgra in memory) to I422 +// same as I420 except UV plane is full height +int ARGBToI422(const uint8* src_argb, int src_stride_argb, + 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) { + if (height < 0) { + height = -height; + src_argb = src_argb + (height - 1) * src_stride_argb; + src_stride_argb = -src_stride_argb; + } + void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) = + ARGBToYRow_C; + void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C; +#if defined(HAS_ARGBTOYROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + if (width > 16) { + ARGBToUVRow = ARGBToUVRow_Any_SSSE3; + ARGBToYRow = ARGBToYRow_Any_SSSE3; + } + if (IS_ALIGNED(width, 16)) { + ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3; + ARGBToYRow = ARGBToYRow_Unaligned_SSSE3; + if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) { + ARGBToUVRow = ARGBToUVRow_SSSE3; + if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) { + ARGBToYRow = ARGBToYRow_SSSE3; + } + } + } + } +#endif + + for (int y = 0; y < height; ++y) { + ARGBToUVRow(src_argb, 0, dst_u, dst_v, width); + ARGBToYRow(src_argb, dst_y, width); + src_argb += src_stride_argb; + dst_y += dst_stride_y; + dst_u += dst_stride_u; + dst_v += dst_stride_v; + } + return 0; +} + int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, uint8* dst_argb, int dst_stride_argb, int width, int height) { diff --git a/unit_test/planar_test.cc b/unit_test/planar_test.cc index 1b053e3a7..64b773c71 100644 --- a/unit_test/planar_test.cc +++ b/unit_test/planar_test.cc @@ -25,54 +25,55 @@ namespace libyuv { -#define TESTPLANARTOB(FMT_A, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B) \ -TEST_F(libyuvTest, ##FMT_A##To##FMT_B##_CvsOPT) { \ - const int src_width = 1280; \ - const int src_height = 720; \ - align_buffer_16(src_y, src_width * src_height); \ - align_buffer_16(src_u, src_width / SUBSAMP_X * src_height / SUBSAMP_Y); \ - align_buffer_16(src_v, src_width / SUBSAMP_X * src_height / SUBSAMP_Y); \ - align_buffer_16(dst_rgb_c, (src_width * BPP_B) * src_height); \ - align_buffer_16(dst_rgb_opt, (src_width * BPP_B) * src_height); \ +#define TESTPLANARTOB(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B) \ +TEST_F(libyuvTest, ##FMT_PLANAR##To##FMT_B##_CvsOPT) { \ + const int kWidth = 1280; \ + const int kHeight = 720; \ + align_buffer_16(src_y, kWidth * kHeight); \ + align_buffer_16(src_u, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ + align_buffer_16(src_v, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ + align_buffer_16(dst_argb_c, (kWidth * BPP_B) * kHeight); \ + align_buffer_16(dst_argb_opt, (kWidth * BPP_B) * kHeight); \ srandom(time(NULL)); \ - for (int i = 0; i < src_height; ++i) \ - for (int j = 0; j < src_width; ++j) \ - src_y[(i * src_width) + j] = (random() & 0xff); \ - for (int i = 0; i < src_height / SUBSAMP_X; ++i) \ - for (int j = 0; j < src_width / SUBSAMP_Y; ++j) { \ - src_u[(i * src_width / SUBSAMP_X) + j] = (random() & 0xff); \ - src_v[(i * src_width / SUBSAMP_X) + j] = (random() & 0xff); \ + for (int i = 0; i < kHeight; ++i) \ + for (int j = 0; j < kWidth; ++j) \ + src_y[(i * kWidth) + j] = (random() & 0xff); \ + for (int i = 0; i < kHeight / SUBSAMP_X; ++i) \ + for (int j = 0; j < kWidth / SUBSAMP_Y; ++j) { \ + src_u[(i * kWidth / SUBSAMP_X) + j] = (random() & 0xff); \ + src_v[(i * kWidth / SUBSAMP_X) + j] = (random() & 0xff); \ } \ MaskCpuFlags(kCpuInitialized); \ - ##FMT_A##To##FMT_B(src_y, src_width, \ - src_u, src_width / SUBSAMP_X, \ - src_v, src_width / SUBSAMP_X, \ - dst_rgb_c, src_width * BPP_B, \ - src_width, src_height); \ + ##FMT_PLANAR##To##FMT_B(src_y, kWidth, \ + src_u, kWidth / SUBSAMP_X, \ + src_v, kWidth / SUBSAMP_X, \ + dst_argb_c, kWidth * BPP_B, \ + kWidth, kHeight); \ MaskCpuFlags(-1); \ const int runs = 1000; \ for (int i = 0; i < runs; ++i) { \ - ##FMT_A##To##FMT_B(src_y, src_width, \ - src_u, src_width / SUBSAMP_X, \ - src_v, src_width / SUBSAMP_X, \ - dst_rgb_opt, src_width * BPP_B, \ - src_width, src_height); \ + ##FMT_PLANAR##To##FMT_B(src_y, kWidth, \ + src_u, kWidth / SUBSAMP_X, \ + src_v, kWidth / SUBSAMP_X, \ + dst_argb_opt, kWidth * BPP_B, \ + kWidth, kHeight); \ } \ int err = 0; \ - for (int i = 0; i < src_height; ++i) { \ - for (int j = 0; j < src_width * BPP_B; ++j) { \ - int diff = static_cast(dst_rgb_c[i * src_width * BPP_B + j]) - \ - static_cast(dst_rgb_opt[i * src_width * BPP_B + j]); \ - if (abs(diff) > 2) \ - err++; \ + for (int i = 0; i < kHeight; ++i) { \ + for (int j = 0; j < kWidth * BPP_B; ++j) { \ + int diff = static_cast(dst_argb_c[i * kWidth * BPP_B + j]) - \ + static_cast(dst_argb_opt[i * kWidth * BPP_B + j]); \ + if (abs(diff) > 2) { \ + ++err; \ + } \ } \ } \ EXPECT_EQ(err, 0); \ free_aligned_buffer_16(src_y) \ free_aligned_buffer_16(src_u) \ free_aligned_buffer_16(src_v) \ - free_aligned_buffer_16(dst_rgb_c) \ - free_aligned_buffer_16(dst_rgb_opt) \ + free_aligned_buffer_16(dst_argb_c) \ + free_aligned_buffer_16(dst_argb_opt) \ } TESTPLANARTOB(I420, 2, 2, ARGB, 4) @@ -87,41 +88,124 @@ TESTPLANARTOB(I411, 4, 1, ARGB, 4) TESTPLANARTOB(I422, 2, 1, ARGB, 4) TESTPLANARTOB(I444, 1, 1, ARGB, 4) -#define TESTATOB(FMT_A, BPP_A, FMT_B, BPP_B) \ -TEST_F(libyuvTest, ##FMT_A##To##FMT_B##_CvsOPT) { \ - const int src_width = 1280; \ - const int src_height = 720; \ - align_buffer_16(src_argb, src_width * src_height * BPP_A); \ - align_buffer_16(dst_rgb_c, (src_width * BPP_B) * src_height); \ - align_buffer_16(dst_rgb_opt, (src_width * BPP_B) * src_height); \ +#define TESTATOPLANAR(FMT_A, BPP_A, FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y) \ +TEST_F(libyuvTest, ##FMT_A##To##FMT_PLANAR##_CvsOPT) { \ + const int kWidth = 1280; \ + const int kHeight = 720; \ + align_buffer_16(src_argb, (kWidth * BPP_A) * kHeight); \ + align_buffer_16(dst_y_c, kWidth * kHeight); \ + align_buffer_16(dst_u_c, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ + align_buffer_16(dst_v_c, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ + align_buffer_16(dst_y_opt, kWidth * kHeight); \ + align_buffer_16(dst_u_opt, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ + align_buffer_16(dst_v_opt, kWidth / SUBSAMP_X * kHeight / SUBSAMP_Y); \ srandom(time(NULL)); \ - for (int i = 0; i < src_height; ++i) \ - for (int j = 0; j < src_width * BPP_A; ++j) \ - src_argb[(i * src_width * BPP_A) + j] = (random() & 0xff); \ + for (int i = 0; i < kHeight; ++i) \ + for (int j = 0; j < kWidth * BPP_A; ++j) \ + src_argb[(i * kWidth * BPP_A) + j] = (random() & 0xff); \ MaskCpuFlags(kCpuInitialized); \ - ##FMT_A##To##FMT_B(src_argb, src_width * BPP_A, \ - dst_rgb_c, src_width * BPP_B, \ - src_width, src_height); \ + ##FMT_A##To##FMT_PLANAR(src_argb, kWidth * BPP_A, \ + dst_y_c, kWidth, \ + dst_u_c, kWidth / SUBSAMP_X, \ + dst_v_c, kWidth / SUBSAMP_X, \ + kWidth, kHeight); \ MaskCpuFlags(-1); \ const int runs = 1000; \ for (int i = 0; i < runs; ++i) { \ - ##FMT_A##To##FMT_B(src_argb, src_width * BPP_A, \ - dst_rgb_opt, src_width * BPP_B, \ - src_width, src_height); \ + ##FMT_A##To##FMT_PLANAR(src_argb, kWidth * BPP_A, \ + dst_y_opt, kWidth, \ + dst_u_opt, kWidth / SUBSAMP_X, \ + dst_v_opt, kWidth / SUBSAMP_X, \ + kWidth, kHeight); \ } \ int err = 0; \ - for (int i = 0; i < src_height; ++i) { \ - for (int j = 0; j < src_width * BPP_B; ++j) { \ - int diff = static_cast(dst_rgb_c[i * src_width * BPP_B + j]) - \ - static_cast(dst_rgb_opt[i * src_width * BPP_B + j]); \ + for (int i = 0; i < kHeight; ++i) { \ + for (int j = 0; j < kWidth; ++j) { \ + int diff = static_cast(dst_y_c[i * kWidth + j]) - \ + static_cast(dst_y_opt[i * kWidth + j]); \ + if (abs(diff) > 2) { \ + ++err; \ + } \ + } \ + } \ + EXPECT_EQ(err, 0); \ + for (int i = 0; i < kHeight / SUBSAMP_Y; ++i) { \ + for (int j = 0; j < kWidth / SUBSAMP_X; ++j) { \ + int diff = static_cast(dst_u_c[i * kWidth / SUBSAMP_X + j]) - \ + static_cast(dst_u_opt[i * kWidth / SUBSAMP_X + j]); \ + if (abs(diff) > 2) { \ + ++err; \ + } \ + } \ + } \ + EXPECT_EQ(err, 0); \ + for (int i = 0; i < kHeight / SUBSAMP_Y; ++i) { \ + for (int j = 0; j < kWidth / SUBSAMP_X; ++j) { \ + int diff = static_cast(dst_v_c[i * kWidth / SUBSAMP_X + j]) - \ + static_cast(dst_v_opt[i * kWidth / SUBSAMP_X + j]); \ + if (abs(diff) > 2) { \ + ++err; \ + } \ + } \ + } \ + EXPECT_EQ(err, 0); \ + free_aligned_buffer_16(dst_y_c) \ + free_aligned_buffer_16(dst_u_c) \ + free_aligned_buffer_16(dst_v_c) \ + free_aligned_buffer_16(dst_y_opt) \ + free_aligned_buffer_16(dst_u_opt) \ + free_aligned_buffer_16(dst_v_opt) \ + free_aligned_buffer_16(src_argb) \ +} + +TESTATOPLANAR(ARGB, 4, I420, 2, 2) +TESTATOPLANAR(BGRA, 4, I420, 2, 2) +TESTATOPLANAR(ABGR, 4, I420, 2, 2) +TESTATOPLANAR(RAW, 3, I420, 2, 2) +TESTATOPLANAR(RGB24, 3, I420, 2, 2) +TESTATOPLANAR(RGB565, 2, I420, 2, 2) +TESTATOPLANAR(ARGB1555, 2, I420, 2, 2) +TESTATOPLANAR(ARGB4444, 2, I420, 2, 2) +//TESTATOPLANAR(ARGB, 4, I411, 4, 1) +TESTATOPLANAR(ARGB, 4, I422, 2, 1) +//TESTATOPLANAR(ARGB, 4, I444, 1, 1) +// TODO(fbarchard): Implement and test 411 and 444 + +#define TESTATOB(FMT_A, BPP_A, FMT_B, BPP_B) \ +TEST_F(libyuvTest, ##FMT_A##To##FMT_B##_CvsOPT) { \ + const int kWidth = 1280; \ + const int kHeight = 720; \ + align_buffer_16(src_argb, kWidth * kHeight * BPP_A); \ + align_buffer_16(dst_argb_c, (kWidth * BPP_B) * kHeight); \ + align_buffer_16(dst_argb_opt, (kWidth * BPP_B) * kHeight); \ + srandom(time(NULL)); \ + for (int i = 0; i < kHeight; ++i) \ + for (int j = 0; j < kWidth * BPP_A; ++j) \ + src_argb[(i * kWidth * BPP_A) + j] = (random() & 0xff); \ + MaskCpuFlags(kCpuInitialized); \ + ##FMT_A##To##FMT_B(src_argb, kWidth * BPP_A, \ + dst_argb_c, kWidth * BPP_B, \ + kWidth, kHeight); \ + MaskCpuFlags(-1); \ + const int runs = 1000; \ + for (int i = 0; i < runs; ++i) { \ + ##FMT_A##To##FMT_B(src_argb, kWidth * BPP_A, \ + dst_argb_opt, kWidth * BPP_B, \ + kWidth, kHeight); \ + } \ + int err = 0; \ + for (int i = 0; i < kHeight; ++i) { \ + for (int j = 0; j < kWidth * BPP_B; ++j) { \ + int diff = static_cast(dst_argb_c[i * kWidth * BPP_B + j]) - \ + static_cast(dst_argb_opt[i * kWidth * BPP_B + j]); \ if (abs(diff) > 2) \ err++; \ } \ } \ EXPECT_EQ(err, 0); \ free_aligned_buffer_16(src_argb) \ - free_aligned_buffer_16(dst_rgb_c) \ - free_aligned_buffer_16(dst_rgb_opt) \ + free_aligned_buffer_16(dst_argb_c) \ + free_aligned_buffer_16(dst_argb_opt) \ } TESTATOB(ARGB, 4, ARGB, 4)