mirror of
https://chromium.googlesource.com/libyuv/libyuv
synced 2026-04-30 19:09:18 +08:00
Add ARGBToI4xxMatrix variants
This was implemented by Gemini followed by manual review and some tweaking for style. The 601 and JPEG constants are fully verified against the existing non-matrix implementations. On x86 the C-only versions appear to be about 25% slower than the optimized ones. Bug: libyuv:42280902 Change-Id: Ia5b7cb499bad5c76faec53f36086ebb18f2b530f Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/7512030 Reviewed-by: Frank Barchard <fbarchard@chromium.org> Reviewed-by: Wan-Teh Chang <wtc@google.com> Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
This commit is contained in:
parent
6067afde56
commit
30809ff64a
@ -831,6 +831,20 @@ int ARGBToI420(const uint8_t* src_argb,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// ARGB little endian (bgra in memory) to I420 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI420Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
const struct ArgbConstants* argbconstants,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert ARGB to I420 with Alpha
|
||||
LIBYUV_API
|
||||
int ARGBToI420Alpha(const uint8_t* src_argb,
|
||||
|
||||
@ -29,6 +29,15 @@ LIBYUV_API extern const struct YuvConstants kYuvF709Constants; // BT.709 full
|
||||
LIBYUV_API extern const struct YuvConstants kYuv2020Constants; // BT.2020
|
||||
LIBYUV_API extern const struct YuvConstants kYuvV2020Constants; // BT.2020 full
|
||||
|
||||
// Conversion matrix for RGB to YUV
|
||||
LIBYUV_API extern const struct ArgbConstants kArgbI601Constants; // BT.601
|
||||
LIBYUV_API extern const struct ArgbConstants kArgbJPEGConstants; // BT.601 full
|
||||
LIBYUV_API extern const struct ArgbConstants kArgbH709Constants; // BT.709
|
||||
LIBYUV_API extern const struct ArgbConstants kArgbF709Constants; // BT.709 full
|
||||
LIBYUV_API extern const struct ArgbConstants kArgbU2020Constants; // BT.2020
|
||||
LIBYUV_API extern const struct ArgbConstants
|
||||
kArgbV2020Constants; // BT.2020 full
|
||||
|
||||
// Conversion matrix for YVU to BGR
|
||||
LIBYUV_API extern const struct YuvConstants kYvuI601Constants; // BT.601
|
||||
LIBYUV_API extern const struct YuvConstants kYvuJPEGConstants; // BT.601 full
|
||||
|
||||
@ -153,6 +153,20 @@ int ARGBToI444(const uint8_t* src_argb,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert ARGB To I444 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI444Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
const struct ArgbConstants* argbconstants,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert ARGB to AR64.
|
||||
LIBYUV_API
|
||||
int ARGBToAR64(const uint8_t* src_argb,
|
||||
@ -190,6 +204,20 @@ int ARGBToI422(const uint8_t* src_argb,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert ARGB To I422 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI422Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
const struct ArgbConstants* argbconstants,
|
||||
int width,
|
||||
int height);
|
||||
|
||||
// Convert ARGB To I420. (also in convert.h)
|
||||
LIBYUV_API
|
||||
int ARGBToI420(const uint8_t* src_argb,
|
||||
|
||||
@ -971,6 +971,14 @@ typedef uint32_t ulvec32[8];
|
||||
typedef uint8_t ulvec8[32];
|
||||
#endif
|
||||
|
||||
struct ArgbConstants {
|
||||
uint8_t kRGBToY[32];
|
||||
int16_t kRGBToU[16];
|
||||
int16_t kRGBToV[16];
|
||||
uint16_t kAddY[16];
|
||||
uint16_t kAddUV[16];
|
||||
};
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm__) || defined(__riscv)
|
||||
// This struct is for ARM and RISC-V color conversion.
|
||||
struct YuvConstants {
|
||||
@ -2074,6 +2082,22 @@ void RAWToYJRow_LASX(const uint8_t* src_raw, uint8_t* dst_yj, int width);
|
||||
|
||||
void ARGBToYRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width);
|
||||
void ARGBToYJRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width);
|
||||
void ARGBToYMatrixRow_C(const uint8_t* src_argb,
|
||||
uint8_t* dst_y,
|
||||
int width,
|
||||
const struct ArgbConstants* c);
|
||||
void ARGBToUVMatrixRow_C(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_u,
|
||||
uint8_t* dst_v,
|
||||
int width,
|
||||
const struct ArgbConstants* c);
|
||||
void ARGBToUV444MatrixRow_C(const uint8_t* src_argb,
|
||||
uint8_t* dst_u,
|
||||
uint8_t* dst_v,
|
||||
int width,
|
||||
const struct ArgbConstants* c);
|
||||
|
||||
void ABGRToYJRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width);
|
||||
void RGBAToYJRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width);
|
||||
void BGRAToYRow_C(const uint8_t* src_rgb, uint8_t* dst_y, int width);
|
||||
|
||||
@ -2144,6 +2144,55 @@ int ARGBToI420(const uint8_t* src_argb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ARGB little endian (bgra in memory) to I420 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI420Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
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 (*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 (!src_argb || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
|
||||
height == 0) {
|
||||
return -1;
|
||||
}
|
||||
// Negative height means invert the image.
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
src_argb = src_argb + (height - 1) * src_stride_argb;
|
||||
src_stride_argb = -src_stride_argb;
|
||||
}
|
||||
|
||||
for (y = 0; y < height - 1; y += 2) {
|
||||
ARGBToUVMatrixRow(src_argb, src_stride_argb, dst_u, dst_v, width,
|
||||
argbconstants);
|
||||
ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
|
||||
ARGBToYMatrixRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width,
|
||||
argbconstants);
|
||||
src_argb += src_stride_argb * 2;
|
||||
dst_y += dst_stride_y * 2;
|
||||
dst_u += dst_stride_u;
|
||||
dst_v += dst_stride_v;
|
||||
}
|
||||
if (height & 1) {
|
||||
ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, argbconstants);
|
||||
ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_EXTRACTALPHA
|
||||
// Convert ARGB to I420 with Alpha
|
||||
// The following version calls ARGBExtractAlpha on the full image.
|
||||
|
||||
@ -165,6 +165,48 @@ int ARGBToI444(const uint8_t* src_argb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert ARGB To I444 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI444Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
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 (!src_argb || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
|
||||
height == 0) {
|
||||
return -1;
|
||||
}
|
||||
// Negative height means invert the image.
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
src_argb = src_argb + (height - 1) * src_stride_argb;
|
||||
src_stride_argb = -src_stride_argb;
|
||||
}
|
||||
|
||||
for (y = 0; y < height; ++y) {
|
||||
ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
|
||||
ARGBToUV444MatrixRow(src_argb, dst_u, dst_v, width, argbconstants);
|
||||
src_argb += src_stride_argb;
|
||||
dst_y += dst_stride_y;
|
||||
dst_u += dst_stride_u;
|
||||
dst_v += dst_stride_v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ARGB little endian (bgra in memory) to I422
|
||||
LIBYUV_API
|
||||
int ARGBToI422(const uint8_t* src_argb,
|
||||
@ -324,6 +366,48 @@ int ARGBToI422(const uint8_t* src_argb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Convert ARGB To I422 with matrix.
|
||||
LIBYUV_API
|
||||
int ARGBToI422Matrix(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_y,
|
||||
int dst_stride_y,
|
||||
uint8_t* dst_u,
|
||||
int dst_stride_u,
|
||||
uint8_t* dst_v,
|
||||
int dst_stride_v,
|
||||
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 (*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 (!src_argb || !dst_y || !dst_u || !dst_v || !argbconstants || width <= 0 ||
|
||||
height == 0) {
|
||||
return -1;
|
||||
}
|
||||
// Negative height means invert the image.
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
src_argb = src_argb + (height - 1) * src_stride_argb;
|
||||
src_stride_argb = -src_stride_argb;
|
||||
}
|
||||
|
||||
for (y = 0; y < height; ++y) {
|
||||
ARGBToUVMatrixRow(src_argb, 0, dst_u, dst_v, width, argbconstants);
|
||||
ARGBToYMatrixRow(src_argb, dst_y, width, argbconstants);
|
||||
src_argb += src_stride_argb;
|
||||
dst_y += dst_stride_y;
|
||||
dst_u += dst_stride_u;
|
||||
dst_v += dst_stride_v;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBYUV_API
|
||||
int ARGBToNV12(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
|
||||
@ -756,6 +756,92 @@ MAKEROWYJ(RGB24, 2, 1, 0, 3)
|
||||
MAKEROWYJ(RAW, 0, 1, 2, 3)
|
||||
#undef MAKEROWYJ
|
||||
|
||||
static __inline uint8_t RGBToYMatrix(uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
const struct ArgbConstants* c) {
|
||||
return (c->kRGBToY[2] * r + c->kRGBToY[1] * g + c->kRGBToY[0] * b +
|
||||
c->kAddY[0]) >>
|
||||
8;
|
||||
}
|
||||
static __inline uint8_t RGBToUMatrix(uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
const struct ArgbConstants* c) {
|
||||
return (c->kRGBToU[2] * r + c->kRGBToU[1] * g + c->kRGBToU[0] * b +
|
||||
c->kAddUV[0]) >>
|
||||
8;
|
||||
}
|
||||
static __inline uint8_t RGBToVMatrix(uint8_t r,
|
||||
uint8_t g,
|
||||
uint8_t b,
|
||||
const struct ArgbConstants* c) {
|
||||
return (c->kRGBToV[2] * r + c->kRGBToV[1] * g + c->kRGBToV[0] * b +
|
||||
c->kAddUV[0]) >>
|
||||
8;
|
||||
}
|
||||
|
||||
void ARGBToYMatrixRow_C(const uint8_t* src_argb,
|
||||
uint8_t* dst_y,
|
||||
int width,
|
||||
const struct ArgbConstants* c) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
dst_y[0] = RGBToYMatrix(src_argb[2], src_argb[1], src_argb[0], c);
|
||||
src_argb += 4;
|
||||
dst_y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ARGBToUVMatrixRow_C(const uint8_t* src_argb,
|
||||
int src_stride_argb,
|
||||
uint8_t* dst_u,
|
||||
uint8_t* dst_v,
|
||||
int width,
|
||||
const struct ArgbConstants* c) {
|
||||
const uint8_t* src_argb1 = src_argb + src_stride_argb;
|
||||
int x;
|
||||
for (x = 0; x < width - 1; x += 2) {
|
||||
uint8_t ab =
|
||||
(src_argb[0] + src_argb[4] + src_argb1[0] + src_argb1[4] + 2) >> 2;
|
||||
uint8_t ag =
|
||||
(src_argb[1] + src_argb[5] + src_argb1[1] + src_argb1[5] + 2) >> 2;
|
||||
uint8_t ar =
|
||||
(src_argb[2] + src_argb[6] + src_argb1[2] + src_argb1[6] + 2) >> 2;
|
||||
dst_u[0] = RGBToUMatrix(ar, ag, ab, c);
|
||||
dst_v[0] = RGBToVMatrix(ar, ag, ab, c);
|
||||
src_argb += 8;
|
||||
src_argb1 += 8;
|
||||
dst_u += 1;
|
||||
dst_v += 1;
|
||||
}
|
||||
if (width & 1) {
|
||||
uint8_t ab = (src_argb[0] + src_argb1[0] + 1) >> 1;
|
||||
uint8_t ag = (src_argb[1] + src_argb1[1] + 1) >> 1;
|
||||
uint8_t ar = (src_argb[2] + src_argb1[2] + 1) >> 1;
|
||||
dst_u[0] = RGBToUMatrix(ar, ag, ab, c);
|
||||
dst_v[0] = RGBToVMatrix(ar, ag, ab, c);
|
||||
}
|
||||
}
|
||||
|
||||
void ARGBToUV444MatrixRow_C(const uint8_t* src_argb,
|
||||
uint8_t* dst_u,
|
||||
uint8_t* dst_v,
|
||||
int width,
|
||||
const struct ArgbConstants* c) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
uint8_t ab = src_argb[0];
|
||||
uint8_t ag = src_argb[1];
|
||||
uint8_t ar = src_argb[2];
|
||||
dst_u[0] = RGBToUMatrix(ar, ag, ab, c);
|
||||
dst_v[0] = RGBToVMatrix(ar, ag, ab, c);
|
||||
src_argb += 4;
|
||||
dst_u += 1;
|
||||
dst_v += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void RGB565ToYRow_C(const uint8_t* src_rgb565, uint8_t* dst_y, int width) {
|
||||
int x;
|
||||
for (x = 0; x < width; ++x) {
|
||||
@ -1399,6 +1485,15 @@ void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) {
|
||||
{YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB, YB}}
|
||||
#endif
|
||||
|
||||
#define ARGBCONSTANTSBODY(RY, GY, BY, RU, GU, BU, RV, GV, BV, AY, AUV) \
|
||||
{{BY, GY, RY, 0, BY, GY, RY, 0, BY, GY, RY, 0, BY, GY, RY, 0, \
|
||||
BY, GY, RY, 0, BY, GY, RY, 0, BY, GY, RY, 0, BY, GY, RY, 0}, \
|
||||
{BU, GU, RU, 0, BU, GU, RU, 0, BU, GU, RU, 0, BU, GU, RU, 0}, \
|
||||
{BV, GV, RV, 0, BV, GV, RV, 0, BV, GV, RV, 0, BV, GV, RV, 0}, \
|
||||
{AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY, AY}, \
|
||||
{AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, AUV, \
|
||||
AUV, AUV}}
|
||||
|
||||
// clang-format on
|
||||
|
||||
#define MAKEYUVCONSTANTS(name, YG, YB, UB, UG, VG, VR) \
|
||||
@ -1407,6 +1502,94 @@ void J400ToARGBRow_C(const uint8_t* src_y, uint8_t* dst_argb, int width) {
|
||||
const struct YuvConstants SIMD_ALIGNED(kYvu##name##Constants) = \
|
||||
YUVCONSTANTSBODY(YG, YB, VR, VG, UG, UB);
|
||||
|
||||
#define MAKEARGBCONSTANTS(name, RY, GY, BY, RU, GU, BU, RV, GV, BV, AY, AUV) \
|
||||
const struct ArgbConstants SIMD_ALIGNED(kArgb##name##Constants) = \
|
||||
ARGBCONSTANTSBODY(RY, GY, BY, RU, GU, BU, RV, GV, BV, AY, AUV);
|
||||
|
||||
// BT.601 limited range RGB to YUV coefficients
|
||||
// RY = round(0.299 * 219 / 255 * 256) = 66
|
||||
// GY = round(0.587 * 219 / 255 * 256) = 129
|
||||
// BY = round(0.114 * 219 / 255 * 256) = 25
|
||||
// BU = round(0.500 * 224 / 255 * 256) = 112
|
||||
// RU = round(-0.299 / (1 - 0.114) * 112.4) = -38
|
||||
// GU = round(-0.587 / (1 - 0.114) * 112.4) = -74
|
||||
// RV = 112
|
||||
// GV = round(-0.587 / (1 - 0.299) * 112.4) = -94
|
||||
// BV = round(-0.114 / (1 - 0.299) * 112.4) = -18
|
||||
// AY = 16 * 256 + 128 = 4224
|
||||
// AUV = 128 * 256 = 32768
|
||||
MAKEARGBCONSTANTS(I601, 66, 129, 25, -38, -74, 112, 112, -94, -18, 4224, 32768)
|
||||
|
||||
// BT.601 full range RGB to YUV coefficients (aka JPEG)
|
||||
// RY = round(0.299 * 256) = 77
|
||||
// GY = round(0.587 * 256) = 150
|
||||
// BY = round(0.114 * 256) = 29
|
||||
// BU = 128
|
||||
// RU = round(-0.299 / (1 - 0.114) * 128) = -43
|
||||
// GU = round(-0.587 / (1 - 0.114) * 128) = -85
|
||||
// RV = 128
|
||||
// GV = round(-0.587 / (1 - 0.299) * 128) = -107
|
||||
// BV = round(-0.114 / (1 - 0.299) * 128) = -21
|
||||
// AY = 128
|
||||
// AUV = 32768
|
||||
MAKEARGBCONSTANTS(JPEG, 77, 150, 29, -43, -85, 128, 128, -107, -21, 128, 32768)
|
||||
|
||||
// BT.709 limited range RGB to YUV coefficients
|
||||
// RY = round(0.2126 * 219 / 255 * 256) = 47
|
||||
// GY = round(0.7152 * 219 / 255 * 256) = 157
|
||||
// BY = round(0.0722 * 219 / 255 * 256) = 16
|
||||
// BU = round(0.500 * 224 / 255 * 256) = 112
|
||||
// RU = round(-0.2126 / (1 - 0.0722) * 112.4) = -26
|
||||
// GU = round(-0.7152 / (1 - 0.0722) * 112.4) = -86
|
||||
// RV = 112
|
||||
// GV = round(-0.7152 / (1 - 0.2126) * 112.4) = -102
|
||||
// BV = round(-0.0722 / (1 - 0.2126) * 112.4) = -10
|
||||
// AY = 16 * 256 + 128 = 4224
|
||||
// AUV = 128 * 256 = 32768
|
||||
MAKEARGBCONSTANTS(H709, 47, 157, 16, -26, -86, 112, 112, -102, -10, 4224, 32768)
|
||||
|
||||
// BT.709 full range RGB to YUV coefficients
|
||||
// RY = round(0.2126 * 256) = 54
|
||||
// GY = round(0.7152 * 256) = 183
|
||||
// BY = round(0.0722 * 256) = 19
|
||||
// BU = 128
|
||||
// RU = round(-0.2126 / (1 - 0.0722) * 128) = -29
|
||||
// GU = round(-0.7152 / (1 - 0.0722) * 128) = -99
|
||||
// RV = 128
|
||||
// GV = round(-0.7152 / (1 - 0.2126) * 128) = -116
|
||||
// BV = round(-0.0722 / (1 - 0.2126) * 128) = -12
|
||||
// AY = 128
|
||||
// AUV = 32768
|
||||
MAKEARGBCONSTANTS(F709, 54, 183, 19, -29, -99, 128, 128, -116, -12, 128, 32768)
|
||||
|
||||
// BT.2020 limited range RGB to YUV coefficients
|
||||
// RY = round(0.2627 * 219 / 255 * 256) = 58
|
||||
// GY = round(0.6780 * 219 / 255 * 256) = 149
|
||||
// BY = round(0.0593 * 219 / 255 * 256) = 13
|
||||
// BU = 112
|
||||
// RU = round(-0.2627 / (1 - 0.0593) * 112.4) = -31
|
||||
// GU = round(-0.6780 / (1 - 0.0593) * 112.4) = -81
|
||||
// RV = 112
|
||||
// GV = round(-0.6780 / (1 - 0.2627) * 112.4) = -103
|
||||
// BV = round(-0.0593 / (1 - 0.2627) * 112.4) = -9
|
||||
// AY = 16 * 256 + 128 = 4224
|
||||
// AUV = 128 * 256 = 32768
|
||||
MAKEARGBCONSTANTS(U2020, 59, 148, 13, -31, -81, 112, 112, -103, -9, 4224, 32768)
|
||||
|
||||
// BT.2020 full range RGB to YUV coefficients
|
||||
// RY = round(0.2627 * 256) = 67
|
||||
// GY = round(0.6780 * 256) = 174
|
||||
// BY = round(0.0593 * 256) = 15
|
||||
// BU = 128
|
||||
// RU = round(-0.2627 / (1 - 0.0593) * 128) = -36
|
||||
// GU = round(-0.6780 / (1 - 0.0593) * 128) = -92
|
||||
// RV = 128
|
||||
// GV = round(-0.6780 / (1 - 0.2627) * 128) = -118
|
||||
// BV = round(-0.0593 / (1 - 0.2627) * 128) = -10
|
||||
// AY = 128
|
||||
// AUV = 32768
|
||||
MAKEARGBCONSTANTS(V2020, 67, 174, 15, -36, -92, 128, 128, -118, -10, 128, 32768)
|
||||
|
||||
// TODO(fbarchard): Generate SIMD structures from float matrix.
|
||||
|
||||
// BT.601 limited range YUV to RGB reference
|
||||
|
||||
@ -2128,6 +2128,194 @@ TEST_F(LibYUVConvertTest, TestJ420ToI420) {
|
||||
EXPECT_EQ(dst_v[2], 240);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVConvertTest, TestARGBToI420Matrix) {
|
||||
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_u, kWidth / 2 * kHeight / 2);
|
||||
align_buffer_page_end(dst_v, kWidth / 2 * kHeight / 2);
|
||||
|
||||
MemRandomize(src_argb, kWidth * kHeight * 4);
|
||||
|
||||
// BT.601
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbI601Constants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
align_buffer_page_end(ref_y, kWidth * kHeight);
|
||||
align_buffer_page_end(ref_u, kWidth / 2 * kHeight / 2);
|
||||
align_buffer_page_end(ref_v, kWidth / 2 * kHeight / 2);
|
||||
ARGBToI420(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth / 2, ref_v,
|
||||
kWidth / 2, kWidth, kHeight);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y[i], ref_y[i]);
|
||||
}
|
||||
for (int i = 0; i < kWidth / 2 * kHeight / 2; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
// JPEG
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbJPEGConstants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
ARGBToJ420(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth / 2, ref_v,
|
||||
kWidth / 2, kWidth, kHeight);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y[i], ref_y[i]);
|
||||
}
|
||||
for (int i = 0; i < kWidth / 2 * kHeight / 2; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
// BT.709
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbH709Constants, kWidth, kHeight);
|
||||
// Just check if it returns 0 for now.
|
||||
// In a real test we'd have reference values.
|
||||
|
||||
// BT.2020
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbU2020Constants, kWidth, kHeight);
|
||||
|
||||
// Reference BT.709 (limited range)
|
||||
// Y = round(0.2126 * 219 / 255 * R + 0.7152 * 219 / 255 * G + 0.0722 * 219 / 255 * B + 16)
|
||||
// Y = round(0.1826 * R + 0.6142 * G + 0.0620 * B + 16)
|
||||
// 47 * 255 + 157 * 255 + 16 * 255 + 4224 = 11985 + 40035 + 4080 + 4224 = 60324
|
||||
// 60324 / 256 = 235.64 -> 235. Correct.
|
||||
|
||||
for (int i = 0; i < kWidth * kHeight * 4; ++i) src_argb[i] = 255;
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbH709Constants, kWidth, kHeight);
|
||||
EXPECT_EQ(dst_y[0], 235);
|
||||
EXPECT_EQ(dst_u[0], 128);
|
||||
EXPECT_EQ(dst_v[0], 128);
|
||||
|
||||
for (int i = 0; i < kWidth * kHeight * 4; i += 4) {
|
||||
src_argb[i + 0] = 0; // B
|
||||
src_argb[i + 1] = 0; // G
|
||||
src_argb[i + 2] = 255; // R
|
||||
src_argb[i + 3] = 255; // A
|
||||
}
|
||||
ARGBToI420Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbH709Constants, kWidth, kHeight);
|
||||
// Y = 47 * 255 + 4224 = 11985 + 4224 = 16209. 16209 / 256 = 63.3 -> 63.
|
||||
EXPECT_EQ(dst_y[0], 63);
|
||||
// U = -26 * 255 + 32768 = -6630 + 32768 = 26138. 26138 / 256 = 102.1 -> 102.
|
||||
EXPECT_EQ(dst_u[0], 102);
|
||||
// V = 112 * 255 + 32768 = 28560 + 32768 = 61328. 61328 / 256 = 239.5 -> 239.
|
||||
EXPECT_EQ(dst_v[0], 239);
|
||||
|
||||
free_aligned_buffer_page_end(src_argb);
|
||||
free_aligned_buffer_page_end(dst_y);
|
||||
free_aligned_buffer_page_end(dst_u);
|
||||
free_aligned_buffer_page_end(dst_v);
|
||||
free_aligned_buffer_page_end(ref_y);
|
||||
free_aligned_buffer_page_end(ref_u);
|
||||
free_aligned_buffer_page_end(ref_v);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVConvertTest, TestARGBToI422Matrix) {
|
||||
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_u, kWidth / 2 * kHeight);
|
||||
align_buffer_page_end(dst_v, kWidth / 2 * kHeight);
|
||||
|
||||
MemRandomize(src_argb, kWidth * kHeight * 4);
|
||||
|
||||
// BT.601
|
||||
ARGBToI422Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbI601Constants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
align_buffer_page_end(ref_y, kWidth * kHeight);
|
||||
align_buffer_page_end(ref_u, kWidth / 2 * kHeight);
|
||||
align_buffer_page_end(ref_v, kWidth / 2 * kHeight);
|
||||
ARGBToI422(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth / 2, ref_v,
|
||||
kWidth / 2, kWidth, kHeight);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y[i], ref_y[i]);
|
||||
}
|
||||
for (int i = 0; i < kWidth / 2 * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
// JPEG
|
||||
ARGBToI422Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbJPEGConstants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
ARGBToJ422(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth / 2, ref_v,
|
||||
kWidth / 2, kWidth, kHeight);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y[i], ref_y[i]);
|
||||
}
|
||||
for (int i = 0; i < kWidth / 2 * kHeight / 2; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
free_aligned_buffer_page_end(src_argb);
|
||||
free_aligned_buffer_page_end(dst_y);
|
||||
free_aligned_buffer_page_end(dst_u);
|
||||
free_aligned_buffer_page_end(dst_v);
|
||||
free_aligned_buffer_page_end(ref_y);
|
||||
free_aligned_buffer_page_end(ref_u);
|
||||
free_aligned_buffer_page_end(ref_v);
|
||||
}
|
||||
|
||||
TEST_F(LibYUVConvertTest, TestARGBToI444Matrix) {
|
||||
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_u, kWidth * kHeight);
|
||||
align_buffer_page_end(dst_v, kWidth * kHeight);
|
||||
|
||||
MemRandomize(src_argb, kWidth * kHeight * 4);
|
||||
|
||||
// BT.601
|
||||
ARGBToI444Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth, dst_v,
|
||||
kWidth, &kArgbI601Constants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
align_buffer_page_end(ref_y, kWidth * kHeight);
|
||||
align_buffer_page_end(ref_u, kWidth * kHeight);
|
||||
align_buffer_page_end(ref_v, kWidth * kHeight);
|
||||
ARGBToI444(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth, ref_v, 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; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
// JPEG
|
||||
ARGBToI444Matrix(src_argb, kWidth * 4, dst_y, kWidth, dst_u, kWidth / 2,
|
||||
dst_v, kWidth / 2, &kArgbJPEGConstants, kWidth, kHeight);
|
||||
// Verify against non-matrix version
|
||||
ARGBToJ444(src_argb, kWidth * 4, ref_y, kWidth, ref_u, kWidth / 2, ref_v,
|
||||
kWidth / 2, kWidth, kHeight);
|
||||
for (int i = 0; i < kWidth * kHeight; ++i) {
|
||||
ASSERT_EQ(dst_y[i], ref_y[i]);
|
||||
}
|
||||
for (int i = 0; i < kWidth / 2 * kHeight / 2; ++i) {
|
||||
ASSERT_EQ(dst_u[i], ref_u[i]);
|
||||
ASSERT_EQ(dst_v[i], ref_v[i]);
|
||||
}
|
||||
|
||||
free_aligned_buffer_page_end(src_argb);
|
||||
free_aligned_buffer_page_end(dst_y);
|
||||
free_aligned_buffer_page_end(dst_u);
|
||||
free_aligned_buffer_page_end(dst_v);
|
||||
free_aligned_buffer_page_end(ref_y);
|
||||
free_aligned_buffer_page_end(ref_u);
|
||||
free_aligned_buffer_page_end(ref_v);
|
||||
}
|
||||
|
||||
#endif // !defined(LEAN_TESTS)
|
||||
|
||||
} // namespace libyuv
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user