From 66305588755486b27380b58c04aa8c1cf4541af3 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Thu, 15 Feb 2018 14:18:17 -0800 Subject: [PATCH] 10 bit YUV to 10 bit BGR BGR variation of 10 bit conversion using swapped U and V and mirrored matrix to produce AB30 format instead of AR30. Bug: libyuv:777 Test: LibYUVConvertTest.H010ToAB30_Opt Change-Id: I96d115a5d1e12138f40cb548871e03aa3ab210eb Reviewed-on: https://chromium-review.googlesource.com/922284 Commit-Queue: Frank Barchard Reviewed-by: Miguel Casas --- README.chromium | 2 +- docs/formats.md | 3 +- include/libyuv/convert_argb.h | 28 +++++++++++++++ include/libyuv/row.h | 28 ++++++++------- include/libyuv/video_common.h | 4 ++- source/convert.cc | 4 +-- source/convert_argb.cc | 38 ++++++++++++++++++-- source/mjpeg_decoder.cc | 6 ++-- unit_test/convert_test.cc | 65 ++++++++++++++++++++++++++++++++++ unit_test/video_common_test.cc | 1 + 10 files changed, 156 insertions(+), 23 deletions(-) diff --git a/README.chromium b/README.chromium index 363ecc332..f38414b3a 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 1697 +Version: 1698 License: BSD License File: LICENSE diff --git a/docs/formats.md b/docs/formats.md index 0130a1ff4..f78f57bb4 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -50,11 +50,12 @@ The following is extracted from video_common.h as a complete list of formats sup // 1 Secondary YUV format: row biplanar. FOURCC_M420 = FOURCC('M', '4', '2', '0'), - // 10 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc + // 11 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), FOURCC_AR30 = FOURCC('A', 'R', '3', '0'), // 10 bit per channel. 2101010. + FOURCC_AB30 = FOURCC('A', 'B', '3', '0'), // ABGR version of 10 bit FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), diff --git a/include/libyuv/convert_argb.h b/include/libyuv/convert_argb.h index 9343dfd74..cd4a611de 100644 --- a/include/libyuv/convert_argb.h +++ b/include/libyuv/convert_argb.h @@ -446,6 +446,32 @@ int H010ToAR30(const uint16_t* src_y, int width, int height); +// Convert I010 to AB30. +LIBYUV_API +int I010ToAB30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ab30, + int dst_stride_ab30, + int width, + int height); + +// Convert H010 to AB30. +LIBYUV_API +int H010ToAB30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ab30, + int dst_stride_ab30, + int width, + int height); + // BGRA little endian (argb in memory) to ARGB. LIBYUV_API int BGRAToARGB(const uint8_t* src_bgra, @@ -530,6 +556,8 @@ int AR30ToARGB(const uint8_t* src_ar30, int width, int height); +#define AB30ToABGR + // Convert AR30 To ABGR. LIBYUV_API int AR30ToABGR(const uint8_t* src_ar30, diff --git a/include/libyuv/row.h b/include/libyuv/row.h index 7a1d4ddca..62ed119db 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -1631,14 +1631,14 @@ void ARGB1555ToARGBRow_Any_SSE2(const uint8_t* src_ptr, void ARGB4444ToARGBRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); -void RGB565ToARGBRow_Any_AVX2(const uint8_t* src_rgb565, - uint8_t* dst_argb, +void RGB565ToARGBRow_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); -void ARGB1555ToARGBRow_Any_AVX2(const uint8_t* src_argb1555, - uint8_t* dst_argb, +void ARGB1555ToARGBRow_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); -void ARGB4444ToARGBRow_Any_AVX2(const uint8_t* src_argb4444, - uint8_t* dst_argb, +void ARGB4444ToARGBRow_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); void RGB24ToARGBRow_Any_NEON(const uint8_t* src_ptr, @@ -1752,7 +1752,9 @@ void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width); void J400ToARGBRow_Any_SSE2(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); -void J400ToARGBRow_Any_AVX2(const uint8_t* src_y, uint8_t* dst_argb, int width); +void J400ToARGBRow_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, + int width); void J400ToARGBRow_Any_NEON(const uint8_t* src_ptr, uint8_t* dst_ptr, int width); @@ -2430,14 +2432,14 @@ void ARGBToRGB565DitherRow_Any_AVX2(const uint8_t* src_ptr, const uint32_t param, int width); -void ARGBToRGB565Row_Any_AVX2(const uint8_t* src_argb, - uint8_t* dst_rgb, +void ARGBToRGB565Row_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); -void ARGBToARGB1555Row_Any_AVX2(const uint8_t* src_argb, - uint8_t* dst_rgb, +void ARGBToARGB1555Row_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); -void ARGBToARGB4444Row_Any_AVX2(const uint8_t* src_argb, - uint8_t* dst_rgb, +void ARGBToARGB4444Row_Any_AVX2(const uint8_t* src_ptr, + uint8_t* dst_ptr, int width); void ABGRToAR30Row_Any_AVX2(const uint8_t* src_ptr, uint8_t* dst_ptr, diff --git a/include/libyuv/video_common.h b/include/libyuv/video_common.h index d2dbde75d..bcef378b5 100644 --- a/include/libyuv/video_common.h +++ b/include/libyuv/video_common.h @@ -63,11 +63,12 @@ enum FourCC { // 1 Secondary YUV format: row biplanar. FOURCC_M420 = FOURCC('M', '4', '2', '0'), - // 10 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc + // 11 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp, 1 10 bpc FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'), FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'), FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'), FOURCC_AR30 = FOURCC('A', 'R', '3', '0'), // 10 bit per channel. 2101010. + FOURCC_AB30 = FOURCC('A', 'B', '3', '0'), // ABGR version of 10 bit FOURCC_24BG = FOURCC('2', '4', 'B', 'G'), FOURCC_RAW = FOURCC('r', 'a', 'w', ' '), FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'), @@ -137,6 +138,7 @@ enum FourCCBpp { FOURCC_BPP_ABGR = 32, FOURCC_BPP_RGBA = 32, FOURCC_BPP_AR30 = 32, + FOURCC_BPP_AB30 = 32, FOURCC_BPP_24BG = 24, FOURCC_BPP_RAW = 24, FOURCC_BPP_RGBP = 16, diff --git a/source/convert.cc b/source/convert.cc index 55a2341e6..375cc732c 100644 --- a/source/convert.cc +++ b/source/convert.cc @@ -1716,8 +1716,8 @@ int Android420ToI420(const uint8_t* src_y, halfwidth, halfheight); return 0; // Split UV planes - NV12 - } else if (src_pixel_stride_uv == 2 && vu_off == 1 && - src_stride_u == src_stride_v) { + } + if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v, halfwidth, halfheight); return 0; diff --git a/source/convert_argb.cc b/source/convert_argb.cc index d024e1af1..e084f6806 100644 --- a/source/convert_argb.cc +++ b/source/convert_argb.cc @@ -500,6 +500,40 @@ int H010ToAR30(const uint16_t* src_y, &kYuvH709Constants, width, height); } +// Convert I010 to AB30. +LIBYUV_API +int I010ToAB30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ab30, + int dst_stride_ab30, + int width, + int height) { + return I010ToAR30Matrix(src_y, src_stride_y, src_v, + src_stride_v, src_u, src_stride_u, dst_ab30, dst_stride_ab30, + &kYvuI601Constants, width, height); +} + +// Convert H010 to AB30. +LIBYUV_API +int H010ToAB30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ab30, + int dst_stride_ab30, + int width, + int height) { + return I010ToAR30Matrix(src_y, src_stride_y, src_v, + src_stride_v, src_u, src_stride_u, dst_ab30, dst_stride_ab30, + &kYvuH709Constants, width, height); +} + // Convert 10 bit YUV to ARGB with matrix static int I010ToARGBMatrix(const uint16_t* src_y, int src_stride_y, @@ -1950,8 +1984,8 @@ int Android420ToARGBMatrix(const uint8_t* src_y, return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb, dst_stride_argb, yuvconstants, width, height); // NV12 - } else if (src_pixel_stride_uv == 2 && vu_off == 1 && - src_stride_u == src_stride_v) { + } + if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) { return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb, dst_stride_argb, yuvconstants, width, height); } diff --git a/source/mjpeg_decoder.cc b/source/mjpeg_decoder.cc index 8b0858c7b..eaf253013 100644 --- a/source/mjpeg_decoder.cc +++ b/source/mjpeg_decoder.cc @@ -556,9 +556,9 @@ JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper( if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 2 && subsample_y[1] == 1 && subsample_x[2] == 2 && subsample_y[2] == 1) { return kJpegYuv422; - } else if (subsample_x[0] == 1 && subsample_y[0] == 1 && - subsample_x[1] == 1 && subsample_y[1] == 1 && - subsample_x[2] == 1 && subsample_y[2] == 1) { + } + if (subsample_x[0] == 1 && subsample_y[0] == 1 && subsample_x[1] == 1 && + subsample_y[1] == 1 && subsample_x[2] == 1 && subsample_y[2] == 1) { return kJpegYuv444; } } else if (number_of_components == 1) { // Grey-scale images. diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index 221eecd5b..750bd8719 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -2122,9 +2122,11 @@ TEST_F(LibYUVConvertTest, ABGRToAR30Row_Opt) { TESTPLANAR16TOB(I010, 2, 2, ARGB, 4, 4, 1, 2) TESTPLANAR16TOB(I010, 2, 2, ABGR, 4, 4, 1, 2) TESTPLANAR16TOB(I010, 2, 2, AR30, 4, 4, 1, 2) +TESTPLANAR16TOB(I010, 2, 2, AB30, 4, 4, 1, 2) TESTPLANAR16TOB(H010, 2, 2, ARGB, 4, 4, 1, 2) TESTPLANAR16TOB(H010, 2, 2, ABGR, 4, 4, 1, 2) TESTPLANAR16TOB(H010, 2, 2, AR30, 4, 4, 1, 2) +TESTPLANAR16TOB(H010, 2, 2, AB30, 4, 4, 1, 2) static int Clamp(int y) { if (y < 0) { @@ -2331,6 +2333,69 @@ TEST_F(LibYUVConvertTest, TestH010ToAR30) { free_aligned_buffer_page_end(ar30_pixels); } +// Test 10 bit YUV to 10 bit RGB +// Caveat: Result is near due to float rounding in expected result. +TEST_F(LibYUVConvertTest, TestH010ToAB30) { + const int kSize = 1024; + int histogram_b[1024]; + int histogram_g[1024]; + int histogram_r[1024]; + memset(histogram_b, 0, sizeof(histogram_b)); + memset(histogram_g, 0, sizeof(histogram_g)); + memset(histogram_r, 0, sizeof(histogram_r)); + + align_buffer_page_end(orig_yuv, kSize * 2 + kSize / 2 * 2 * 2); + align_buffer_page_end(ab30_pixels, kSize * 4); + uint16_t* orig_y = reinterpret_cast(orig_yuv); + uint16_t* orig_u = orig_y + kSize; + uint16_t* orig_v = orig_u + kSize / 2; + + // Test grey scale + for (int i = 0; i < kSize; ++i) { + orig_y[i] = i; + } + for (int i = 0; i < kSize / 2; ++i) { + orig_u[i] = 512; // 512 is 0. + orig_v[i] = 512; + } + + H010ToAB30(orig_y, 0, orig_u, 0, orig_v, 0, ab30_pixels, 0, kSize, 1); + + for (int i = 0; i < kSize; ++i) { + int r10 = reinterpret_cast(ab30_pixels)[i] & 1023; + int g10 = (reinterpret_cast(ab30_pixels)[i] >> 10) & 1023; + int b10 = (reinterpret_cast(ab30_pixels)[i] >> 20) & 1023; + int a2 = (reinterpret_cast(ab30_pixels)[i] >> 30) & 3; + ++histogram_b[b10]; + ++histogram_g[g10]; + ++histogram_r[r10]; + int expected_y = Clamp10(static_cast((i - 64) * 1.164f)); + EXPECT_NEAR(b10, expected_y, 4); + EXPECT_NEAR(g10, expected_y, 4); + EXPECT_NEAR(r10, expected_y, 4); + EXPECT_EQ(a2, 3); + } + + int count_b = 0; + int count_g = 0; + int count_r = 0; + for (int i = 0; i < kSize; ++i) { + if (histogram_b[i]) { + ++count_b; + } + if (histogram_g[i]) { + ++count_g; + } + if (histogram_r[i]) { + ++count_r; + } + } + printf("uniques: B %d, G, %d, R %d\n", count_b, count_g, count_r); + + free_aligned_buffer_page_end(orig_yuv); + free_aligned_buffer_page_end(ab30_pixels); +} + // Test 8 bit YUV to 10 bit RGB TEST_F(LibYUVConvertTest, TestH420ToAR30) { const int kSize = 256; diff --git a/unit_test/video_common_test.cc b/unit_test/video_common_test.cc index 3de4f4c24..4d89586e7 100644 --- a/unit_test/video_common_test.cc +++ b/unit_test/video_common_test.cc @@ -71,6 +71,7 @@ TEST_F(LibYUVBaseTest, TestFourCC) { EXPECT_TRUE(TestValidFourCC(FOURCC_BGRA, FOURCC_BPP_BGRA)); EXPECT_TRUE(TestValidFourCC(FOURCC_ABGR, FOURCC_BPP_ABGR)); EXPECT_TRUE(TestValidFourCC(FOURCC_AR30, FOURCC_BPP_AR30)); + EXPECT_TRUE(TestValidFourCC(FOURCC_AB30, FOURCC_BPP_AB30)); EXPECT_TRUE(TestValidFourCC(FOURCC_24BG, FOURCC_BPP_24BG)); EXPECT_TRUE(TestValidFourCC(FOURCC_RAW, FOURCC_BPP_RAW)); EXPECT_TRUE(TestValidFourCC(FOURCC_RGBA, FOURCC_BPP_RGBA));