Bug 1493898 - P4. Add BT2020 YUV->RGB conversion. r=jgilbert

This is used by the basic compositor.
Re-using existing logic, however as with other conversion it only handles limited 8 bits ranges (16-235) and to make things worse is rounded aggressively as the focus is on speed.

Differential Revision: https://phabricator.services.mozilla.com/D25345

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jean-Yves Avenard 2019-04-11 16:57:39 +00:00
parent 09b5578692
commit fd742471ad
6 changed files with 252 additions and 78 deletions

View File

@ -54,7 +54,7 @@ extern "C" {
// -[3] Modified scaling functions as to handle YUV conversion buffer and
// use YUVBuferIter.
// -[4] Color conversion function selections in YUVBuferIter were borrowed from
// I444ToARGBMatrix(), I422ToARGBMatrix() and I420ToARGBMatrix()
// I444ToARGBMatrix(), I422ToARGBMatrix() and I420ToARGBMatrix()
static __inline int Abs(int v) {
return v >= 0 ? v : -v;
@ -210,10 +210,15 @@ void YUVBuferIter_Init(YUVBuferIter& iter, uint32 src_fourcc, mozilla::YUVColorS
iter.src_row_y = iter.src_y;
iter.src_row_u = iter.src_u;
iter.src_row_v = iter.src_v;
if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
iter.yuvconstants = &kYuvH709Constants;
} else {
iter.yuvconstants = &kYuvI601Constants;
switch (yuv_color_space) {
case mozilla::YUVColorSpace::BT2020:
iter.yuvconstants = &kYuv2020Constants;
break;
case mozilla::YUVColorSpace::BT709:
iter.yuvconstants = &kYuvH709Constants;
break;
default:
iter.yuvconstants = &kYuvI601Constants;
}
if (src_fourcc == FOURCC_I444) {
@ -531,7 +536,7 @@ static void ScaleYUVToARGBBilinearDown(int src_width, int src_height,
// Allocate 2 row of ARGB for source conversion.
const int kRowSize = (src_width * 4 + 15) & ~15;
align_buffer_64(argb_cnv_row, kRowSize * 2);
uint8* argb_cnv_rowptr = argb_cnv_row;
uint8* argb_cnv_rowptr = argb_cnv_row;
int argb_cnv_rowstride = kRowSize;
#if defined(HAS_INTERPOLATEROW_SSSE3)

View File

@ -64,26 +64,16 @@ libyuv::FourCC FourCCFromYUVType(YUVType aYUVType)
}
// Convert a frame of YUV to 32 bit ARGB.
void ConvertYCbCrToRGB32(const uint8* y_buf,
const uint8* u_buf,
const uint8* v_buf,
uint8* rgb_buf,
int pic_x,
int pic_y,
int pic_width,
int pic_height,
int y_pitch,
int uv_pitch,
int rgb_pitch,
YUVType yuv_type,
void ConvertYCbCrToRGB32(const uint8* y_buf, const uint8* u_buf,
const uint8* v_buf, uint8* rgb_buf, int pic_x,
int pic_y, int pic_width, int pic_height, int y_pitch,
int uv_pitch, int rgb_pitch, YUVType yuv_type,
YUVColorSpace yuv_color_space) {
// Deprecated function's conversion is accurate.
// libyuv converion is a bit inaccurate to get performance. It dynamically
// calculates RGB from YUV to use simd. In it, signed byte is used for conversion's
// coefficient, but it requests 129. libyuv cut 129 to 127. And only 6 bits are
// used for a decimal part during the dynamic calculation.
// calculates RGB from YUV to use simd. In it, signed byte is used for
// conversion's coefficient, but it requests 129. libyuv cut 129 to 127. And
// only 6 bits are used for a decimal part during the dynamic calculation.
//
// The function is still fast on some old intel chips.
// See Bug 1256475.
@ -96,69 +86,77 @@ void ConvertYCbCrToRGB32(const uint8* y_buf,
use_deprecated = false;
}
if (use_deprecated) {
ConvertYCbCrToRGB32_deprecated(y_buf, u_buf, v_buf, rgb_buf,
pic_x, pic_y, pic_width, pic_height,
y_pitch, uv_pitch, rgb_pitch, yuv_type);
ConvertYCbCrToRGB32_deprecated(y_buf, u_buf, v_buf, rgb_buf, pic_x, pic_y,
pic_width, pic_height, y_pitch, uv_pitch,
rgb_pitch, yuv_type);
return;
}
if (yuv_type == YV24) {
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x;
const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x;
if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
DebugOnly<int> err = libyuv::H444ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
MOZ_ASSERT(!err);
} else {
DebugOnly<int> err = libyuv::I444ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
decltype(libyuv::U444ToARGB)* fConvertYUVToARGB = nullptr;
switch (yuv_type) {
case YV24: {
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x;
const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x;
switch (yuv_color_space) {
case mozilla::YUVColorSpace::BT2020:
fConvertYUVToARGB = libyuv::U444ToARGB;
break;
case mozilla::YUVColorSpace::BT709:
fConvertYUVToARGB = libyuv::H444ToARGB;
break;
default:
fConvertYUVToARGB = libyuv::I444ToARGB;
break;
}
DebugOnly<int> err =
fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
rgb_buf, rgb_pitch, pic_width, pic_height);
MOZ_ASSERT(!err);
break;
}
} else if (yuv_type == YV16) {
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x / 2;
const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x / 2;
if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
DebugOnly<int> err = libyuv::H422ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
MOZ_ASSERT(!err);
} else {
DebugOnly<int> err = libyuv::I422ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
case YV16: {
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + uv_pitch * pic_y + pic_x / 2;
const uint8* src_v = v_buf + uv_pitch * pic_y + pic_x / 2;
switch (yuv_color_space) {
case mozilla::YUVColorSpace::BT2020:
fConvertYUVToARGB = libyuv::U422ToARGB;
break;
case mozilla::YUVColorSpace::BT709:
fConvertYUVToARGB = libyuv::H422ToARGB;
break;
default:
fConvertYUVToARGB = libyuv::I422ToARGB;
break;
}
DebugOnly<int> err =
fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
rgb_buf, rgb_pitch, pic_width, pic_height);
MOZ_ASSERT(!err);
break;
}
} else {
MOZ_ASSERT(yuv_type == YV12);
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2;
const uint8* src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2;
if (yuv_color_space == mozilla::YUVColorSpace::BT709) {
DebugOnly<int> err = libyuv::H420ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
MOZ_ASSERT(!err);
} else {
DebugOnly<int> err = libyuv::I420ToARGB(src_y, y_pitch,
src_u, uv_pitch,
src_v, uv_pitch,
rgb_buf, rgb_pitch,
pic_width, pic_height);
default: {
MOZ_ASSERT(yuv_type == YV12);
const uint8* src_y = y_buf + y_pitch * pic_y + pic_x;
const uint8* src_u = u_buf + (uv_pitch * pic_y + pic_x) / 2;
const uint8* src_v = v_buf + (uv_pitch * pic_y + pic_x) / 2;
switch (yuv_color_space) {
case mozilla::YUVColorSpace::BT2020:
fConvertYUVToARGB = libyuv::U420ToARGB;
break;
case mozilla::YUVColorSpace::BT709:
fConvertYUVToARGB = libyuv::H420ToARGB;
break;
default:
fConvertYUVToARGB = libyuv::I420ToARGB;
break;
}
DebugOnly<int> err =
fConvertYUVToARGB(src_y, y_pitch, src_u, uv_pitch, src_v, uv_pitch,
rgb_buf, rgb_pitch, pic_width, pic_height);
MOZ_ASSERT(!err);
break;
}
}
}

View File

@ -166,6 +166,18 @@ int H444ToARGB(const uint8_t* src_y,
int width,
int height);
LIBYUV_API
int U444ToARGB(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 J444 to ARGB.
LIBYUV_API
int J444ToARGB(const uint8_t* src_y,
@ -402,6 +414,19 @@ int H420ToARGB(const uint8_t* src_y,
int width,
int height);
// Convert U420 to ARGB.
LIBYUV_API
int U420ToARGB(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 H422 to ARGB.
LIBYUV_API
int H422ToARGB(const uint8_t* src_y,
@ -415,6 +440,19 @@ int H422ToARGB(const uint8_t* src_y,
int width,
int height);
// Convert U422 to ARGB.
LIBYUV_API
int U422ToARGB(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 H420 to ABGR.
LIBYUV_API
int H420ToABGR(const uint8_t* src_y,

View File

@ -558,11 +558,13 @@ struct YuvConstants {
extern const struct YuvConstants SIMD_ALIGNED(kYuvI601Constants); // BT.601
extern const struct YuvConstants SIMD_ALIGNED(kYuvJPEGConstants); // JPeg
extern const struct YuvConstants SIMD_ALIGNED(kYuvH709Constants); // BT.709
extern const struct YuvConstants SIMD_ALIGNED(kYuv2020Constants); // BT.2020
// Conversion matrix for YVU to BGR
extern const struct YuvConstants SIMD_ALIGNED(kYvuI601Constants); // BT.601
extern const struct YuvConstants SIMD_ALIGNED(kYvuJPEGConstants); // JPeg
extern const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants); // BT.709
extern const struct YuvConstants SIMD_ALIGNED(kYvu2020Constants); // BT.2020
#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a)-1)))

View File

@ -226,6 +226,23 @@ int H420ToABGR(const uint8_t* src_y,
width, height);
}
// Convert U420 to ARGB.
LIBYUV_API
int U420ToARGB(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) {
return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
src_stride_v, dst_argb, dst_stride_argb,
&kYuv2020Constants, width, height);
}
// Convert I422 to ARGB with matrix
static int I422ToARGBMatrix(const uint8_t* src_y,
int src_stride_y,
@ -660,6 +677,23 @@ int H010ToABGR(const uint16_t* src_y,
width, height);
}
// Convert U422 to ARGB.
LIBYUV_API
int U422ToARGB(const uint8* src_y,
int src_stride_y,
const uint8* src_u,
int src_stride_u,
const uint8* src_v,
int src_stride_v,
uint8* dst_argb,
int dst_stride_argb,
int width,
int height) {
return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
src_stride_v, dst_argb, dst_stride_argb,
&kYuv2020Constants, width, height);
}
// Convert I444 to ARGB with matrix
static int I444ToARGBMatrix(const uint8_t* src_y,
int src_stride_y,
@ -770,6 +804,23 @@ int H444ToARGB(const uint8_t* src_y,
&kYuvH709Constants, width, height);
}
// Convert U444 to ARGB.
LIBYUV_API
int U444ToARGB(const uint8* src_y,
int src_stride_y,
const uint8* src_u,
int src_stride_u,
const uint8* src_v,
int src_stride_v,
uint8* dst_argb,
int dst_stride_argb,
int width,
int height) {
return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
src_stride_v, dst_argb, dst_stride_argb,
&kYuv2020Constants, width, height);
}
// Convert I444 to ABGR.
LIBYUV_API
int I444ToABGR(const uint8_t* src_y,

View File

@ -1306,6 +1306,86 @@ const struct YuvConstants SIMD_ALIGNED(kYvuH709Constants) = {
#undef VR
#undef YG
// BT.2020 YUV to RGB reference
// R = (Y - 16) * 1.164384 - V * -1.67867
// G = (Y - 16) * 1.164384 - U * 0.187326 - V * -0.65042
// B = (Y - 16) * 1.164384 - U * -2.14177
// Y contribution to R,G,B. Scale and bias.
#define YG 19003 /* round(1.164384 * 64 * 256 * 256 / 257) */
#define YGB -1160 /* 1.164384 * 64 * -16 + 64 / 2 */
#define UB -128 /* max(-128, round(-2.142 * 64)) */
#define UG 12 /* round(0.187326 * 64) */
#define VG 42 /* round(0.65042 * 64) */
#define VR -107 /* round(-1.67867 * 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)
#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, 0, 0, 0, 0, 0},
{0x0101 * YG, 0, 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, 0, 0, 0, 0, 0},
{0x0101 * YG, 0, 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, 0, 0, 0, 0, 0},
{0x0101 * YG, 0, 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, 0, 0, 0, 0, 0},
{0x0101 * YG, 0, 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}};
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}};
#endif
#undef BB
#undef BG
#undef BR
#undef YGB
#undef UB
#undef UG
#undef VG
#undef VR
#undef YG
// C reference code that mimics the YUV assembly.
// Reads 8 bit YUV and leaves result as 16 bit.