diff --git a/README.chromium b/README.chromium index 7125848f1..abd0e7d9c 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1683 +Version: 1684 License: BSD License File: LICENSE diff --git a/include/libyuv/convert_argb.h b/include/libyuv/convert_argb.h index ca87dc769..5998649df 100644 --- a/include/libyuv/convert_argb.h +++ b/include/libyuv/convert_argb.h @@ -443,6 +443,15 @@ int ARGB4444ToARGB(const uint8* src_frame, int width, int height); +// Convert AR30 To ARGB. +LIBYUV_API +int AR30ToARGB(const uint8* src_ar30, + int src_stride_ar30, + uint8* dst_argb, + int dst_stride_argb, + int width, + int height); + #ifdef HAVE_JPEG // src_width/height provided by capture // dst_width/height for clipping determine final size. diff --git a/include/libyuv/row.h b/include/libyuv/row.h index 7c9ca04a3..ea0186dd1 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -1601,6 +1601,7 @@ void RAWToRGB24Row_C(const uint8* src_raw, uint8* dst_rgb24, int width); void RGB565ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int width); void ARGB1555ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int width); void ARGB4444ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int width); +void AR30ToARGBRow_C(const uint8* src_ar30, uint8* dst_argb, int width); void RGB24ToARGBRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int width); diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 39e6cc4d5..68919b202 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 1683 +#define LIBYUV_VERSION 1684 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/source/convert_argb.cc b/source/convert_argb.cc index 2e7c0f8fe..5858ec25e 100644 --- a/source/convert_argb.cc +++ b/source/convert_argb.cc @@ -1504,6 +1504,40 @@ int ARGB4444ToARGB(const uint8* src_argb4444, return 0; } +// Convert AR30 to ARGB. +LIBYUV_API +int AR30ToARGB(const uint8* src_ar30, + int src_stride_ar30, + uint8* dst_argb, + int dst_stride_argb, + int width, + int height) { + int y; + void (*AR30ToARGBRow)(const uint8* src_ar30, uint8* dst_argb, int width) = + AR30ToARGBRow_C; + if (!src_ar30 || !dst_argb || width <= 0 || height == 0) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_ar30 = src_ar30 + (height - 1) * src_stride_ar30; + src_stride_ar30 = -src_stride_ar30; + } + // Coalesce rows. + if (src_stride_ar30 == width * 2 && dst_stride_argb == width * 4) { + width *= height; + height = 1; + src_stride_ar30 = dst_stride_argb = 0; + } + for (y = 0; y < height; ++y) { + AR30ToARGBRow(src_ar30, dst_argb, width); + src_ar30 += src_stride_ar30; + dst_argb += dst_stride_argb; + } + return 0; +} + // Convert NV12 to ARGB with matrix static int NV12ToARGBMatrix(const uint8* src_y, int src_stride_y, diff --git a/source/row_common.cc b/source/row_common.cc index d69634908..4a5f53710 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -165,6 +165,23 @@ void ARGB4444ToARGBRow_C(const uint8* src_argb4444, } } +void AR30ToARGBRow_C(const uint8* src_ar30, uint8* dst_argb, int width) { + int x; + for (x = 0; x < width; ++x) { + uint32 ar30 = *(uint32*)src_ar30; + uint32 b = ar30 & 0x3ff; + uint32 g = (ar30 >> 10) & 0x3ff; + uint32 r = (ar30 >> 20) & 0x3ff; + uint32 a = (ar30 >> 30) & 0x3; + dst_argb[0] = b >> 2; + dst_argb[1] = g >> 2; + dst_argb[2] = r >> 2; + dst_argb[3] = a * 0x55; + dst_argb += 4; + src_ar30 += 4; + } +} + void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { @@ -304,9 +321,9 @@ void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { void ARGBToAR30Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { int x; for (x = 0; x < width; ++x) { - uint32 b0 = (src_argb[0] >> 6) | (src_argb[0] << 2); - uint32 g0 = (src_argb[1] >> 6) | (src_argb[1] << 2); - uint32 r0 = (src_argb[2] >> 6) | (src_argb[2] << 2); + uint32 b0 = (src_argb[0] >> 6) | ((uint32)(src_argb[0]) << 2); + uint32 g0 = (src_argb[1] >> 6) | ((uint32)(src_argb[1]) << 2); + uint32 r0 = (src_argb[2] >> 6) | ((uint32)(src_argb[2]) << 2); uint32 a0 = (src_argb[3] >> 6); *(uint32*)(dst_rgb) = b0 | (g0 << 10) | (r0 << 20) | (a0 << 30); dst_rgb += 4; diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index b246064d5..e49b7df53 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -1072,6 +1072,7 @@ TESTATOB(RGB24, 3, 3, 1, ARGB, 4, 4, 1, 0) TESTATOB(RGB565, 2, 2, 1, ARGB, 4, 4, 1, 0) TESTATOB(ARGB1555, 2, 2, 1, ARGB, 4, 4, 1, 0) TESTATOB(ARGB4444, 2, 2, 1, ARGB, 4, 4, 1, 0) +TESTATOB(AR30, 4, 4, 1, ARGB, 4, 4, 1, 0) TESTATOB(YUY2, 2, 4, 1, ARGB, 4, 4, 1, 4) TESTATOB(UYVY, 2, 4, 1, ARGB, 4, 4, 1, 4) TESTATOB(YUY2, 2, 4, 1, Y, 1, 1, 1, 0) @@ -1718,6 +1719,8 @@ TESTPLANARTOBD(I420, 2, 2, RGB565, 2, 2, 1, 9, ARGB, 4) TESTPTOB(TestYUY2ToNV12, YUY2ToI420, YUY2ToNV12) TESTPTOB(TestUYVYToNV12, UYVYToI420, UYVYToNV12) +// Transitive tests. A to B to C is same as A to C. + #define TESTPLANARTOEI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, SUB_B, BPP_B, \ W1280, N, NEG, OFF, FMT_C, BPP_C) \ TEST_F(LibYUVConvertTest, FMT_PLANAR##To##FMT_B##_##FMT_C##N) { \ @@ -1883,6 +1886,59 @@ TESTPLANARTOE(I422, 2, 1, UYVY, 2, 4, ARGB, 4) TESTQPLANARTOE(I420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4) TESTQPLANARTOE(I420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4) +#define TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, W1280, N, NEG, \ + OFF, FMT_C, BPP_C) \ + TEST_F(LibYUVConvertTest, FMT_A##To##FMT_B##_##FMT_C##N) { \ + const int kWidth = ((W1280) > 0) ? (W1280) : 1; \ + const int kHeight = benchmark_height_; \ + const int kStrideA = SUBSAMPLE(kWidth, SUB_A) * BPP_A; \ + const int kStrideB = SUBSAMPLE(kWidth, SUB_B) * BPP_B; \ + align_buffer_page_end(src_argb_a, kStrideA* kHeight + OFF); \ + align_buffer_page_end(dst_argb_b, kStrideB* kHeight + OFF); \ + MemRandomize(src_argb_a + OFF, kStrideA * kHeight); \ + memset(dst_argb_b + OFF, 1, kStrideB * kHeight); \ + for (int i = 0; i < benchmark_iterations_; ++i) { \ + FMT_A##To##FMT_B(src_argb_a + OFF, kStrideA, dst_argb_b + OFF, kStrideB, \ + kWidth, NEG kHeight); \ + } \ + /* Convert to a 3rd format in 1 step and 2 steps and compare */ \ + const int kStrideC = kWidth * BPP_C; \ + align_buffer_page_end(dst_argb_c, kStrideC* kHeight + OFF); \ + align_buffer_page_end(dst_argb_bc, kStrideC* kHeight + OFF); \ + memset(dst_argb_c + OFF, 2, kStrideC * kHeight); \ + memset(dst_argb_bc + OFF, 3, kStrideC * kHeight); \ + FMT_A##To##FMT_C(src_argb_a + OFF, kStrideA, dst_argb_c + OFF, kStrideC, \ + kWidth, NEG kHeight); \ + /* Convert B to C */ \ + FMT_B##To##FMT_C(dst_argb_b + OFF, kStrideB, dst_argb_bc + OFF, kStrideC, \ + kWidth, kHeight); \ + for (int i = 0; i < kStrideC * kHeight; i += 4) { \ + EXPECT_EQ(dst_argb_c[i + OFF + 0], dst_argb_bc[i + OFF + 0]); \ + EXPECT_EQ(dst_argb_c[i + OFF + 1], dst_argb_bc[i + OFF + 1]); \ + EXPECT_EQ(dst_argb_c[i + OFF + 2], dst_argb_bc[i + OFF + 2]); \ + EXPECT_NEAR(dst_argb_c[i + OFF + 3], dst_argb_bc[i + OFF + 3], 64); \ + } \ + free_aligned_buffer_page_end(src_argb_a); \ + free_aligned_buffer_page_end(dst_argb_b); \ + free_aligned_buffer_page_end(dst_argb_c); \ + free_aligned_buffer_page_end(dst_argb_bc); \ + } + +#define TESTPLANETOE(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, FMT_C, BPP_C) \ + TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, \ + benchmark_width_ - 4, _Any, +, 0, FMT_C, BPP_C) \ + TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ + _Unaligned, +, 1, FMT_C, BPP_C) \ + TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ + _Invert, -, 0, FMT_C, BPP_C) \ + TESTPLANETOEI(FMT_A, SUB_A, BPP_A, FMT_B, SUB_B, BPP_B, benchmark_width_, \ + _Opt, +, 0, FMT_C, BPP_C) + +// Caveat: Destination needs to be 4 bytes +TESTPLANETOE(ARGB, 1, 4, AR30, 1, 4, ARGB, 4) + +// TESTPLANETOE(ARGB, 1, 4, BGRA, 1, 4, ARGB, 4) + TEST_F(LibYUVConvertTest, RotateWithARGBSource) { // 2x2 frames uint32_t src[4];