diff --git a/README.chromium b/README.chromium index 8f5266f1f..eb2ceabe8 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: http://code.google.com/p/libyuv/ -Version: 274 +Version: 275 License: BSD License File: LICENSE diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h index c1a1cdd74..4850dc622 100644 --- a/include/libyuv/planar_functions.h +++ b/include/libyuv/planar_functions.h @@ -57,6 +57,11 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, uint8* dst_argb, int dst_stride_argb, int width, int height); +// Convert UYVY to ARGB. +int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_argb, int dst_stride_argb, + int width, int height); + // Convert I422 to ARGB. int I422ToARGB(const uint8* src_y, int src_stride_y, const uint8* src_u, int src_stride_u, @@ -101,6 +106,7 @@ int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, // Palindromes. #define ARGBToBGRA BGRAToARGB +#define ARGBToABGR ABGRToARGB // Convert BGRA to ARGB. Also used for ARGB to BGRA. int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra, @@ -117,6 +123,11 @@ int ARGBToRAW(const uint8* src_argb, int src_stride_argb, uint8* dst_rgb, int dst_stride_rgb, int width, int height); +// Convert ARGB To RGB565. +int ARGBToRGB565(const uint8* src_argb, int src_stride_argb, + uint8* dst_rgb565, int dst_stride_rgb565, + int width, int height); + // Convert ARGB to I400. int ARGBToI400(const uint8* src_argb, int src_stride_argb, uint8* dst_y, int dst_stride_y, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index 8f99aaa80..5a7c7dabd 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 274 +#define LIBYUV_VERSION 275 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/source/planar_functions.cc b/source/planar_functions.cc index 9af76b690..51f928358 100644 --- a/source/planar_functions.cc +++ b/source/planar_functions.cc @@ -539,6 +539,38 @@ int ARGBToRAW(const uint8* src_argb, int src_stride_argb, return 0; } +// Convert ARGB To RGB565. +int ARGBToRGB565(const uint8* src_argb, int src_stride_argb, + uint8* dst_rgb565, int dst_stride_rgb565, + 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 (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int pix) = + ARGBToRGB565Row_C; +#if defined(HAS_ARGBTORGB565ROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3) && + IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) { + if (width * 3 <= kMaxStride) { + ARGBToRGB565Row = ARGBToRGB565Row_Any_SSSE3; + } + if (IS_ALIGNED(width, 16) && + IS_ALIGNED(dst_rgb565, 16) && IS_ALIGNED(dst_stride_rgb565, 16)) { + ARGBToRGB565Row = ARGBToRGB565Row_SSSE3; + } + } +#endif + + for (int y = 0; y < height; ++y) { + ARGBToRGB565Row(src_argb, dst_rgb565, width); + src_argb += src_stride_argb; + dst_rgb565 += dst_stride_rgb565; + } + return 0; +} + // Convert NV12 to ARGB. int NV12ToARGB(const uint8* src_y, int src_stride_y, const uint8* src_uv, int src_stride_uv, @@ -665,6 +697,72 @@ int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, return 0; } +// Convert UYVY to ARGB. +int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_argb, int dst_stride_argb, + int width, int height) { + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; + src_stride_uyvy = -src_stride_uyvy; + } + void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, + uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C; + void (*UYVYToYRow)(const uint8* src_uyvy, + uint8* dst_y, int pix) = UYVYToYRow_C; +#if defined(HAS_UYVYTOYROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + if (width > 16) { + UYVYToUVRow = UYVYToUVRow_Any_SSE2; + UYVYToYRow = UYVYToYRow_Any_SSE2; + } + if (IS_ALIGNED(width, 16)) { + UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2; + UYVYToYRow = UYVYToYRow_Unaligned_SSE2; + if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) { + UYVYToUVRow = UYVYToUVRow_SSE2; + UYVYToYRow = UYVYToYRow_SSE2; + } + } + } +#endif + void (*I420ToARGBRow)(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* argb_buf, + int width) = I420ToARGBRow_C; +#if defined(HAS_I420TOARGBROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + I420ToARGBRow = I420ToARGBRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + I420ToARGBRow = I420ToARGBRow_NEON; + } + } +#elif defined(HAS_I420TOARGBROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { + I420ToARGBRow = I420ToARGBRow_Any_SSSE3; + if (IS_ALIGNED(width, 8) && + IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { + I420ToARGBRow = I420ToARGBRow_SSSE3; + } + } +#endif + + SIMD_ALIGNED(uint8 rowy[kMaxStride]); + SIMD_ALIGNED(uint8 rowu[kMaxStride]); + SIMD_ALIGNED(uint8 rowv[kMaxStride]); + + for (int y = 0; y < height; ++y) { + UYVYToUVRow(src_uyvy, src_stride_uyvy, rowu, rowv, width); + UYVYToYRow(src_uyvy, rowy, width); + I420ToARGBRow(rowy, rowu, rowv, dst_argb, width); + src_uyvy += src_stride_uyvy; + dst_argb += dst_stride_argb; + } + return 0; +} + // Convert NV12 to RGB565. int NV12ToRGB565(const uint8* src_y, int src_stride_y, const uint8* src_uv, int src_stride_uv, diff --git a/source/row_common.cc b/source/row_common.cc index cb1a6e2c7..cfb1dc52d 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -110,10 +110,10 @@ void ARGB1555ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int width) { void ARGB4444ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int width) { for (int x = 0; x < width; ++x) { - uint8 a = src_rgb[1] >> 4; - uint8 r = src_rgb[1] & 0x0f; - uint8 g = src_rgb[0] >> 4; uint8 b = src_rgb[0] & 0x0f; + uint8 g = src_rgb[0] >> 4; + uint8 r = src_rgb[1] & 0x0f; + uint8 a = src_rgb[1] >> 4; dst_argb[0] = (b << 4) | b; dst_argb[1] = (g << 4) | g; dst_argb[2] = (r << 4) | r; @@ -166,7 +166,7 @@ void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { uint8 b = src_argb[0] >> 3; uint8 g = src_argb[1] >> 3; uint8 r = src_argb[2] >> 3; - uint8 a = src_argb[2] >> 7; + uint8 a = src_argb[3] >> 7; *reinterpret_cast(dst_rgb) = (a << 15) | (r << 10) | (g << 5) | b; dst_rgb += 2; src_argb += 4; @@ -178,7 +178,7 @@ void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int width) { uint8 b = src_argb[0] >> 4; uint8 g = src_argb[1] >> 4; uint8 r = src_argb[2] >> 4; - uint8 a = src_argb[2] >> 4; + uint8 a = src_argb[3] >> 4; *reinterpret_cast(dst_rgb) = (a << 12) | (r << 8) | (g << 4) | b; dst_rgb += 2; src_argb += 4; diff --git a/unit_test/planar_test.cc b/unit_test/planar_test.cc index 1ae3b736f..799b1652e 100644 --- a/unit_test/planar_test.cc +++ b/unit_test/planar_test.cc @@ -94,16 +94,19 @@ TEST_F(libyuvTest, I420To##FMT##_CvsOPT) { \ dst_rgb_c, src_width * BPP, \ src_width, src_height); \ MaskCpuFlags(-1); \ - I420To##FMT(src_y, src_width, \ - src_u, src_width >> 1, \ - src_v, src_width >> 1, \ - dst_rgb_opt, src_width * BPP, \ - src_width, src_height); \ + const int runs = 1000; \ + for (int i = 0; i < runs; ++i) { \ + I420To##FMT(src_y, src_width, \ + src_u, src_width >> 1, \ + src_v, src_width >> 1, \ + dst_rgb_opt, src_width * BPP, \ + src_width, src_height); \ + } \ int err = 0; \ for (int i = 0; i < src_height; ++i) { \ for (int j = 0; j < src_width * BPP; ++j) { \ - int diff = static_cast(dst_rgb_c[i * src_width * BPP + j]) - \ - static_cast(dst_rgb_opt[i * src_width * BPP + j]); \ + int diff = static_cast(dst_rgb_c[i * src_width * BPP + j]) - \ + static_cast(dst_rgb_opt[i * src_width * BPP + j]); \ if (abs(diff) > 2) \ err++; \ } \ @@ -122,34 +125,36 @@ TESTI420TO(ABGR, 4) TESTI420TO(RAW, 3) TESTI420TO(RGB24, 3) TESTI420TO(RGB565, 2) -// TODO(fbarchard): Add 555/4444 unittests once passing. -//TESTI420TO(ARGB1555, 2) -//TESTI420TO(ARGB4444, 2) +TESTI420TO(ARGB1555, 2) +TESTI420TO(ARGB4444, 2) -#define TESTARGBTO(FMT, BPP) \ -TEST_F(libyuvTest, ARGBTo##FMT##_CvsOPT) { \ +#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 * 4); \ - align_buffer_16(dst_rgb_c, (src_width * BPP) * src_height); \ - align_buffer_16(dst_rgb_opt, (src_width * BPP) * src_height); \ + 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); \ srandom(time(NULL)); \ for (int i = 0; i < src_height; ++i) \ - for (int j = 0; j < src_width * 4; ++j) \ - src_argb[(i * src_width * 4) + j] = (random() & 0xff); \ + for (int j = 0; j < src_width * BPP_A; ++j) \ + src_argb[(i * src_width * BPP_A) + j] = (random() & 0xff); \ MaskCpuFlags(kCpuInitialized); \ - ARGBTo##FMT(src_argb, src_width * 4, \ - dst_rgb_c, src_width * BPP, \ + ##FMT_A##To##FMT_B(src_argb, src_width * BPP_A, \ + dst_rgb_c, src_width * BPP_B, \ src_width, src_height); \ MaskCpuFlags(-1); \ - ARGBTo##FMT(src_argb, src_width * 4, \ - dst_rgb_opt, src_width * BPP, \ - src_width, src_height); \ + 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); \ + } \ int err = 0; \ for (int i = 0; i < src_height; ++i) { \ - for (int j = 0; j < src_width * BPP; ++j) { \ - int diff = static_cast(dst_rgb_c[i * src_width * BPP + j]) - \ - static_cast(dst_rgb_opt[i * src_width * BPP + j]); \ + 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++; \ } \ @@ -160,14 +165,17 @@ TEST_F(libyuvTest, ARGBTo##FMT##_CvsOPT) { \ free_aligned_buffer_16(dst_rgb_opt) \ } -// TODO(fbarchard): Expose all ARGBToRGB functions and test. -//TESTARGBTO(BGRA, 4) -//TESTARGBTO(ABGR, 4) -TESTARGBTO(RAW, 3) -TESTARGBTO(RGB24, 3) -//TESTARGBTO(RGB565, 2) -//TESTARGBTO(ARGB1555, 2) -//TESTARGBTO(ARGB4444, 2) +// TODO(fbarchard): Expose more ARGBToRGB functions and test. +TESTATOB(ARGB, 4, BGRA, 4) +TESTATOB(ARGB, 4, ABGR, 4) +TESTATOB(ARGB, 4, RAW, 3) +TESTATOB(ARGB, 4, RGB24, 3) +TESTATOB(ARGB, 4, RGB565, 2) +//TESTATOB(ARGB, 4, ARGB1555, 2) +//TESTATOB(ARGB, 4, ARGB4444, 2) + +TESTATOB(YUY2, 2, ARGB, 4) +TESTATOB(UYVY, 2, ARGB, 4) TEST_F(libyuvTest, TestAttenuate) { SIMD_ALIGNED(uint8 orig_pixels[256][4]);