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 <fbarchard@google.com>
Reviewed-by: richard winterton <rrwinterton@gmail.com>
This commit is contained in:
Sida Zhu 2026-09-01 18:01:49 +08:00 committed by Frank Barchard
parent af714f0810
commit bcb6b76283
3 changed files with 582 additions and 35 deletions

View File

@ -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,

View File

@ -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<size_t>(halfwidth) + 31) &
~static_cast<size_t>(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<size_t>(width) + 31) &
~static_cast<size_t>(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,

View File

@ -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;