Add BT.709 Full Range yuv constants.

MAKEYUVCONSTANTS macro to generate struct for YUV to RGB
Fix I444AlphaToARGB unit test for ARM by adjusting C version to match Neon implementation.

Bug: libyuv:879, libyuv:878, libyuv:877, libyuv:862, b/178283356
Change-Id: Iedb171fbf668316e7d45ab9e3481de6205ed31e2
Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/2646472
Commit-Queue: Frank Barchard <fbarchard@chromium.org>
Reviewed-by: Wan-Teh Chang <wtc@google.com>
This commit is contained in:
Frank Barchard 2021-01-26 10:32:31 -08:00 committed by Frank Barchard
parent 08d0dce5fc
commit 37480f12c6
15 changed files with 390 additions and 310 deletions

View File

@ -1,6 +1,6 @@
Name: libyuv
URL: http://code.google.com/p/libyuv/
Version: 1770
Version: 1772
License: BSD
License File: LICENSE

View File

@ -23,12 +23,14 @@ extern "C" {
// Conversion matrix for YUV to RGB
LIBYUV_API extern const struct YuvConstants kYuvI601Constants; // BT.601
LIBYUV_API extern const struct YuvConstants kYuvJPEGConstants; // JPeg
LIBYUV_API extern const struct YuvConstants kYuvF709Constants; // BT.709 full
LIBYUV_API extern const struct YuvConstants kYuvH709Constants; // BT.709
LIBYUV_API extern const struct YuvConstants kYuv2020Constants; // BT.2020
// Conversion matrix for YVU to BGR
LIBYUV_API extern const struct YuvConstants kYvuI601Constants; // BT.601
LIBYUV_API extern const struct YuvConstants kYvuJPEGConstants; // JPeg
LIBYUV_API extern const struct YuvConstants kYvuF709Constants; // BT.709 full
LIBYUV_API extern const struct YuvConstants kYvuH709Constants; // BT.709
LIBYUV_API extern const struct YuvConstants kYvu2020Constants; // BT.2020
@ -37,6 +39,7 @@ LIBYUV_API extern const struct YuvConstants kYvu2020Constants; // BT.2020
// TODO(fbarchard): Add macro for each Matrix function.
#define kYuvI601ConstantsVU kYvuI601Constants
#define kYuvJPEGConstantsVU kYvuJPEGConstants
#define kYuvF709ConstantsVU kYvuF709Constants
#define kYuvH709ConstantsVU kYvuH709Constants
#define kYuv2020ConstantsVU kYvu2020Constants
#define NV12ToABGRMatrix(a, b, c, d, e, f, g, h, i) \
@ -118,6 +121,32 @@ int J420ToABGR(const uint8_t* src_y,
int width,
int height);
// Convert F420 to ARGB. BT.709 full range
LIBYUV_API
int F420ToARGB(const uint8_t* src_y,
int src_stride_y,
const uint8_t* src_u,
int src_stride_u,
const uint8_t* src_v,
int src_stride_v,
uint8_t* dst_argb,
int dst_stride_argb,
int width,
int height);
// Convert F420 to ABGR. BT.709 full range
LIBYUV_API
int F420ToABGR(const uint8_t* src_y,
int src_stride_y,
const uint8_t* src_u,
int src_stride_u,
const uint8_t* src_v,
int src_stride_v,
uint8_t* dst_abgr,
int dst_stride_abgr,
int width,
int height);
// Convert H420 to ARGB.
LIBYUV_API
int H420ToARGB(const uint8_t* src_y,

View File

@ -201,14 +201,28 @@ int I444Copy(const uint8_t* src_y,
int height);
// Copy NV12. Supports inverting.
int NV12Copy(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_uv, int dst_stride_uv, int width, int height);
int NV12Copy(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_uv,
int dst_stride_uv,
int width,
int height);
// Copy NV21. Supports inverting.
int NV21Copy(const uint8_t* src_y, int src_stride_y, const uint8_t* src_vu,
int src_stride_vu, uint8_t* dst_y, int dst_stride_y,
uint8_t* dst_vu, int dst_stride_vu, int width, int height);
int NV21Copy(const uint8_t* src_y,
int src_stride_y,
const uint8_t* src_vu,
int src_stride_vu,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_vu,
int dst_stride_vu,
int width,
int height);
// Convert YUY2 to I422.
LIBYUV_API

View File

@ -11,6 +11,6 @@
#ifndef INCLUDE_LIBYUV_VERSION_H_
#define INCLUDE_LIBYUV_VERSION_H_
#define LIBYUV_VERSION 1770
#define LIBYUV_VERSION 1772
#endif // INCLUDE_LIBYUV_VERSION_H_

View File

@ -94,16 +94,21 @@ enum FourCC {
FOURCC('J', '4', '4', '4'), // jpeg (bt.601 full), unofficial fourcc
FOURCC_J400 =
FOURCC('J', '4', '0', '0'), // jpeg (bt.601 full), unofficial fourcc
FOURCC_F420 = FOURCC('F', '4', '2', '0'), // bt.709 full, unofficial fourcc
FOURCC_F422 = FOURCC('F', '4', '2', '2'), // bt.709 full, unofficial fourcc
FOURCC_F444 = FOURCC('F', '4', '4', '4'), // bt.709 full, unofficial fourcc
FOURCC_H420 = FOURCC('H', '4', '2', '0'), // bt.709, unofficial fourcc
FOURCC_H422 = FOURCC('H', '4', '2', '2'), // bt.709, unofficial fourcc
FOURCC_H444 = FOURCC('H', '4', '4', '4'), // bt.709, unofficial fourcc
FOURCC_U420 = FOURCC('U', '4', '2', '0'), // bt.2020, unofficial fourcc
FOURCC_U422 = FOURCC('U', '4', '2', '2'), // bt.2020, unofficial fourcc
FOURCC_U444 = FOURCC('U', '4', '4', '4'), // bt.2020, unofficial fourcc
FOURCC_F010 = FOURCC('F', '0', '1', '0'), // bt.709 full range 10 bit 420
FOURCC_H010 = FOURCC('H', '0', '1', '0'), // bt.709 10 bit 420
FOURCC_U010 = FOURCC('U', '0', '1', '0'), // bt.2020 10 bit 420
FOURCC_H210 = FOURCC('H', '0', '1', '0'), // bt.709 10 bit 422
FOURCC_U210 = FOURCC('U', '0', '1', '0'), // bt.2020 10 bit 422
FOURCC_F210 = FOURCC('F', '2', '1', '0'), // bt.709 full range 10 bit 422
FOURCC_H210 = FOURCC('H', '2', '1', '0'), // bt.709 10 bit 422
FOURCC_U210 = FOURCC('U', '2', '1', '0'), // bt.2020 10 bit 422
// 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.

View File

@ -350,9 +350,16 @@ int I420ToI400(const uint8_t* src_y,
}
// Copy NV12. Supports inverting.
int NV12Copy(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_uv, int dst_stride_uv, int width, int height) {
int NV12Copy(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_uv,
int dst_stride_uv,
int width,
int height) {
if (!src_y || !dst_y || !src_uv || !dst_uv || width <= 0 || height == 0) {
return -1;
}
@ -375,9 +382,16 @@ int NV12Copy(const uint8_t* src_y, int src_stride_y, const uint8_t* src_uv,
}
// Copy NV21. Supports inverting.
int NV21Copy(const uint8_t* src_y, int src_stride_y, const uint8_t* src_vu,
int src_stride_vu, uint8_t* dst_y, int dst_stride_y,
uint8_t* dst_vu, int dst_stride_vu, int width, int height) {
int NV21Copy(const uint8_t* src_y,
int src_stride_y,
const uint8_t* src_vu,
int src_stride_vu,
uint8_t* dst_y,
int dst_stride_y,
uint8_t* dst_vu,
int dst_stride_vu,
int width,
int height) {
return NV12Copy(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
dst_stride_y, dst_vu, dst_stride_vu, width, height);
}

View File

@ -1327,7 +1327,68 @@ void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) {
}
}
// TODO(fbarchard): Unify these structures to be platform independent.
// Macros to create SIMD specific yuv to rgb conversion constants.
#if defined(__aarch64__)
#define MAKEYUVCONSTANTS(name, YG, YGB, UB, UG, VG, VR, BB, BG, BR) \
const struct YuvConstants SIMD_ALIGNED(kYuv##name##Constants) = { \
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR}, \
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR}, \
{UG, VG, UG, VG, UG, VG, UG, VG}, \
{UG, VG, UG, VG, UG, VG, UG, VG}, \
{BB, BG, BR, YGB, 0, 0, 0, 0}, \
{0x0101 * YG, YG, 0, 0}}; \
const struct YuvConstants SIMD_ALIGNED(kYvu##name##Constants) = { \
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB}, \
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB}, \
{VG, UG, VG, UG, VG, UG, VG, UG}, \
{VG, UG, VG, UG, VG, UG, VG, UG}, \
{BR, BG, BB, YGB, 0, 0, 0, 0}, \
{0x0101 * YG, YG, 0, 0}};
#elif defined(__arm__)
#define MAKEYUVCONSTANTS(name, YG, YGB, UB, UG, VG, VR, BB, BG, BR) \
const struct YuvConstants SIMD_ALIGNED(kYuv##name##Constants) = { \
{-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0}, \
{UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0}, \
{BB, BG, BR, YGB, 0, 0, 0, 0}, \
{0x0101 * YG, YG, 0, 0}}; \
const struct YuvConstants SIMD_ALIGNED(kYvu##name##Constants) = { \
{-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0}, \
{VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0}, \
{BR, BG, BB, YGB, 0, 0, 0, 0}, \
{0x0101 * YG, YG, 0, 0}};
#else
#define MAKEYUVCONSTANTS(name, YG, YGB, UB, UG, VG, VR, BB, BG, BR) \
const struct YuvConstants SIMD_ALIGNED(kYuv##name##Constants) = { \
{UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, \
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0}, \
{UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, \
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG}, \
{0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, \
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR}, \
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB}, \
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG}, \
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR}, \
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG}, \
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, \
YGB, YGB}}; \
const struct YuvConstants SIMD_ALIGNED(kYvu##name##Constants) = { \
{VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, \
VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0}, \
{VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, \
VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG}, \
{0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, \
0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB}, \
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR}, \
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG}, \
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB}, \
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG}, \
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, \
YGB, YGB}};
#endif
// TODO(fbarchard): Generate SIMD structures from float matrix.
// BT.601 YUV to RGB reference
@ -1350,60 +1411,7 @@ void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) {
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
#if defined(__aarch64__) // 64 bit arm
const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants) = {
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{UG, VG, UG, VG, UG, VG, UG, VG},
{UG, VG, UG, VG, UG, VG, UG, VG},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants) = {
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{VG, UG, VG, UG, VG, UG, VG, UG},
{VG, UG, VG, UG, VG, UG, VG, UG},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#elif defined(__arm__) // 32 bit arm
const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants) = {
{-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0},
{UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants) = {
{-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0},
{VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#else
const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants) = {
{UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0},
{UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG},
{0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants) = {
{VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0,
VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0},
{VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG},
{0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB,
0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
#endif
MAKEYUVCONSTANTS(I601, YG, YGB, UB, UG, VG, VR, BB, BG, BR)
#undef BB
#undef BG
@ -1435,60 +1443,7 @@ const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants) = {
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
#if defined(__aarch64__)
const struct YuvConstants SIMD_ALIGNED(kYuvJPEGConstants) = {
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{UG, VG, UG, VG, UG, VG, UG, VG},
{UG, VG, UG, VG, UG, VG, UG, VG},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants) = {
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{VG, UG, VG, UG, VG, UG, VG, UG},
{VG, UG, VG, UG, VG, UG, VG, UG},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#elif defined(__arm__)
const struct YuvConstants SIMD_ALIGNED(kYuvJPEGConstants) = {
{-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0},
{UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants) = {
{-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0},
{VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#else
const struct YuvConstants SIMD_ALIGNED(kYuvJPEGConstants) = {
{UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0},
{UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG},
{0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants) = {
{VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0,
VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0},
{VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG},
{0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB,
0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
#endif
MAKEYUVCONSTANTS(JPEG, YG, YGB, UB, UG, VG, VR, BB, BG, BR)
#undef BB
#undef BG
@ -1504,7 +1459,6 @@ const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants) = {
// R = (Y - 16) * 1.164 - V * -1.793
// G = (Y - 16) * 1.164 - U * 0.213 - V * 0.533
// B = (Y - 16) * 1.164 - U * -2.112
// See also http://www.equasys.de/colorconversion.html
// Y contribution to R,G,B. Scale and bias.
#define YG 18997 /* round(1.164 * 64 * 256 * 256 / 257) */
@ -1522,60 +1476,45 @@ const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants) = {
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
#if defined(__aarch64__)
const struct YuvConstants SIMD_ALIGNED(kYuvH709Constants) = {
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{UG, VG, UG, VG, UG, VG, UG, VG},
{UG, VG, UG, VG, UG, VG, UG, VG},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = {
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{VG, UG, VG, UG, VG, UG, VG, UG},
{VG, UG, VG, UG, VG, UG, VG, UG},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#elif defined(__arm__)
const struct YuvConstants SIMD_ALIGNED(kYuvH709Constants) = {
{-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0},
{UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = {
{-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0},
{VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#else
const struct YuvConstants SIMD_ALIGNED(kYuvH709Constants) = {
{UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0},
{UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG},
{0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = {
{VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0,
VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0},
{VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG},
{0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB,
0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
#endif
MAKEYUVCONSTANTS(H709, YG, YGB, UB, UG, VG, VR, BB, BG, BR)
#undef BB
#undef BG
#undef BR
#undef YGB
#undef UB
#undef UG
#undef VG
#undef VR
#undef YG
// BT.709 full range YUV to RGB reference
// R = Y - V * -1.5748
// G = Y - U * 0.18732 - V * 0.46812
// B = Y - U * -1.8556
// WR = 0.2126
// WB = 0.0722
// WR and WB given, the equations are:
// R = Y + (2 * (1 - WR)) * V;
// G = Y - ((2 * ((WR * (1 - WR) * V) + (WB * (1 - WB) * U))) / (1 - WB - WR));
// B = Y + (2 * (1 - WB)) * U;
// Y contribution to R,G,B. Scale and bias. (same as jpeg)
#define YG 16320 /* round(1 * 64 * 256 * 256 / 257) */
#define YGB 32 /* 64 / 2 */
// U and V contributions to R,G,B.
#define UB -119 /* round(-1.8556 * 64) */
#define UG 12 /* round(0.18732 * 64) */
#define VG 30 /* round(0.46812 * 64) */
#define VR -101 /* round(-1.5748 * 64) */
// Bias values to round, and subtract 128 from U and V.
#define BB (UB * 128 + YGB)
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
MAKEYUVCONSTANTS(F709, YG, YGB, UB, UG, VG, VR, BB, BG, BR)
#undef BB
#undef BG
@ -1608,60 +1547,7 @@ const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = {
#define BG (UG * 128 + VG * 128 + YGB)
#define BR (VR * 128 + YGB)
#if defined(__aarch64__)
const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{-UB, -VR, -UB, -VR, -UB, -VR, -UB, -VR},
{UG, VG, UG, VG, UG, VG, UG, VG},
{UG, VG, UG, VG, UG, VG, UG, VG},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{-VR, -UB, -VR, -UB, -VR, -UB, -VR, -UB},
{VG, UG, VG, UG, VG, UG, VG, UG},
{VG, UG, VG, UG, VG, UG, VG, UG},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#elif defined(__arm__)
const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
{-UB, -UB, -UB, -UB, -VR, -VR, -VR, -VR, 0, 0, 0, 0, 0, 0, 0, 0},
{UG, UG, UG, UG, VG, VG, VG, VG, 0, 0, 0, 0, 0, 0, 0, 0},
{BB, BG, BR, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
{-VR, -VR, -VR, -VR, -UB, -UB, -UB, -UB, 0, 0, 0, 0, 0, 0, 0, 0},
{VG, VG, VG, VG, UG, UG, UG, UG, 0, 0, 0, 0, 0, 0, 0, 0},
{BR, BG, BB, YGB, 0, 0, 0, 0},
{0x0101 * YG, YG, 0, 0}};
#else
const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants) = {
{UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0,
UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0},
{UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG},
{0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR,
0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
{VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0,
VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0, VR, 0},
{VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG},
{0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB,
0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB, 0, UB},
{BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR},
{BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG},
{BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB},
{YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG},
{YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB, YGB,
YGB}};
#endif
MAKEYUVCONSTANTS(2020, YG, YGB, UB, UG, VG, VR, BB, BG, BR)
#undef BB
#undef BG
@ -1673,6 +1559,8 @@ const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants) = {
#undef VR
#undef YG
#undef MAKEYUVCONSTANTS
// C reference code that mimics the YUV assembly.
// Reads 8 bit YUV and leaves result as 16 bit.
static __inline void YuvPixel(uint8_t y,
@ -1712,9 +1600,9 @@ static __inline void YuvPixel(uint8_t y,
#endif
uint32_t y1 = (uint32_t)(y * 0x0101 * yg) >> 16;
*b = Clamp((int32_t)(-(u * ub) + y1 + bb) >> 6);
*g = Clamp((int32_t)(-(u * ug + v * vg) + y1 + bg) >> 6);
*r = Clamp((int32_t)(-(v * vr) + y1 + br) >> 6);
*b = Clamp((int32_t)(y1 + -(u * ub) + bb) >> 6);
*g = Clamp((int32_t)(y1 + -(u * ug + v * vg) + bg) >> 6);
*r = Clamp((int32_t)(y1 + -(v * vr) + br) >> 6);
}
// Reads 8 bit YUV and leaves result as 16 bit.
@ -2016,6 +1904,40 @@ void I422ToAR30Row_C(const uint8_t* src_y,
}
}
#if !defined(LIBYUV_DISABLE_NEON) && \
(defined(__ARM_NEON__) || defined(__aarch64__) || defined(LIBYUV_NEON))
// C mimic assembly.
// TODO(fbarchard): Remove subsampling from Neon.
void I444AlphaToARGBRow_C(const uint8_t* src_y,
const uint8_t* src_u,
const uint8_t* src_v,
const uint8_t* src_a,
uint8_t* rgb_buf,
const struct YuvConstants* yuvconstants,
int width) {
int x;
for (x = 0; x < width - 1; x += 2) {
uint8_t u = (src_u[0] + src_u[1] + 1) >> 1;
uint8_t v = (src_v[0] + src_v[1] + 1) >> 1;
YuvPixel(src_y[0], u, v, rgb_buf + 0, rgb_buf + 1, rgb_buf + 2,
yuvconstants);
rgb_buf[3] = src_a[0];
YuvPixel(src_y[1], u, v, rgb_buf + 4, rgb_buf + 5, rgb_buf + 6,
yuvconstants);
rgb_buf[7] = src_a[1];
src_y += 2;
src_u += 2;
src_v += 2;
src_a += 2;
rgb_buf += 8; // Advance 2 pixels.
}
if (width & 1) {
YuvPixel(src_y[0], src_u[0], src_v[0], rgb_buf + 0, rgb_buf + 1,
rgb_buf + 2, yuvconstants);
rgb_buf[3] = src_a[0];
}
}
#else
void I444AlphaToARGBRow_C(const uint8_t* src_y,
const uint8_t* src_u,
const uint8_t* src_v,
@ -2035,6 +1957,7 @@ void I444AlphaToARGBRow_C(const uint8_t* src_y,
rgb_buf += 4; // Advance 1 pixel.
}
}
#endif
void I422AlphaToARGBRow_C(const uint8_t* src_y,
const uint8_t* src_u,

View File

@ -1278,7 +1278,7 @@ void RGBAToYJRow_AVX2(const uint8_t* src_rgba, uint8_t* dst_y, int width) {
"vmovdqu %5,%%ymm6 \n"
LABELALIGN RGBTOY_AVX2(
ymm5) "vzeroupper \n"
ymm5) "vzeroupper \n"
: "+r"(src_rgba), // %0
"+r"(dst_y), // %1
"+r"(width) // %2
@ -2161,15 +2161,15 @@ void OMITFP I444AlphaToARGBRow_SSSE3(const uint8_t* y_buf,
// clang-format off
asm volatile (
YUVTORGB_SETUP(yuvconstants)
"sub %[u_buf],%[v_buf] \n"
"sub %[u_buf],%[v_buf] \n"
LABELALIGN
"1: \n"
"1: \n"
READYUVA444
YUVTORGB(yuvconstants)
STOREARGB
"subl $0x8,%[width] \n"
"jg 1b \n"
"subl $0x8,%[width] \n"
"jg 1b \n"
: [y_buf]"+r"(y_buf), // %[y_buf]
[u_buf]"+r"(u_buf), // %[u_buf]
[v_buf]"+r"(v_buf), // %[v_buf]
@ -2947,16 +2947,16 @@ void OMITFP I444AlphaToARGBRow_AVX2(const uint8_t* y_buf,
// clang-format off
asm volatile (
YUVTORGB_SETUP_AVX2(yuvconstants)
"sub %[u_buf],%[v_buf] \n"
"sub %[u_buf],%[v_buf] \n"
LABELALIGN
"1: \n"
"1: \n"
READYUVA444_AVX2
YUVTORGB_AVX2(yuvconstants)
STOREARGB_AVX2
"subl $0x10,%[width] \n"
"jg 1b \n"
"vzeroupper \n"
"subl $0x10,%[width] \n"
"jg 1b \n"
"vzeroupper \n"
: [y_buf]"+r"(y_buf), // %[y_buf]
[u_buf]"+r"(u_buf), // %[u_buf]
[v_buf]"+r"(v_buf), // %[v_buf]

View File

@ -168,8 +168,8 @@ void I444AlphaToARGBRow_NEON(const uint8_t* src_y,
asm volatile(
YUVTORGB_SETUP
"1: \n" READYUV444 YUVTORGB
"subs %5, %5, #8 \n"
"vld1.8 {d23}, [%3]! \n"
"subs %5, %5, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%4]! \n"
"bgt 1b \n"
: "+r"(src_y), // %0
@ -415,11 +415,11 @@ void NV12ToARGBRow_NEON(const uint8_t* src_y,
const struct YuvConstants* yuvconstants,
int width) {
asm volatile(YUVTORGB_SETUP
"vmov.u8 d23, #255 \n"
"1: \n" READNV12 YUVTORGB
"subs %3, %3, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%2]! \n"
"bgt 1b \n"
"vmov.u8 d23, #255 \n"
"1: \n" READNV12 YUVTORGB
"subs %3, %3, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%2]! \n"
"bgt 1b \n"
: "+r"(src_y), // %0
"+r"(src_uv), // %1
"+r"(dst_argb), // %2
@ -438,11 +438,11 @@ void NV21ToARGBRow_NEON(const uint8_t* src_y,
const struct YuvConstants* yuvconstants,
int width) {
asm volatile(YUVTORGB_SETUP
"vmov.u8 d23, #255 \n"
"1: \n" READNV21 YUVTORGB
"subs %3, %3, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%2]! \n"
"bgt 1b \n"
"vmov.u8 d23, #255 \n"
"1: \n" READNV21 YUVTORGB
"subs %3, %3, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%2]! \n"
"bgt 1b \n"
: "+r"(src_y), // %0
"+r"(src_vu), // %1
"+r"(dst_argb), // %2
@ -537,11 +537,11 @@ void YUY2ToARGBRow_NEON(const uint8_t* src_yuy2,
const struct YuvConstants* yuvconstants,
int width) {
asm volatile(YUVTORGB_SETUP
"vmov.u8 d23, #255 \n"
"1: \n" READYUY2 YUVTORGB
"subs %2, %2, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%1]! \n"
"bgt 1b \n"
"vmov.u8 d23, #255 \n"
"1: \n" READYUY2 YUVTORGB
"subs %2, %2, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%1]! \n"
"bgt 1b \n"
: "+r"(src_yuy2), // %0
"+r"(dst_argb), // %1
"+r"(width) // %2
@ -558,11 +558,11 @@ void UYVYToARGBRow_NEON(const uint8_t* src_uyvy,
const struct YuvConstants* yuvconstants,
int width) {
asm volatile(YUVTORGB_SETUP
"vmov.u8 d23, #255 \n"
"1: \n" READUYVY YUVTORGB
"subs %2, %2, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%1]! \n"
"bgt 1b \n"
"vmov.u8 d23, #255 \n"
"1: \n" READUYVY YUVTORGB
"subs %2, %2, #8 \n"
"vst4.8 {d20, d21, d22, d23}, [%1]! \n"
"bgt 1b \n"
: "+r"(src_uyvy), // %0
"+r"(dst_argb), // %1
"+r"(width) // %2

View File

@ -595,7 +595,7 @@ void NV12ToRGB565Row_NEON(const uint8_t* src_y,
int width) {
asm volatile(
YUVTORGB_SETUP "1: \n" READNV12
"prfm pldl1keep, [%0, 448] \n" YUVTORGB(
"prfm pldl1keep, [%0, 448] \n" YUVTORGB(
v22, v21, v20) ARGBTORGB565
"prfm pldl1keep, [%1, 256] \n"
"subs %w3, %w3, #8 \n"

View File

@ -28,25 +28,25 @@ extern "C" {
#if defined(_M_X64)
// Read 8 UV from 444
#define READYUV444 \
xmm0 = _mm_loadl_epi64((__m128i*)u_buf); \
xmm1 = _mm_loadl_epi64((__m128i*)(u_buf + offset)); \
xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \
u_buf += 8; \
xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \
xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \
#define READYUV444 \
xmm0 = _mm_loadl_epi64((__m128i*)u_buf); \
xmm1 = _mm_loadl_epi64((__m128i*)(u_buf + offset)); \
xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \
u_buf += 8; \
xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \
xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \
y_buf += 8;
// Read 8 UV from 444, With 8 Alpha.
#define READYUVA444 \
xmm0 = _mm_loadl_epi64((__m128i*)u_buf); \
xmm1 = _mm_loadl_epi64((__m128i*)(u_buf + offset)); \
xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \
u_buf += 8; \
xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \
xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \
y_buf += 8; \
xmm5 = _mm_loadl_epi64((__m128i*)a_buf); \
#define READYUVA444 \
xmm0 = _mm_loadl_epi64((__m128i*)u_buf); \
xmm1 = _mm_loadl_epi64((__m128i*)(u_buf + offset)); \
xmm0 = _mm_unpacklo_epi8(xmm0, xmm1); \
u_buf += 8; \
xmm4 = _mm_loadl_epi64((__m128i*)y_buf); \
xmm4 = _mm_unpacklo_epi8(xmm4, xmm4); \
y_buf += 8; \
xmm5 = _mm_loadl_epi64((__m128i*)a_buf); \
a_buf += 8;
// Read 4 UV from 422, upsample to 8 UV.

View File

@ -991,20 +991,20 @@ void ScaleUVRowDownEven_NEON(const uint8_t* src_ptr,
(void)src_stride;
asm volatile(
"1: \n"
"vld1.16 {d0[0]}, [%0], %6 \n"
"vld1.16 {d0[1]}, [%1], %6 \n"
"vld1.16 {d0[2]}, [%2], %6 \n"
"vld1.16 {d0[3]}, [%3], %6 \n"
"subs %5, %5, #4 \n" // 4 pixels per loop.
"vst1.8 {d0}, [%4]! \n"
"bgt 1b \n"
: "+r"(src_ptr), // %0
"+r"(src1_ptr), // %1
"+r"(src2_ptr), // %2
"+r"(src3_ptr), // %3
"+r"(dst_ptr), // %4
"+r"(dst_width) // %5
: "r"(src_stepx * 8) // %6
"vld1.16 {d0[0]}, [%0], %6 \n"
"vld1.16 {d0[1]}, [%1], %6 \n"
"vld1.16 {d0[2]}, [%2], %6 \n"
"vld1.16 {d0[3]}, [%3], %6 \n"
"subs %5, %5, #4 \n" // 4 pixels per loop.
"vst1.8 {d0}, [%4]! \n"
"bgt 1b \n"
: "+r"(src_ptr), // %0
"+r"(src1_ptr), // %1
"+r"(src2_ptr), // %2
"+r"(src3_ptr), // %3
"+r"(dst_ptr), // %4
"+r"(dst_width) // %5
: "r"(src_stepx * 8) // %6
: "memory", "cc", "d0");
}

View File

@ -305,7 +305,7 @@ static void ScaleUVDownEven(int src_width,
ScaleUVRowDownEven = ScaleUVRowDownEven_NEON;
}
}
#endif// TODO(fbarchard): Enable Box filter
#endif // TODO(fbarchard): Enable Box filter
#if defined(HAS_SCALEUVROWDOWNEVENBOX_NEON)
if (TestCpuFlag(kCpuHasNEON)) {
ScaleUVRowDownEven = filtering ? ScaleUVRowDownEvenBox_Any_NEON

View File

@ -208,7 +208,33 @@ static void YUVHToRGB(int y, int u, int v, int* r, int* g, int* b) {
*r = orig_pixels[2];
}
static void YUVRec2020ToRGB(int y, int u, int v, int* r, int* g, int* b) {
#define F422ToARGB(a, b, c, d, e, f, g, h, i, j) \
I422ToARGBMatrix(a, b, c, d, e, f, g, h, &kYuvF709Constants, i, j)
static void YUVFToRGB(int y, int u, int v, int* r, int* g, int* b) {
const int kWidth = 16;
const int kHeight = 1;
const int kPixels = kWidth * kHeight;
const int kHalfPixels = ((kWidth + 1) / 2) * ((kHeight + 1) / 2);
SIMD_ALIGNED(uint8_t orig_y[16]);
SIMD_ALIGNED(uint8_t orig_u[8]);
SIMD_ALIGNED(uint8_t orig_v[8]);
SIMD_ALIGNED(uint8_t orig_pixels[16 * 4]);
memset(orig_y, y, kPixels);
memset(orig_u, u, kHalfPixels);
memset(orig_v, v, kHalfPixels);
/* YUV converted to ARGB. */
F422ToARGB(orig_y, kWidth, orig_u, (kWidth + 1) / 2, orig_v, (kWidth + 1) / 2,
orig_pixels, kWidth * 4, kWidth, kHeight);
*b = orig_pixels[0];
*g = orig_pixels[1];
*r = orig_pixels[2];
}
static void YUVUToRGB(int y, int u, int v, int* r, int* g, int* b) {
const int kWidth = 16;
const int kHeight = 1;
const int kPixels = kWidth * kHeight;
@ -401,13 +427,15 @@ static void YUVHToRGBReference(int y, int u, int v, int* r, int* g, int* b) {
*b = RoundToByte((y - 16) * 1.164 - (u - 128) * -2.112);
}
// BT.709 full range YUV to RGB reference
static void YUVFToRGBReference(int y, int u, int v, int* r, int* g, int* b) {
*r = RoundToByte(y - (v - 128) * -1.5748);
*g = RoundToByte(y - (u - 128) * 0.18732 - (v - 128) * 0.46812);
*b = RoundToByte(y - (u - 128) * -1.8556);
}
// BT.2020 YUV to RGB reference
static void YUVRec2020ToRGBReference(int y,
int u,
int v,
int* r,
int* g,
int* b) {
static void YUVUToRGBReference(int y, int u, int v, int* r, int* g, int* b) {
*r = RoundToByte((y - 16) * 1.164384 - (v - 128) * -1.67867);
*g = RoundToByte((y - 16) * 1.164384 - (u - 128) * 0.187326 -
(v - 128) * 0.65042);
@ -633,7 +661,7 @@ TEST_F(LibYUVColorTest, TestFullYUVH) {
PrintHistogram(rh, gh, bh);
}
TEST_F(LibYUVColorTest, TestFullYUVRec2020) {
TEST_F(LibYUVColorTest, TestFullYUVF) {
int rh[256] = {
0,
};
@ -648,8 +676,37 @@ TEST_F(LibYUVColorTest, TestFullYUVRec2020) {
for (int y2 = 0; y2 < 256; y2 += FASTSTEP) {
int r0, g0, b0, r1, g1, b1;
int y = RANDOM256(y2);
YUVRec2020ToRGBReference(y, u, v, &r0, &g0, &b0);
YUVRec2020ToRGB(y, u, v, &r1, &g1, &b1);
YUVFToRGBReference(y, u, v, &r0, &g0, &b0);
YUVFToRGB(y, u, v, &r1, &g1, &b1);
EXPECT_NEAR(r0, r1, 5);
EXPECT_NEAR(g0, g1, 5);
EXPECT_NEAR(b0, b1, 5);
++rh[r1 - r0 + 128];
++gh[g1 - g0 + 128];
++bh[b1 - b0 + 128];
}
}
}
PrintHistogram(rh, gh, bh);
}
TEST_F(LibYUVColorTest, TestFullYUVU) {
int rh[256] = {
0,
};
int gh[256] = {
0,
};
int bh[256] = {
0,
};
for (int u = 0; u < 256; ++u) {
for (int v = 0; v < 256; ++v) {
for (int y2 = 0; y2 < 256; y2 += FASTSTEP) {
int r0, g0, b0, r1, g1, b1;
int y = RANDOM256(y2);
YUVUToRGBReference(y, u, v, &r0, &g0, &b0);
YUVUToRGB(y, u, v, &r1, &g1, &b1);
EXPECT_NEAR(r0, r1, ERROR_R);
EXPECT_NEAR(g0, g1, ERROR_G);
// TODO(crbug.com/libyuv/863): Reduce the errors in the B channel.

View File

@ -546,6 +546,20 @@ TESTBIPLANARTOBP(NV12, 2, 2, NV12Mirror, 2, 2)
TESTBIPLANARTOP(NV12, 2, 2, I420, 2, 2)
TESTBIPLANARTOP(NV21, 2, 2, I420, 2, 2)
// Provide matrix wrappers
#define F420ToABGR(a, b, c, d, e, f, g, h, i, j) \
I420ToARGBMatrix(a, b, e, f, c, d, g, h, &kYvuF709Constants, i, j)
#define F420ToARGB(a, b, c, d, e, f, g, h, i, j) \
I420ToARGBMatrix(a, b, c, d, e, f, g, h, &kYuvF709Constants, i, j)
#define F422ToABGR(a, b, c, d, e, f, g, h, i, j) \
I422ToARGBMatrix(a, b, e, f, c, d, g, h, &kYvuF709Constants, i, j)
#define F422ToARGB(a, b, c, d, e, f, g, h, i, j) \
I422ToARGBMatrix(a, b, c, d, e, f, g, h, &kYuvF709Constants, i, j)
#define F444ToABGR(a, b, c, d, e, f, g, h, i, j) \
I444ToARGBMatrix(a, b, e, f, c, d, g, h, &kYvuF709Constants, i, j)
#define F444ToARGB(a, b, c, d, e, f, g, h, i, j) \
I444ToARGBMatrix(a, b, c, d, e, f, g, h, &kYuvF709Constants, i, j)
#define ALIGNINT(V, ALIGN) (((V) + (ALIGN)-1) / (ALIGN) * (ALIGN))
#define TESTPLANARTOBI(FMT_PLANAR, SUBSAMP_X, SUBSAMP_Y, FMT_B, BPP_B, ALIGN, \
@ -611,6 +625,8 @@ TESTPLANARTOB(I420, 2, 2, ARGB, 4, 4, 1)
TESTPLANARTOB(I420, 2, 2, ABGR, 4, 4, 1)
TESTPLANARTOB(J420, 2, 2, ARGB, 4, 4, 1)
TESTPLANARTOB(J420, 2, 2, ABGR, 4, 4, 1)
TESTPLANARTOB(F420, 2, 2, ARGB, 4, 4, 1)
TESTPLANARTOB(F420, 2, 2, ABGR, 4, 4, 1)
TESTPLANARTOB(H420, 2, 2, ARGB, 4, 4, 1)
TESTPLANARTOB(H420, 2, 2, ABGR, 4, 4, 1)
TESTPLANARTOB(U420, 2, 2, ARGB, 4, 4, 1)
@ -726,6 +742,12 @@ TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
#define J420AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I420AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvJPEGConstants, k, \
l, m)
#define F420AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I420AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define F420AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I420AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define H420AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I420AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvH709Constants, k, \
l, m)
@ -744,6 +766,12 @@ TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
#define J422AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I422AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvJPEGConstants, k, \
l, m)
#define F422AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I422AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define F422AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I422AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define H422AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I422AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvH709Constants, k, \
l, m)
@ -762,6 +790,12 @@ TESTPLANARTOB(H420, 2, 2, AR30, 4, 4, 1)
#define J444AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I444AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvJPEGConstants, k, \
l, m)
#define F444AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I444AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define F444AlphaToABGR(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I444AlphaToABGRMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvF709Constants, k, \
l, m)
#define H444AlphaToARGB(a, b, c, d, e, f, g, h, i, j, k, l, m) \
I444AlphaToARGBMatrix(a, b, c, d, e, f, g, h, i, j, &kYuvH709Constants, k, \
l, m)
@ -2812,12 +2846,16 @@ TESTQPLANARTOE(J420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(J420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(H420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(H420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(F420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(F420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(U420Alpha, 2, 2, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(U420Alpha, 2, 2, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(I422Alpha, 2, 1, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(I422Alpha, 2, 1, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(J422Alpha, 2, 1, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(J422Alpha, 2, 1, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(F422Alpha, 2, 1, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(F422Alpha, 2, 1, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(H422Alpha, 2, 1, ARGB, 1, 4, ABGR, 4)
TESTQPLANARTOE(H422Alpha, 2, 1, ABGR, 1, 4, ARGB, 4)
TESTQPLANARTOE(U422Alpha, 2, 1, ARGB, 1, 4, ABGR, 4)