From bcb6b7628306366b66d4f0b00d6ff09e11ca16e9 Mon Sep 17 00:00:00 2001 From: Sida Zhu Date: Tue, 1 Sep 2026 18:01:49 +0800 Subject: [PATCH] convert_from_argb: Add ARGB to NV16 and NV24 Add matrix and BT.601 wrapper APIs for converting ARGB to NV16 and NV24. Reuse the optimized ARGB Y and UV row functions, then merge the planar chroma rows into the interleaved destination plane. NV16 performs horizontal 2:1 chroma subsampling on every source row. NV24 preserves full-resolution 4:4:4 chroma. Both paths support odd widths, negative heights, and the existing matrix constants. Add tests that compare scalar and optimized paths at an odd width and height through the matrix API and its BT.601 wrapper. Bug: 537818862 Change-Id: Iddefc714a800cdec4dd1394ac7a52bf7b51fd350 Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8314188 Reviewed-by: Frank Barchard Reviewed-by: richard winterton --- include/libyuv/convert_from_argb.h | 54 +++- source/convert_from_argb.cc | 492 +++++++++++++++++++++++++++++ unit_test/convert_test.cc | 71 +++-- 3 files changed, 582 insertions(+), 35 deletions(-) diff --git a/include/libyuv/convert_from_argb.h b/include/libyuv/convert_from_argb.h index 0928bb53f..a394f8229 100644 --- a/include/libyuv/convert_from_argb.h +++ b/include/libyuv/convert_from_argb.h @@ -196,7 +196,7 @@ int ARGBToI444(const uint8_t* src_argb, int width, int height); -// RGB to I444 with matrix. See ArgbConstants at the top of this file for usage. +// ARGB to I444 with matrix. See ArgbConstants at the top of this file for usage. LIBYUV_API int ARGBToI444Matrix(const uint8_t* src_argb, int src_stride_argb, @@ -260,7 +260,7 @@ int ABGRToI422(const uint8_t* src_abgr, int width, int height); -// RGB to I444 with matrix. See ArgbConstants at the top of this file for usage. +// ARGB to I422 with matrix. See ArgbConstants at the top of this file for usage. LIBYUV_API int ARGBToI422Matrix(const uint8_t* src_argb, int src_stride_argb, @@ -408,7 +408,7 @@ int ARGBToNV12(const uint8_t* src_argb, int width, int height); -// RGB to NV12 with matrix. See ArgbConstants at the top of this file for usage. +// ARGB to NV12 with matrix. See ArgbConstants at the top of this file for usage. LIBYUV_API int ARGBToNV12Matrix(const uint8_t* src_argb, int src_stride_argb, @@ -420,7 +420,53 @@ int ARGBToNV12Matrix(const uint8_t* src_argb, int width, int height); -// RGB to NV21 with matrix. See ArgbConstants at the top of this file for usage. +// Convert ARGB To NV16. +LIBYUV_API +int ARGBToNV16(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + int width, + int height); + +// ARGB to NV16 with matrix. See ArgbConstants at the top of this file for usage. +LIBYUV_API +int ARGBToNV16Matrix(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + const struct ArgbConstants* argbconstants, + int width, + int height); + +// Convert ARGB To NV24. +LIBYUV_API +int ARGBToNV24(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + int width, + int height); + +// ARGB to NV24 with matrix. See ArgbConstants at the top of this file for usage. +LIBYUV_API +int ARGBToNV24Matrix(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + const struct ArgbConstants* argbconstants, + int width, + int height); + +// ARGB to NV21 with matrix. See ArgbConstants at the top of this file for usage. LIBYUV_API int ARGBToNV21Matrix(const uint8_t* src_argb, int src_stride_argb, diff --git a/source/convert_from_argb.cc b/source/convert_from_argb.cc index c8834a16a..f87c5c054 100644 --- a/source/convert_from_argb.cc +++ b/source/convert_from_argb.cc @@ -638,6 +638,498 @@ int ARGBToNV12Matrix(const uint8_t* src_argb, return 0; } +LIBYUV_API +int ARGBToNV16(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + int width, + int height) { + return ARGBToNV16Matrix(src_argb, src_stride_argb, dst_y, dst_stride_y, + dst_uv, dst_stride_uv, &kArgbI601Constants, width, + height); +} + +LIBYUV_API +int ARGBToNV16Matrix(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + const struct ArgbConstants* argbconstants, + int width, + int height) { + int y; + int halfwidth = (width >> 1) + (width & 1); + void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width, + const struct ArgbConstants* c) = ARGBToYMatrixRow_C; + void (*ARGBToUVMatrixRow)(const uint8_t* src_argb, int src_stride_argb, + uint8_t* dst_u, uint8_t* dst_v, int width, + const struct ArgbConstants* c) = + ARGBToUVMatrixRow_C; + +#if defined(HAS_ARGBTOYMATRIXROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW; + if (IS_ALIGNED(width, 64)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_NEON; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD) + if (TestCpuFlag(kCpuHasNeonDotProd)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2; + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SME; + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_LSX; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_LASX) + if (TestCpuFlag(kCpuHasLASX)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX; + if (IS_ALIGNED(width, 32)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_LASX; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_RVV; + } +#endif + +#if defined(HAS_ARGBTOUVMATRIXROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_NEON_I8MM) + if (TestCpuFlag(kCpuHasNEON) && TestCpuFlag(kCpuHasNeonI8MM)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_NEON_I8MM; + if (IS_ALIGNED(width, 16)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_NEON_I8MM; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + if (IS_ALIGNED(width, 2)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_SVE2; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + if (IS_ALIGNED(width, 2)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_SME; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_SSSE3; + if (IS_ALIGNED(width, 8)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_SSSE3; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX2; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_Any_AVX512BW; + if (IS_ALIGNED(width, 64)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_AVX512BW; + } + } +#endif +#if defined(HAS_ARGBTOUVMATRIXROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + ARGBToUVMatrixRow = ARGBToUVMatrixRow_RVV; + } +#endif + void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v, + uint8_t* dst_uv, int width) = MergeUVRow_C; + if (!src_argb || !dst_y || !dst_uv || !argbconstants || width <= 0 || + height == 0 || height == INT_MIN) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb; + src_stride_argb = -src_stride_argb; + } +#if defined(HAS_MERGEUVROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + MergeUVRow = MergeUVRow_Any_SSE2; + if (IS_ALIGNED(halfwidth, 16)) { + MergeUVRow = MergeUVRow_SSE2; + } + } +#endif +#if defined(HAS_MERGEUVROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + MergeUVRow = MergeUVRow_Any_AVX2; + if (IS_ALIGNED(halfwidth, 32)) { + MergeUVRow = MergeUVRow_AVX2; + } + } +#endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(halfwidth, 32)) { + MergeUVRow = MergeUVRow_AVX512BW; + } + } +#endif +#if defined(HAS_MERGEUVROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + MergeUVRow = MergeUVRow_Any_NEON; + if (IS_ALIGNED(halfwidth, 16)) { + MergeUVRow = MergeUVRow_NEON; + } + } +#endif +#if defined(HAS_MERGEUVROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + MergeUVRow = MergeUVRow_SVE2; + } +#endif +#if defined(HAS_MERGEUVROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + MergeUVRow = MergeUVRow_SME; + } +#endif +#if defined(HAS_MERGEUVROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + MergeUVRow = MergeUVRow_Any_LSX; + if (IS_ALIGNED(halfwidth, 16)) { + MergeUVRow = MergeUVRow_LSX; + } + } +#endif +#if defined(HAS_MERGEUVROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + MergeUVRow = MergeUVRow_RVV; + } +#endif + + size_t row_size = (static_cast(halfwidth) + 31) & + ~static_cast(31); + if (row_size > SIZE_MAX / 2) { + return -1; + } + align_buffer_64(row_u, row_size * 2); + if (!row_u) + return 1; + uint8_t* row_v = row_u + row_size; + + for (y = 0; y < height; ++y) { + ARGBToUVMatrixRow(src_argb, 0, row_u, row_v, width, argbconstants); + ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants); + MergeUVRow(row_u, row_v, dst_uv, halfwidth); + src_argb += src_stride_argb; + dst_y += dst_stride_y; + dst_uv += dst_stride_uv; + } + free_aligned_buffer_64(row_u); + return 0; +} + +LIBYUV_API +int ARGBToNV24(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + int width, + int height) { + return ARGBToNV24Matrix(src_argb, src_stride_argb, dst_y, dst_stride_y, + dst_uv, dst_stride_uv, &kArgbI601Constants, width, + height); +} + +LIBYUV_API +int ARGBToNV24Matrix(const uint8_t* src_argb, + int src_stride_argb, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_uv, + int dst_stride_uv, + const struct ArgbConstants* argbconstants, + int width, + int height) { + int y; + void (*ARGBToYMatrixRow)(const uint8_t* src_argb, uint8_t* dst_y, int width, + const struct ArgbConstants* c) = ARGBToYMatrixRow_C; + void (*ARGBToUV444MatrixRow)( + const uint8_t* src_argb, uint8_t* dst_u, uint8_t* dst_v, int width, + const struct ArgbConstants* c) = ARGBToUV444MatrixRow_C; + +#if defined(HAS_ARGBTOYMATRIXROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_SSSE3; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SSSE3; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_AVX2; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_AVX512BW; + if (IS_ALIGNED(width, 64)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_AVX512BW; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_NEON; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_NEON_DOTPROD) + if (TestCpuFlag(kCpuHasNeonDotProd)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_NEON_DotProd; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_NEON_DotProd; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SVE2; + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_SME; + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LSX; + if (IS_ALIGNED(width, 16)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_LSX; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_LASX) + if (TestCpuFlag(kCpuHasLASX)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_Any_LASX; + if (IS_ALIGNED(width, 32)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_LASX; + } + } +#endif +#if defined(HAS_ARGBTOYMATRIXROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + ARGBToYMatrixRow = ARGBToYMatrixRow_RVV; + } +#endif + +#if defined(HAS_ARGBTOUV444MATRIXROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_Any_SSSE3; + if (IS_ALIGNED(width, 16)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_SSSE3; + } + } +#endif +#if defined(HAS_ARGBTOUV444MATRIXROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_AVX2; + } + } +#endif +#if defined(HAS_ARGBTOUV444MATRIXROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_Any_AVX512BW; + if (IS_ALIGNED(width, 64)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_AVX512BW; + } + } +#endif +#if defined(HAS_ARGBTOUV444MATRIXROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_Any_NEON; + if (IS_ALIGNED(width, 8)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_NEON; + } + } +#endif +#if defined(HAS_ARGBTOUV444MATRIXROW_NEON_I8MM) + if (TestCpuFlag(kCpuHasNeonI8MM)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_Any_NEON_I8MM; + if (IS_ALIGNED(width, 8)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_NEON_I8MM; + } + } +#endif +#if defined(HAS_ARGBTOUV444MATRIXROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + ARGBToUV444MatrixRow = ARGBToUV444MatrixRow_RVV; + } +#endif + void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v, + uint8_t* dst_uv, int width) = MergeUVRow_C; + if (!src_argb || !dst_y || !dst_uv || !argbconstants || width <= 0 || + height == 0 || height == INT_MIN) { + return -1; + } + // Negative height means invert the image. + if (height < 0) { + height = -height; + src_argb = src_argb + (ptrdiff_t)(height - 1) * src_stride_argb; + src_stride_argb = -src_stride_argb; + } +#if defined(HAS_MERGEUVROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + MergeUVRow = MergeUVRow_Any_SSE2; + if (IS_ALIGNED(width, 16)) { + MergeUVRow = MergeUVRow_SSE2; + } + } +#endif +#if defined(HAS_MERGEUVROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + MergeUVRow = MergeUVRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + MergeUVRow = MergeUVRow_AVX2; + } + } +#endif +#if defined(HAS_MERGEUVROW_AVX512BW) + if (TestCpuFlag(kCpuHasAVX512BW)) { + MergeUVRow = MergeUVRow_Any_AVX512BW; + if (IS_ALIGNED(width, 32)) { + MergeUVRow = MergeUVRow_AVX512BW; + } + } +#endif +#if defined(HAS_MERGEUVROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + MergeUVRow = MergeUVRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + MergeUVRow = MergeUVRow_NEON; + } + } +#endif +#if defined(HAS_MERGEUVROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + MergeUVRow = MergeUVRow_SVE2; + } +#endif +#if defined(HAS_MERGEUVROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + MergeUVRow = MergeUVRow_SME; + } +#endif +#if defined(HAS_MERGEUVROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + MergeUVRow = MergeUVRow_Any_LSX; + if (IS_ALIGNED(width, 16)) { + MergeUVRow = MergeUVRow_LSX; + } + } +#endif +#if defined(HAS_MERGEUVROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + MergeUVRow = MergeUVRow_RVV; + } +#endif + + size_t row_size = (static_cast(width) + 31) & + ~static_cast(31); + if (row_size > SIZE_MAX / 2) { + return -1; + } + align_buffer_64(row_u, row_size * 2); + if (!row_u) + return 1; + uint8_t* row_v = row_u + row_size; + + for (y = 0; y < height; ++y) { + ARGBToUV444MatrixRow(src_argb, row_u, row_v, width, argbconstants); + ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants); + MergeUVRow(row_u, row_v, dst_uv, width); + src_argb += src_stride_argb; + dst_y += dst_stride_y; + dst_uv += dst_stride_uv; + } + free_aligned_buffer_64(row_u); + return 0; +} + LIBYUV_API int ARGBToNV21Matrix(const uint8_t* src_argb, int src_stride_argb, diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index 211b13d5d..fa7314cd7 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -834,6 +834,8 @@ TESTATOPLANARA(ARGB, 4, 1, I420Alpha, 2, 2) TESTATOBP(ARGB, 1, 4, NV12, 2, 2) TESTATOBP(ARGB, 1, 4, NV21, 2, 2) +TESTATOBP(ARGB, 1, 4, NV16, 2, 1) +TESTATOBP(ARGB, 1, 4, NV24, 1, 1) TESTATOBP(ABGR, 1, 4, NV12, 2, 2) TESTATOBP(ABGR, 1, 4, NV21, 2, 2) TESTATOBP(YUY2, 2, 4, NV12, 2, 2) @@ -841,6 +843,44 @@ TESTATOBP(UYVY, 2, 4, NV12, 2, 2) TESTATOBP(AYUV, 1, 4, NV12, 2, 2) TESTATOBP(AYUV, 1, 4, NV21, 2, 2) +// Matrix API with I601 constants matches the non-matrix wrapper. +#define TESTATOBPMATRIX(FMT_A, BPP_A, FMT_B, SUBSAMP_X, SUBSAMP_Y) \ + TEST_F(LibYUVConvertTest, Test##FMT_A##To##FMT_B##Matrix) { \ + const int kWidth = 16; \ + const int kHeight = 16; \ + const int kStrideUV = SUBSAMPLE(kWidth, SUBSAMP_X); \ + const int kHeightUV = SUBSAMPLE(kHeight, SUBSAMP_Y); \ + align_buffer_page_end(src_argb, kWidth * kHeight * BPP_A); \ + align_buffer_page_end(dst_y, kWidth * kHeight); \ + align_buffer_page_end(dst_uv, kStrideUV * 2 * kHeightUV); \ + align_buffer_page_end(ref_y, kWidth * kHeight); \ + align_buffer_page_end(ref_uv, kStrideUV * 2 * kHeightUV); \ + \ + MemRandomize(src_argb, kWidth * kHeight * BPP_A); \ + \ + FMT_A##To##FMT_B##Matrix(src_argb, kWidth * BPP_A, dst_y, kWidth, dst_uv, \ + kStrideUV * 2, &kArgbI601Constants, kWidth, \ + kHeight); \ + FMT_A##To##FMT_B(src_argb, kWidth * BPP_A, ref_y, kWidth, ref_uv, \ + kStrideUV * 2, kWidth, kHeight); \ + for (int i = 0; i < kWidth * kHeight; ++i) { \ + ASSERT_EQ(dst_y[i], ref_y[i]); \ + } \ + for (int i = 0; i < kStrideUV * 2 * kHeightUV; ++i) { \ + ASSERT_EQ(dst_uv[i], ref_uv[i]); \ + } \ + \ + free_aligned_buffer_page_end(src_argb); \ + free_aligned_buffer_page_end(dst_y); \ + free_aligned_buffer_page_end(dst_uv); \ + free_aligned_buffer_page_end(ref_y); \ + free_aligned_buffer_page_end(ref_uv); \ + } + +TESTATOBPMATRIX(ARGB, 4, NV12, 2, 2) +TESTATOBPMATRIX(ARGB, 4, NV16, 2, 1) +TESTATOBPMATRIX(ARGB, 4, NV24, 1, 1) + #if !defined(LEAN_TESTS) #ifdef HAVE_JPEG @@ -2420,37 +2460,6 @@ TEST_F(LibYUVConvertTest, TestRGB24ToNV12) { free_aligned_buffer_page_end(ref_uv); } -TEST_F(LibYUVConvertTest, TestARGBToNV12Matrix) { - const int kWidth = 16; - const int kHeight = 16; - align_buffer_page_end(src_argb, kWidth * kHeight * 4); - align_buffer_page_end(dst_y, kWidth * kHeight); - align_buffer_page_end(dst_uv, kWidth * kHeight / 2); - - MemRandomize(src_argb, kWidth * kHeight * 4); - - // BT.601 - ARGBToNV12Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_uv, kWidth, - &kArgbI601Constants, kWidth, kHeight); - // Verify against non-matrix version - align_buffer_page_end(ref_y, kWidth * kHeight); - align_buffer_page_end(ref_uv, kWidth * kHeight / 2); - ARGBToNV12(src_argb, kWidth * 4, ref_y, kWidth, ref_uv, kWidth, kWidth, - kHeight); - for (int i = 0; i < kWidth * kHeight; ++i) { - ASSERT_EQ(dst_y[i], ref_y[i]); - } - for (int i = 0; i < kWidth * kHeight / 2; ++i) { - ASSERT_EQ(dst_uv[i], ref_uv[i]); - } - - free_aligned_buffer_page_end(src_argb); - free_aligned_buffer_page_end(dst_y); - free_aligned_buffer_page_end(dst_uv); - free_aligned_buffer_page_end(ref_y); - free_aligned_buffer_page_end(ref_uv); -} - TEST_F(LibYUVConvertTest, TestABGRToNV12Matrix) { const int kWidth = 16; const int kHeight = 16;