From 2fcc1272dd3eb27e1363e7e7218ef192d2a4e080 Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Tue, 1 Sep 2026 13:39:10 -0700 Subject: [PATCH] Convert8To16 takes bits instead of scale. - NV16/24 FOURCC and document - Rotate take uint8* for ubsan Bug: 537818862 Change-Id: I2bc7109abaffe2464e031e33c22296c007077d82 Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8339427 Commit-Queue: Frank Barchard Reviewed-by: richard winterton --- README.chromium | 2 +- docs/formats.md | 4 +- include/libyuv/planar_functions.h | 4 +- include/libyuv/row.h | 22 +-- include/libyuv/version.h | 2 +- include/libyuv/video_common.h | 6 +- source/convert_from.cc | 37 +++++ source/convert_to_argb.cc | 232 ++++++++++++++++++++++++++++++ source/convert_to_i420.cc | 174 ++++++++++++++++++++++ source/planar_functions.cc | 15 +- source/rotate_common.cc | 55 +++---- source/row_any.cc | 6 +- source/row_common.cc | 30 ++-- source/row_gcc.cc | 17 +-- source/row_neon.cc | 10 +- source/row_neon64.cc | 9 +- source/row_rvv.cc | 4 +- source/row_sme.cc | 8 +- source/row_win.cc | 15 +- unit_test/convert_argb_test.cc | 36 +++++ unit_test/convert_test.cc | 94 ++++++++++++ unit_test/planar_test.cc | 12 +- unit_test/video_common_test.cc | 2 + 23 files changed, 677 insertions(+), 119 deletions(-) diff --git a/README.chromium b/README.chromium index 5eb8a85c5..9eacdccaf 100644 --- a/README.chromium +++ b/README.chromium @@ -1,6 +1,6 @@ Name: libyuv URL: https://chromium.googlesource.com/libyuv/libyuv/ -Version: 1967 +Version: 1968 Revision: DEPS License: BSD-3-Clause License File: LICENSE diff --git a/docs/formats.md b/docs/formats.md index b0cae5a71..1c7299a9e 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -38,13 +38,15 @@ This is how OSX formats map to libyuv The following is extracted from video_common.h as a complete list of formats supported by libyuv. enum FourCC { - // 10 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + // 12 Primary YUV formats: 5 planar, 4 biplanar, 2 packed. FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), FOURCC_I400 = FOURCC('I', '4', '0', '0'), FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), + FOURCC_NV16 = FOURCC('N', 'V', '1', '6'), + FOURCC_NV24 = FOURCC('N', 'V', '2', '4'), FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), FOURCC_H010 = FOURCC('H', '0', '1', '0'), // unofficial fourcc. 10 bit lsb diff --git a/include/libyuv/planar_functions.h b/include/libyuv/planar_functions.h index e790699b6..7429e8a87 100644 --- a/include/libyuv/planar_functions.h +++ b/include/libyuv/planar_functions.h @@ -51,12 +51,14 @@ void Convert16To8Plane(const uint16_t* src_y, int width, int height); +// Convert 8 bit Y to 10/12/16 bit. +// "bits" accepts bit depths (10, 12, 16) or legacy scale values (1024, 4096, 65536). LIBYUV_API void Convert8To16Plane(const uint8_t* src_y, int src_stride_y, uint16_t* dst_y, int dst_stride_y, - int scale, // 1024 for 10 bits + int bits, // 10, 12, 16 bits (or 1024, 4096, 65536 scale) int width, int height); diff --git a/include/libyuv/row.h b/include/libyuv/row.h index 533734e6f..9744ff121 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -3572,47 +3572,47 @@ void DivideRow_16_Any_NEON(const uint16_t* src_ptr, void Convert8To16Row_C(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_SSE2(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_AVX2(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_AVX512BW(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_Any_SSE2(const uint8_t* src_ptr, uint16_t* dst_ptr, - int scale, + int bits, int width); void Convert8To16Row_Any_AVX2(const uint8_t* src_ptr, uint16_t* dst_ptr, - int scale, + int bits, int width); void Convert8To16Row_Any_AVX512BW(const uint8_t* src_ptr, uint16_t* dst_ptr, - int scale, + int bits, int width); void Convert8To16Row_NEON(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_Any_NEON(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_SME(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert8To16Row_RVV(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width); void Convert16To8Row_C(const uint16_t* src_y, diff --git a/include/libyuv/version.h b/include/libyuv/version.h index f411b327a..80581b28f 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 1968 +#define LIBYUV_VERSION 1969 #endif // INCLUDE_LIBYUV_VERSION_H_ diff --git a/include/libyuv/video_common.h b/include/libyuv/video_common.h index d39e4dd0c..0cdfd5217 100644 --- a/include/libyuv/video_common.h +++ b/include/libyuv/video_common.h @@ -53,13 +53,15 @@ extern "C" { // Secondary formats are converted in 2 steps. // Auxilliary formats call primary converters. enum FourCC { - // 10 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + // 12 Primary YUV formats: 5 planar, 4 biplanar, 2 packed. FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), FOURCC_I400 = FOURCC('I', '4', '0', '0'), FOURCC_NV21 = FOURCC('N', 'V', '2', '1'), FOURCC_NV12 = FOURCC('N', 'V', '1', '2'), + FOURCC_NV16 = FOURCC('N', 'V', '1', '6'), + FOURCC_NV24 = FOURCC('N', 'V', '2', '4'), FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'), FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'), FOURCC_I010 = FOURCC('I', '0', '1', '0'), // bt.601 10 bit 420 @@ -158,6 +160,8 @@ enum FourCCBpp { FOURCC_BPP_I400 = 8, FOURCC_BPP_NV21 = 12, FOURCC_BPP_NV12 = 12, + FOURCC_BPP_NV16 = 16, + FOURCC_BPP_NV24 = 24, FOURCC_BPP_YUY2 = 16, FOURCC_BPP_UYVY = 16, FOURCC_BPP_M420 = 12, // deprecated diff --git a/source/convert_from.cc b/source/convert_from.cc index bed7ddefa..7e5a24443 100644 --- a/source/convert_from.cc +++ b/source/convert_from.cc @@ -814,6 +814,43 @@ int ConvertFromI420(const uint8_t* y, height); break; } + case FOURCC_NV16: { + int dst_y_stride = dst_sample_stride ? dst_sample_stride : width; + int dst_uv_stride = dst_sample_stride ? dst_sample_stride : width; + uint8_t* dst_uv = dst_sample + (ptrdiff_t)dst_y_stride * height; + int halfwidth = (width + 1) / 2; + int halfheight = (height + 1) / 2; + CopyPlane(y, y_stride, dst_sample, dst_y_stride, width, height); + MergeUVPlane(u, u_stride, v, v_stride, dst_uv, dst_uv_stride * 2, + halfwidth, halfheight); + if (height > 1) { + MergeUVPlane(u, u_stride, v, v_stride, dst_uv + dst_uv_stride, + dst_uv_stride * 2, halfwidth, height / 2); + } + r = 0; + break; + } + case FOURCC_NV24: { + int dst_y_stride = dst_sample_stride ? dst_sample_stride : width; + int dst_uv_stride = dst_sample_stride ? dst_sample_stride * 2 : width * 2; + uint8_t* dst_uv = dst_sample + (ptrdiff_t)dst_y_stride * height; + align_buffer_64(temp_u, (size_t)width * height); + align_buffer_64(temp_v, (size_t)width * height); + if (!temp_u || !temp_v) { + free_aligned_buffer_64(temp_u); + free_aligned_buffer_64(temp_v); + return 1; + } + r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample, + dst_y_stride, temp_u, width, temp_v, width, width, height); + if (r == 0) { + MergeUVPlane(temp_u, width, temp_v, width, dst_uv, dst_uv_stride, width, + height); + } + free_aligned_buffer_64(temp_u); + free_aligned_buffer_64(temp_v); + break; + } // Triplanar formats case FOURCC_I420: case FOURCC_YV12: { diff --git a/source/convert_to_argb.cc b/source/convert_to_argb.cc index 997652fe3..16b538a2e 100644 --- a/source/convert_to_argb.cc +++ b/source/convert_to_argb.cc @@ -28,6 +28,221 @@ namespace libyuv { extern "C" { #endif +static int NV16ToARGB(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_uv, + int src_stride_uv, + uint8_t* dst_argb, + int dst_stride_argb, + int width, + int height) { + int y; + void (*NV12ToARGBRow)( + const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf, + const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C; + if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0 || + height == INT_MIN) { + return -1; + } + if (height < 0) { + height = -height; + dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb; + dst_stride_argb = -dst_stride_argb; + } +#if defined(HAS_NV12TOARGBROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; + if (IS_ALIGNED(width, 8)) { + NV12ToARGBRow = NV12ToARGBRow_SSSE3; + } + } +#endif +#if defined(HAS_NV12TOARGBROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + NV12ToARGBRow = NV12ToARGBRow_Any_AVX2; + if (IS_ALIGNED(width, 16)) { + NV12ToARGBRow = NV12ToARGBRow_AVX2; + } + } +#endif +#if defined(HAS_NV12TOARGBROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + NV12ToARGBRow = NV12ToARGBRow_Any_NEON; + if (IS_ALIGNED(width, 8)) { + NV12ToARGBRow = NV12ToARGBRow_NEON; + } + } +#endif +#if defined(HAS_NV12TOARGBROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + NV12ToARGBRow = NV12ToARGBRow_SVE2; + } +#endif +#if defined(HAS_NV12TOARGBROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + NV12ToARGBRow = NV12ToARGBRow_SME; + } +#endif +#if defined(HAS_NV12TOARGBROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + NV12ToARGBRow = NV12ToARGBRow_Any_LSX; + if (IS_ALIGNED(width, 8)) { + NV12ToARGBRow = NV12ToARGBRow_LSX; + } + } +#endif +#if defined(HAS_NV12TOARGBROW_LASX) + if (TestCpuFlag(kCpuHasLASX)) { + NV12ToARGBRow = NV12ToARGBRow_Any_LASX; + if (IS_ALIGNED(width, 16)) { + NV12ToARGBRow = NV12ToARGBRow_LASX; + } + } +#endif +#if defined(HAS_NV12TOARGBROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + NV12ToARGBRow = NV12ToARGBRow_RVV; + } +#endif + + for (y = 0; y < height; ++y) { + NV12ToARGBRow(src_y, src_uv, dst_argb, &kYuvI601Constants, width); + dst_argb += dst_stride_argb; + src_y += src_stride_y; + src_uv += src_stride_uv; + } + return 0; +} + +static int NV24ToARGB(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_uv, + int src_stride_uv, + uint8_t* dst_argb, + int dst_stride_argb, + int width, + int height) { + int y; + void (*I444ToARGBRow)( + const uint8_t* y_buf, const uint8_t* u_buf, const uint8_t* v_buf, + uint8_t* rgb_buf, const struct YuvConstants* yuvconstants, int width) = + I444ToARGBRow_C; + void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, + int width) = SplitUVRow_C; + if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0 || + height == INT_MIN) { + return -1; + } + if (height < 0) { + height = -height; + dst_argb = dst_argb + (ptrdiff_t)(height - 1) * dst_stride_argb; + dst_stride_argb = -dst_stride_argb; + } +#if defined(HAS_I444TOARGBROW_SSSE3) + if (TestCpuFlag(kCpuHasSSSE3)) { + I444ToARGBRow = I444ToARGBRow_Any_SSSE3; + if (IS_ALIGNED(width, 8)) { + I444ToARGBRow = I444ToARGBRow_SSSE3; + } + } +#endif +#if defined(HAS_I444TOARGBROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + I444ToARGBRow = I444ToARGBRow_Any_AVX2; + if (IS_ALIGNED(width, 16)) { + I444ToARGBRow = I444ToARGBRow_AVX2; + } + } +#endif +#if defined(HAS_I444TOARGBROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + I444ToARGBRow = I444ToARGBRow_Any_NEON; + if (IS_ALIGNED(width, 8)) { + I444ToARGBRow = I444ToARGBRow_NEON; + } + } +#endif +#if defined(HAS_I444TOARGBROW_SVE2) + if (TestCpuFlag(kCpuHasSVE2)) { + I444ToARGBRow = I444ToARGBRow_SVE2; + } +#endif +#if defined(HAS_I444TOARGBROW_SME) + if (TestCpuFlag(kCpuHasSME)) { + I444ToARGBRow = I444ToARGBRow_SME; + } +#endif +#if defined(HAS_I444TOARGBROW_LSX) + if (TestCpuFlag(kCpuHasLSX)) { + I444ToARGBRow = I444ToARGBRow_Any_LSX; + if (IS_ALIGNED(width, 8)) { + I444ToARGBRow = I444ToARGBRow_LSX; + } + } +#endif +#if defined(HAS_I444TOARGBROW_LASX) + if (TestCpuFlag(kCpuHasLASX)) { + I444ToARGBRow = I444ToARGBRow_Any_LASX; + if (IS_ALIGNED(width, 16)) { + I444ToARGBRow = I444ToARGBRow_LASX; + } + } +#endif +#if defined(HAS_I444TOARGBROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + I444ToARGBRow = I444ToARGBRow_RVV; + } +#endif + +#if defined(HAS_SPLITUVROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + SplitUVRow = SplitUVRow_Any_SSE2; + if (IS_ALIGNED(width, 16)) { + SplitUVRow = SplitUVRow_SSE2; + } + } +#endif +#if defined(HAS_SPLITUVROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + SplitUVRow = SplitUVRow_Any_AVX2; + if (IS_ALIGNED(width, 32)) { + SplitUVRow = SplitUVRow_AVX2; + } + } +#endif +#if defined(HAS_SPLITUVROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + SplitUVRow = SplitUVRow_Any_NEON; + if (IS_ALIGNED(width, 16)) { + SplitUVRow = SplitUVRow_NEON; + } + } +#endif +#if defined(HAS_SPLITUVROW_RVV) + if (TestCpuFlag(kCpuHasRVV)) { + SplitUVRow = SplitUVRow_RVV; + } +#endif + + align_buffer_64(row_u, width); + align_buffer_64(row_v, width); + if (!row_u || !row_v) { + free_aligned_buffer_64(row_u); + free_aligned_buffer_64(row_v); + return 1; + } + for (y = 0; y < height; ++y) { + SplitUVRow(src_uv, row_u, row_v, width); + I444ToARGBRow(src_y, row_u, row_v, dst_argb, &kYuvI601Constants, width); + dst_argb += dst_stride_argb; + src_y += src_stride_y; + src_uv += src_stride_uv; + } + free_aligned_buffer_64(row_u); + free_aligned_buffer_64(row_v); + return 0; +} + // Convert camera sample to ARGB with cropping, rotation and vertical flip. // src_width is used for source stride computation // src_height is used to compute location of planes, and indicate inversion @@ -203,6 +418,23 @@ int ConvertToARGB(const uint8_t* sample, r = NV21ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb, dst_stride_argb, crop_width, inv_crop_height); break; + case FOURCC_NV16: + src = sample + ((ptrdiff_t)src_width * crop_y + crop_x); + src_uv = sample + + aligned_src_width * ((ptrdiff_t)abs_src_height + crop_y) + + (crop_x & ~1); + r = NV16ToARGB(src, src_width, src_uv, aligned_src_width, dst_argb, + dst_stride_argb, crop_width, inv_crop_height); + break; + case FOURCC_NV24: + src = sample + ((ptrdiff_t)src_width * crop_y + crop_x); + src_uv = sample + + (ptrdiff_t)aligned_src_width * abs_src_height + + (ptrdiff_t)aligned_src_width * 2 * crop_y + + (ptrdiff_t)crop_x * 2; + r = NV24ToARGB(src, src_width, src_uv, aligned_src_width * 2, dst_argb, + dst_stride_argb, crop_width, inv_crop_height); + break; // Triplanar formats case FOURCC_I420: case FOURCC_YV12: { diff --git a/source/convert_to_i420.cc b/source/convert_to_i420.cc index 19bfe7ca5..91cd507c0 100644 --- a/source/convert_to_i420.cc +++ b/source/convert_to_i420.cc @@ -14,7 +14,11 @@ #include #include #include +#include +#include "libyuv/cpu_id.h" +#include "libyuv/planar_functions.h" +#include "libyuv/row.h" #include "libyuv/video_common.h" #ifdef __cplusplus @@ -22,6 +26,158 @@ namespace libyuv { extern "C" { #endif +static void HalfRow_C(const uint8_t* src_uv, + ptrdiff_t src_uv_stride, + uint8_t* dst_uv, + int width) { + int x; + for (x = 0; x < width; ++x) { + dst_uv[x] = (src_uv[x] + src_uv[src_uv_stride + x] + 1) >> 1; + } +} + +static int NV16ToI420(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_uv, + int src_stride_uv, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int width, + int height) { + int y; + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + void (*SplitUVRow)(const uint8_t* src_uv, uint8_t* dst_u, uint8_t* dst_v, + int width) = SplitUVRow_C; + if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 || + height == 0 || height == INT_MIN) { + return -1; + } + if (height < 0) { + height = -height; + halfheight = (height + 1) >> 1; + src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y; + src_uv = src_uv + (ptrdiff_t)(height - 1) * src_stride_uv; + src_stride_y = -src_stride_y; + src_stride_uv = -src_stride_uv; + } + if (dst_y) { + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + } +#if defined(HAS_SPLITUVROW_SSE2) + if (TestCpuFlag(kCpuHasSSE2)) { + SplitUVRow = SplitUVRow_Any_SSE2; + if (IS_ALIGNED(halfwidth, 16)) { + SplitUVRow = SplitUVRow_SSE2; + } + } +#endif +#if defined(HAS_SPLITUVROW_AVX2) + if (TestCpuFlag(kCpuHasAVX2)) { + SplitUVRow = SplitUVRow_Any_AVX2; + if (IS_ALIGNED(halfwidth, 32)) { + SplitUVRow = SplitUVRow_AVX2; + } + } +#endif +#if defined(HAS_SPLITUVROW_NEON) + if (TestCpuFlag(kCpuHasNEON)) { + SplitUVRow = SplitUVRow_Any_NEON; + if (IS_ALIGNED(halfwidth, 16)) { + SplitUVRow = SplitUVRow_NEON; + } + } +#endif + + align_buffer_64(row_uv, halfwidth * 2); + if (!row_uv) { + return 1; + } + for (y = 0; y < halfheight; ++y) { + if (y * 2 + 1 < height) { + HalfRow_C(src_uv, src_stride_uv, row_uv, halfwidth * 2); + } else { + memcpy(row_uv, src_uv, (size_t)halfwidth * 2); + } + SplitUVRow(row_uv, dst_u, dst_v, halfwidth); + src_uv += (ptrdiff_t)src_stride_uv * 2; + dst_u += dst_stride_u; + dst_v += dst_stride_v; + } + free_aligned_buffer_64(row_uv); + return 0; +} + +static int NV24ToI420(const uint8_t* src_y, + int src_stride_y, + const uint8_t* src_uv, + int src_stride_uv, + uint8_t* dst_y, + int dst_stride_y, + uint8_t* dst_u, + int dst_stride_u, + uint8_t* dst_v, + int dst_stride_v, + int width, + int height) { + int x, y; + int halfwidth = (width + 1) >> 1; + int halfheight = (height + 1) >> 1; + if ((!src_y && dst_y) || !src_uv || !dst_u || !dst_v || width <= 0 || + height == 0 || height == INT_MIN) { + return -1; + } + if (height < 0) { + height = -height; + halfheight = (height + 1) >> 1; + src_y = src_y + (ptrdiff_t)(height - 1) * src_stride_y; + src_uv = src_uv + (ptrdiff_t)(height - 1) * src_stride_uv; + src_stride_y = -src_stride_y; + src_stride_uv = -src_stride_uv; + } + if (dst_y) { + CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height); + } + + align_buffer_64(row_uv, width * 2); + if (!row_uv) { + return 1; + } + for (y = 0; y < halfheight; ++y) { + if (y * 2 + 1 < height) { + HalfRow_C(src_uv, src_stride_uv, row_uv, width * 2); + } else { + memcpy(row_uv, src_uv, (size_t)width * 2); + } + for (x = 0; x < halfwidth - 1; ++x) { + dst_u[x] = (row_uv[x * 4 + 0] + row_uv[x * 4 + 2] + 1) >> 1; + dst_v[x] = (row_uv[x * 4 + 1] + row_uv[x * 4 + 3] + 1) >> 1; + } + if (width & 1) { + dst_u[halfwidth - 1] = row_uv[(halfwidth - 1) * 4 + 0]; + dst_v[halfwidth - 1] = row_uv[(halfwidth - 1) * 4 + 1]; + } else { + dst_u[halfwidth - 1] = + (row_uv[(halfwidth - 1) * 4 + 0] + row_uv[(halfwidth - 1) * 4 + 2] + + 1) >> + 1; + dst_v[halfwidth - 1] = + (row_uv[(halfwidth - 1) * 4 + 1] + row_uv[(halfwidth - 1) * 4 + 3] + + 1) >> + 1; + } + src_uv += (ptrdiff_t)src_stride_uv * 2; + dst_u += dst_stride_u; + dst_v += dst_stride_v; + } + free_aligned_buffer_64(row_uv); + return 0; +} + // Convert camera sample to I420 with cropping, rotation and vertical flip. // src_width is used for source stride computation // src_height is used to compute location of planes, and indicate inversion @@ -204,6 +360,24 @@ int ConvertToI420(const uint8_t* sample, dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u, crop_width, inv_crop_height, rotation); break; + case FOURCC_NV16: + src = sample + ((ptrdiff_t)src_width * crop_y + crop_x); + src_uv = sample + ((ptrdiff_t)aligned_src_width * abs_src_height) + + ((ptrdiff_t)crop_y * aligned_src_width) + + ((crop_x / 2) * 2); + r = NV16ToI420(src, src_width, src_uv, aligned_src_width, dst_y, + dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, + crop_width, inv_crop_height); + break; + case FOURCC_NV24: + src = sample + ((ptrdiff_t)src_width * crop_y + crop_x); + src_uv = sample + ((ptrdiff_t)aligned_src_width * abs_src_height) + + ((ptrdiff_t)crop_y * aligned_src_width * 2) + + (crop_x * 2); + r = NV24ToI420(src, src_width, src_uv, aligned_src_width * 2, dst_y, + dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, + crop_width, inv_crop_height); + break; // Triplanar formats case FOURCC_I420: case FOURCC_YV12: { diff --git a/source/planar_functions.cc b/source/planar_functions.cc index b63fc988a..2c6cd09c0 100644 --- a/source/planar_functions.cc +++ b/source/planar_functions.cc @@ -196,16 +196,25 @@ void Convert8To16Plane(const uint8_t* src_y, int src_stride_y, uint16_t* dst_y, int dst_stride_y, - int scale, // 1024 for 10 bits + int bits, // 10, 12, 16 bits (or 1024, 4096, 65536 scale) int width, int height) { int y; - void (*Convert8To16Row)(const uint8_t* src_y, uint16_t* dst_y, int scale, + void (*Convert8To16Row)(const uint8_t* src_y, uint16_t* dst_y, int bits, int width) = Convert8To16Row_C; if (width <= 0 || height == 0 || height == INT_MIN) { return; } + // Convert legacy scale to bits if needed. + if (bits > 16) { + int b = 0; + while (bits > 1) { + bits >>= 1; + ++b; + } + bits = b; + } // Negative height means invert the image. if (height < 0) { height = -height; @@ -264,7 +273,7 @@ void Convert8To16Plane(const uint8_t* src_y, // Convert plane for (y = 0; y < height; ++y) { - Convert8To16Row(src_y, dst_y, scale, width); + Convert8To16Row(src_y, dst_y, bits, width); src_y += src_stride_y; dst_y += dst_stride_y; } diff --git a/source/rotate_common.cc b/source/rotate_common.cc index 899405651..af1bea016 100644 --- a/source/rotate_common.cc +++ b/source/rotate_common.cc @@ -145,6 +145,13 @@ void TransposeWxH_16_C(const uint16_t* src, } } +static inline void Copy4(uint8_t* dst, const uint8_t* src) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + // Transpose 32 bit values (ARGB) void Transpose4x4_32_C(const uint8_t* src, int src_stride, @@ -159,38 +166,22 @@ void Transpose4x4_32_C(const uint8_t* src, uint8_t* dst3 = dst2 + dst_stride; int i; for (i = 0; i < width; i += 4) { - uint32_t p00 = ((uint32_t*)(src))[0]; - uint32_t p10 = ((uint32_t*)(src))[1]; - uint32_t p20 = ((uint32_t*)(src))[2]; - uint32_t p30 = ((uint32_t*)(src))[3]; - uint32_t p01 = ((uint32_t*)(src1))[0]; - uint32_t p11 = ((uint32_t*)(src1))[1]; - uint32_t p21 = ((uint32_t*)(src1))[2]; - uint32_t p31 = ((uint32_t*)(src1))[3]; - uint32_t p02 = ((uint32_t*)(src2))[0]; - uint32_t p12 = ((uint32_t*)(src2))[1]; - uint32_t p22 = ((uint32_t*)(src2))[2]; - uint32_t p32 = ((uint32_t*)(src2))[3]; - uint32_t p03 = ((uint32_t*)(src3))[0]; - uint32_t p13 = ((uint32_t*)(src3))[1]; - uint32_t p23 = ((uint32_t*)(src3))[2]; - uint32_t p33 = ((uint32_t*)(src3))[3]; - ((uint32_t*)(dst))[0] = p00; - ((uint32_t*)(dst))[1] = p01; - ((uint32_t*)(dst))[2] = p02; - ((uint32_t*)(dst))[3] = p03; - ((uint32_t*)(dst1))[0] = p10; - ((uint32_t*)(dst1))[1] = p11; - ((uint32_t*)(dst1))[2] = p12; - ((uint32_t*)(dst1))[3] = p13; - ((uint32_t*)(dst2))[0] = p20; - ((uint32_t*)(dst2))[1] = p21; - ((uint32_t*)(dst2))[2] = p22; - ((uint32_t*)(dst2))[3] = p23; - ((uint32_t*)(dst3))[0] = p30; - ((uint32_t*)(dst3))[1] = p31; - ((uint32_t*)(dst3))[2] = p32; - ((uint32_t*)(dst3))[3] = p33; + Copy4(dst + 0, src + 0); + Copy4(dst + 4, src1 + 0); + Copy4(dst + 8, src2 + 0); + Copy4(dst + 12, src3 + 0); + Copy4(dst1 + 0, src + 4); + Copy4(dst1 + 4, src1 + 4); + Copy4(dst1 + 8, src2 + 4); + Copy4(dst1 + 12, src3 + 4); + Copy4(dst2 + 0, src + 8); + Copy4(dst2 + 4, src1 + 8); + Copy4(dst2 + 8, src2 + 8); + Copy4(dst2 + 12, src3 + 8); + Copy4(dst3 + 0, src + 12); + Copy4(dst3 + 4, src1 + 12); + Copy4(dst3 + 8, src2 + 12); + Copy4(dst3 + 12, src3 + 12); src += (ptrdiff_t)src_stride * 4; // advance 4 rows src1 += (ptrdiff_t)src_stride * 4; src2 += (ptrdiff_t)src_stride * 4; diff --git a/source/row_any.cc b/source/row_any.cc index 179ad5f1d..9daa51ae3 100644 --- a/source/row_any.cc +++ b/source/row_any.cc @@ -1494,7 +1494,7 @@ ANY11T(AB64ToARGBRow_Any_NEON, AB64ToARGBRow_NEON, 8, 4, uint16_t, uint8_t, 7) // Any 1 to 1 with parameter and shorts. BPP measures in shorts. #define ANY11C(NAMEANY, ANY_SIMD, SBPP, BPP, STYPE, DTYPE, MASK) \ - void NAMEANY(const STYPE* src_ptr, DTYPE* dst_ptr, int scale, int width) { \ + void NAMEANY(const STYPE* src_ptr, DTYPE* dst_ptr, int value, int width) { \ SIMD_ALIGNED(STYPE vin[64]); \ static_assert((MASK + 1) * SBPP <= sizeof(vin), "vin buffer too small"); \ SIMD_ALIGNED(DTYPE vout[64]); \ @@ -1503,11 +1503,11 @@ ANY11T(AB64ToARGBRow_Any_NEON, AB64ToARGBRow_NEON, 8, 4, uint16_t, uint8_t, 7) int r = width & MASK; \ int n = width & ~MASK; \ if (n > 0) { \ - ANY_SIMD(src_ptr, dst_ptr, scale, n); \ + ANY_SIMD(src_ptr, dst_ptr, value, n); \ } \ ptrdiff_t np = n; \ memcpy(vin, src_ptr + np, r * SBPP); \ - ANY_SIMD(vin, vout, scale, MASK + 1); \ + ANY_SIMD(vin, vout, value, MASK + 1); \ memcpy(dst_ptr + np, vout, r * BPP); \ } diff --git a/source/row_common.cc b/source/row_common.cc index dc823883c..bd0eba368 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -2822,16 +2822,15 @@ void MirrorSplitUVRow_C(const uint8_t* src_uv, void ARGBMirrorRow_C(const uint8_t* src, uint8_t* dst, int width) { int x; - const uint32_t* src32 = (const uint32_t*)(src); - uint32_t* dst32 = (uint32_t*)(dst); - src32 += width - 1; - for (x = 0; x < width - 1; x += 2) { - dst32[x] = src32[0]; - dst32[x + 1] = src32[-1]; - src32 -= 2; - } - if (width & 1) { - dst32[width - 1] = src32[0]; + const uint8_t* s = src + (ptrdiff_t)(width - 1) * 4; + uint8_t* d = dst; + for (x = 0; x < width; ++x) { + d[0] = s[0]; + d[1] = s[1]; + d[2] = s[2]; + d[3] = s[3]; + s -= 4; + d += 4; } } @@ -3241,18 +3240,15 @@ void Convert16To8Row_C(const uint16_t* src_y, } } -// Use scale to convert lsb formats to msb, depending how many bits there are: -// 1024 = 10 bits -// 4096 = 12 bits -// 65536 = 16 bits +// Convert 8 bit values to 10, 12 or 16 bits. void Convert8To16Row_C(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { int x; - scale *= 0x0101; // replicates the byte. + int shift = 16 - bits; for (x = 0; x < width; ++x) { - dst_y[x] = (src_y[x] * scale) >> 16; + dst_y[x] = (src_y[x] * 0x0101) >> shift; } } diff --git a/source/row_gcc.cc b/source/row_gcc.cc index 7252f8f44..ae69f6a2c 100644 --- a/source/row_gcc.cc +++ b/source/row_gcc.cc @@ -6218,9 +6218,9 @@ void HalfWidthRow_16To8_AVX512BW(const uint16_t* src_uv, // 65536 = 16 bits void Convert8To16Row_SSE2(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - const int shift = __builtin_clz(scale) - 15; + const int shift = 16 - bits; asm volatile( "movd %3,%%xmm2 \n" @@ -6249,9 +6249,9 @@ void Convert8To16Row_SSE2(const uint8_t* src_y, #ifdef HAS_CONVERT8TO16ROW_AVX2 void Convert8To16Row_AVX2(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - const int shift = __builtin_clz(scale) - 15; + const int shift = 16 - bits; asm volatile("vmovd %3,%%xmm2 \n" // 32 pixels per loop. @@ -6279,16 +6279,11 @@ void Convert8To16Row_AVX2(const uint8_t* src_y, #endif // HAS_CONVERT8TO16ROW_AVX2 #ifdef HAS_CONVERT8TO16ROW_AVX512BW -// Use scale to convert to lsb formats depending how many bits there are: -// 512 = 9 bits -// 1024 = 10 bits -// 4096 = 12 bits -// 65536 = 16 bits void Convert8To16Row_AVX512BW(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - const int shift = __builtin_clz(scale) - 15; + const int shift = 16 - bits; asm volatile( "vpbroadcastw %4,%%zmm2 \n" "vmovd %3,%%xmm3 \n" diff --git a/source/row_neon.cc b/source/row_neon.cc index 69c42bf44..1168b34b3 100644 --- a/source/row_neon.cc +++ b/source/row_neon.cc @@ -3835,15 +3835,13 @@ void Convert8To8Row_NEON(const uint8_t* src_y, // 512 = 9 bits // 1024 = 10 bits // 4096 = 12 bits -// 65536 = 16 bits void Convert8To16Row_NEON(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - // (src * 0x0101 * scale) >> 16. - // Since scale is a power of two, compute the shift to use to avoid needing - // to widen to int32. - const int shift = 15 - __builtin_clz(scale); + // (src * 0x0101) >> (16 - bits). + // Use negative shift for right shift with vshl. + const int shift = bits - 16; asm volatile( "vdup.16 q2, %3 \n" "1: \n" diff --git a/source/row_neon64.cc b/source/row_neon64.cc index 1fadf0844..53666bf41 100644 --- a/source/row_neon64.cc +++ b/source/row_neon64.cc @@ -5273,12 +5273,11 @@ void Convert8To8Row_NEON(const uint8_t* src_y, // 65536 = 16 bits void Convert8To16Row_NEON(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - // (src * 0x0101 * scale) >> 16. - // Since scale is a power of two, compute the shift to use to avoid needing - // to widen to int32. - const int shift = 15 - __builtin_clz(scale); + // (src * 0x0101) >> (16 - bits). + // Use negative shift for right shift with ushl. + const int shift = bits - 16; asm volatile( "dup v2.8h, %w[shift] \n" "1: \n" diff --git a/source/row_rvv.cc b/source/row_rvv.cc index 18cbe6a63..062ab09e2 100644 --- a/source/row_rvv.cc +++ b/source/row_rvv.cc @@ -1821,10 +1821,10 @@ void Convert16To8Row_RVV(const uint16_t* src_y, // 65536 = 16 bits void Convert8To16Row_RVV(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { size_t w = (size_t)width; - const int shift = __builtin_clz((int32_t)scale) - 15; + const int shift = 16 - bits; do { size_t vl = __riscv_vsetvl_e8m2(w); vuint8m2_t v_src = __riscv_vle8_v_u8m2(src_y, vl); diff --git a/source/row_sme.cc b/source/row_sme.cc index fe2d0a117..a78a2c02b 100644 --- a/source/row_sme.cc +++ b/source/row_sme.cc @@ -1054,12 +1054,10 @@ __arm_locally_streaming void Convert8To8Row_SME(const uint8_t* src_y, __arm_locally_streaming void Convert8To16Row_SME(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { - // (src * 0x0101 * scale) >> 16. - // Since scale is a power of two, compute the shift to use to avoid needing - // to widen to int32. - const int shift = __builtin_clz(scale) - 15; + // (src * 0x0101) >> (16 - bits). + const int shift = 16 - bits; uint64_t vl; asm volatile( diff --git a/source/row_win.cc b/source/row_win.cc index b0e1e634b..927729d15 100644 --- a/source/row_win.cc +++ b/source/row_win.cc @@ -766,23 +766,12 @@ void ARGBToUVMatrixRow_AVX2(const uint8_t* src_argb, #endif // HAS_ARGBTOUVMATRIXROW_AVX2 #ifdef HAS_CONVERT8TO16ROW_AVX2 -// Use scale to convert to lsb formats depending how many bits there are: -// 512 = 9 bits -// 1024 = 10 bits -// 4096 = 12 bits -// 65536 = 16 bits LIBYUV_TARGET_AVX2 void Convert8To16Row_AVX2(const uint8_t* src_y, uint16_t* dst_y, - int scale, + int bits, int width) { -#if defined(_MSC_VER) && !defined(__clang__) - unsigned long index; - _BitScanReverse(&index, (unsigned long)scale); - const int shift = 16 - (int)index; -#else - const int shift = __builtin_clz(scale) - 15; -#endif + const int shift = 16 - bits; __m128i shift128 = _mm_cvtsi32_si128(shift); do { __m256i ymm0 = _mm256_loadu_si256((const __m256i*)src_y); diff --git a/unit_test/convert_argb_test.cc b/unit_test/convert_argb_test.cc index 3a21e3c12..ab3427635 100644 --- a/unit_test/convert_argb_test.cc +++ b/unit_test/convert_argb_test.cc @@ -1680,6 +1680,42 @@ TEST_F(LibYUVConvertTest, RotateWithARGBSource) { ASSERT_EQ(dst[3], src[1]); } +TEST_F(LibYUVConvertTest, ConvertToARGB_NV16) { + const int kWidth = 64; + const int kHeight = 48; + const int sample_size = kWidth * kHeight * 2; + align_buffer_page_end(src, sample_size); + align_buffer_page_end(dst, kWidth * kHeight * 4); + MemRandomize(src, sample_size); + memset(dst, 0, kWidth * kHeight * 4); + + int r = ConvertToARGB(src, sample_size, dst, kWidth * 4, + 0, 0, kWidth, kHeight, kWidth, kHeight, + kRotate0, FOURCC_NV16); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src); + free_aligned_buffer_page_end(dst); +} + +TEST_F(LibYUVConvertTest, ConvertToARGB_NV24) { + const int kWidth = 64; + const int kHeight = 48; + const int sample_size = kWidth * kHeight * 3; + align_buffer_page_end(src, sample_size); + align_buffer_page_end(dst, kWidth * kHeight * 4); + MemRandomize(src, sample_size); + memset(dst, 0, kWidth * kHeight * 4); + + int r = ConvertToARGB(src, sample_size, dst, kWidth * 4, + 0, 0, kWidth, kHeight, kWidth, kHeight, + kRotate0, FOURCC_NV24); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src); + free_aligned_buffer_page_end(dst); +} + #ifdef HAS_ARGBTOAR30ROW_AVX2 TEST_F(LibYUVConvertTest, ARGBToAR30Row_Opt) { // ARGBToAR30Row_AVX2 expects a multiple of 8 pixels. diff --git a/unit_test/convert_test.cc b/unit_test/convert_test.cc index fa7314cd7..8ea10a414 100644 --- a/unit_test/convert_test.cc +++ b/unit_test/convert_test.cc @@ -1923,6 +1923,100 @@ TEST_F(LibYUVConvertTest, NV12Crop) { free_aligned_buffer_page_end(src_y); } +TEST_F(LibYUVConvertTest, ConvertToI420_NV16) { + const int kWidth = 64; + const int kHeight = 48; + const int sample_size = kWidth * kHeight * 2; + align_buffer_page_end(src, sample_size); + align_buffer_page_end(dst_y, kWidth * kHeight); + align_buffer_page_end(dst_u, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(dst_v, (kWidth / 2) * (kHeight / 2)); + MemRandomize(src, sample_size); + memset(dst_y, 0, kWidth * kHeight); + memset(dst_u, 0, (kWidth / 2) * (kHeight / 2)); + memset(dst_v, 0, (kWidth / 2) * (kHeight / 2)); + + int r = ConvertToI420(src, sample_size, dst_y, kWidth, dst_u, kWidth / 2, + dst_v, kWidth / 2, 0, 0, kWidth, kHeight, kWidth, + kHeight, kRotate0, FOURCC_NV16); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src); + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_u); + free_aligned_buffer_page_end(dst_v); +} + +TEST_F(LibYUVConvertTest, ConvertToI420_NV24) { + const int kWidth = 64; + const int kHeight = 48; + const int sample_size = kWidth * kHeight * 3; + align_buffer_page_end(src, sample_size); + align_buffer_page_end(dst_y, kWidth * kHeight); + align_buffer_page_end(dst_u, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(dst_v, (kWidth / 2) * (kHeight / 2)); + MemRandomize(src, sample_size); + memset(dst_y, 0, kWidth * kHeight); + memset(dst_u, 0, (kWidth / 2) * (kHeight / 2)); + memset(dst_v, 0, (kWidth / 2) * (kHeight / 2)); + + int r = ConvertToI420(src, sample_size, dst_y, kWidth, dst_u, kWidth / 2, + dst_v, kWidth / 2, 0, 0, kWidth, kHeight, kWidth, + kHeight, kRotate0, FOURCC_NV24); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src); + free_aligned_buffer_page_end(dst_y); + free_aligned_buffer_page_end(dst_u); + free_aligned_buffer_page_end(dst_v); +} + +TEST_F(LibYUVConvertTest, ConvertFromI420_NV16) { + const int kWidth = 64; + const int kHeight = 48; + const int dst_size = kWidth * kHeight * 2; + align_buffer_page_end(src_y, kWidth * kHeight); + align_buffer_page_end(src_u, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(src_v, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(dst, dst_size); + MemRandomize(src_y, kWidth * kHeight); + MemRandomize(src_u, (kWidth / 2) * (kHeight / 2)); + MemRandomize(src_v, (kWidth / 2) * (kHeight / 2)); + memset(dst, 0, dst_size); + + int r = ConvertFromI420(src_y, kWidth, src_u, kWidth / 2, src_v, kWidth / 2, + dst, kWidth, kWidth, kHeight, FOURCC_NV16); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src_y); + free_aligned_buffer_page_end(src_u); + free_aligned_buffer_page_end(src_v); + free_aligned_buffer_page_end(dst); +} + +TEST_F(LibYUVConvertTest, ConvertFromI420_NV24) { + const int kWidth = 64; + const int kHeight = 48; + const int dst_size = kWidth * kHeight * 3; + align_buffer_page_end(src_y, kWidth * kHeight); + align_buffer_page_end(src_u, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(src_v, (kWidth / 2) * (kHeight / 2)); + align_buffer_page_end(dst, dst_size); + MemRandomize(src_y, kWidth * kHeight); + MemRandomize(src_u, (kWidth / 2) * (kHeight / 2)); + MemRandomize(src_v, (kWidth / 2) * (kHeight / 2)); + memset(dst, 0, dst_size); + + int r = ConvertFromI420(src_y, kWidth, src_u, kWidth / 2, src_v, kWidth / 2, + dst, kWidth, kWidth, kHeight, FOURCC_NV24); + EXPECT_EQ(0, r); + + free_aligned_buffer_page_end(src_y); + free_aligned_buffer_page_end(src_u); + free_aligned_buffer_page_end(src_v); + free_aligned_buffer_page_end(dst); +} + TEST_F(LibYUVConvertTest, I420CropOddY) { const int SUBSAMP_X = 2; const int SUBSAMP_Y = 2; diff --git a/unit_test/planar_test.cc b/unit_test/planar_test.cc index 214081c0a..df7747564 100644 --- a/unit_test/planar_test.cc +++ b/unit_test/planar_test.cc @@ -4159,7 +4159,7 @@ TEST_F(LibYUVPlanarTest, Convert8To16Plane) { MaskCpuFlags(disable_cpu_flags_); Convert8To16Plane(src_pixels_y, benchmark_width_, reinterpret_cast(dst_pixels_y_c), - benchmark_width_, 1024, benchmark_width_, + benchmark_width_, 10, benchmark_width_, benchmark_height_); MaskCpuFlags(benchmark_cpu_info_); @@ -4193,7 +4193,7 @@ TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) { memset(dst_pixels_y_c, 1, kPixels * 2); Convert8To16Row_C(src_pixels_y, reinterpret_cast(dst_pixels_y_c), - 1024, kPixels); + 10, kPixels); #if defined(HAS_CONVERT8TO16ROW_AVX512BW) int has_avx512 = TestCpuFlag(kCpuHasAVX512BW); @@ -4205,20 +4205,20 @@ TEST_F(LibYUVPlanarTest, Convert8To16Row_Opt) { if (has_avx512) { Convert8To16Row_AVX512BW(src_pixels_y, reinterpret_cast(dst_pixels_y_opt), - 1024, kPixels); + 10, kPixels); } else #endif if (has_avx2) { Convert8To16Row_AVX2(src_pixels_y, - reinterpret_cast(dst_pixels_y_opt), 1024, + reinterpret_cast(dst_pixels_y_opt), 10, kPixels); } else if (has_sse2) { Convert8To16Row_SSE2(src_pixels_y, - reinterpret_cast(dst_pixels_y_opt), 1024, + reinterpret_cast(dst_pixels_y_opt), 10, kPixels); } else { Convert8To16Row_C(src_pixels_y, - reinterpret_cast(dst_pixels_y_opt), 1024, + reinterpret_cast(dst_pixels_y_opt), 10, kPixels); } } diff --git a/unit_test/video_common_test.cc b/unit_test/video_common_test.cc index 9ff99faac..2577ef7f7 100644 --- a/unit_test/video_common_test.cc +++ b/unit_test/video_common_test.cc @@ -63,6 +63,8 @@ TEST_F(LibYUVBaseTest, TestFourCC) { ASSERT_TRUE(TestValidFourCC(FOURCC_I400, FOURCC_BPP_I400)); ASSERT_TRUE(TestValidFourCC(FOURCC_NV21, FOURCC_BPP_NV21)); ASSERT_TRUE(TestValidFourCC(FOURCC_NV12, FOURCC_BPP_NV12)); + ASSERT_TRUE(TestValidFourCC(FOURCC_NV16, FOURCC_BPP_NV16)); + ASSERT_TRUE(TestValidFourCC(FOURCC_NV24, FOURCC_BPP_NV24)); ASSERT_TRUE(TestValidFourCC(FOURCC_YUY2, FOURCC_BPP_YUY2)); ASSERT_TRUE(TestValidFourCC(FOURCC_UYVY, FOURCC_BPP_UYVY)); ASSERT_TRUE(TestValidFourCC(FOURCC_M420, FOURCC_BPP_M420)); // deprecated.