diff --git a/docs/formats.md b/docs/formats.md index 97e8ce05f..260dd7318 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -36,7 +36,7 @@ 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 { - // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + // 10 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), @@ -46,6 +46,8 @@ The following is extracted from video_common.h as a complete list of formats sup 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 + FOURCC_U010 = FOURCC('U', '0', '1', '0'), // bt.2020, unofficial fourcc. + // 10 bit lsb // 1 Secondary YUV format: row biplanar. FOURCC_M420 = FOURCC('M', '4', '2', '0'), @@ -66,7 +68,7 @@ The following is extracted from video_common.h as a complete list of formats sup // 1 Primary Compressed YUV format. FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), - // 8 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. + // 11 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), @@ -75,6 +77,9 @@ The following is extracted from video_common.h as a complete list of formats sup FOURCC_J400 = FOURCC('J', '4', '0', '0'), // unofficial fourcc FOURCC_H420 = FOURCC('H', '4', '2', '0'), // unofficial fourcc FOURCC_H422 = FOURCC('H', '4', '2', '2'), // 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 // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc. FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420. diff --git a/include/libyuv/convert_argb.h b/include/libyuv/convert_argb.h index 33c783b5d..1ff137255 100644 --- a/include/libyuv/convert_argb.h +++ b/include/libyuv/convert_argb.h @@ -128,6 +128,32 @@ int H010ToABGR(const uint16_t* src_y, int width, int height); +// Convert U010 to ARGB. +LIBYUV_API +int U010ToARGB(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_argb, + int dst_stride_argb, + int width, + int height); + +// Convert U010 to ABGR. +LIBYUV_API +int U010ToABGR(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_abgr, + int dst_stride_abgr, + int width, + int height); + // Convert I422 to ARGB. LIBYUV_API int I422ToARGB(const uint8_t* src_y, @@ -154,6 +180,19 @@ int I444ToARGB(const uint8_t* src_y, int width, int height); +// Convert U444 to ARGB. +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, @@ -424,6 +463,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, @@ -437,6 +489,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, diff --git a/include/libyuv/row.h b/include/libyuv/row.h index ba55c0258..b721858f1 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -690,11 +690,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))) diff --git a/include/libyuv/video_common.h b/include/libyuv/video_common.h index ffcbdbf1b..8a8fc96e4 100644 --- a/include/libyuv/video_common.h +++ b/include/libyuv/video_common.h @@ -50,7 +50,7 @@ extern "C" { // Secondary formats are converted in 2 steps. // Auxilliary formats call primary converters. enum FourCC { - // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. + // 10 Primary YUV formats: 5 planar, 2 biplanar, 2 packed. FOURCC_I420 = FOURCC('I', '4', '2', '0'), FOURCC_I422 = FOURCC('I', '4', '2', '2'), FOURCC_I444 = FOURCC('I', '4', '4', '4'), @@ -60,6 +60,8 @@ enum FourCC { 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 + FOURCC_U010 = FOURCC('U', '0', '1', '0'), // bt.2020, unofficial fourcc. + // 10 bit lsb // 1 Secondary YUV format: row biplanar. FOURCC_M420 = FOURCC('M', '4', '2', '0'), @@ -80,7 +82,7 @@ enum FourCC { // 1 Primary Compressed YUV format. FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'), - // 8 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. + // 11 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias. FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'), FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'), FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'), @@ -89,6 +91,9 @@ enum FourCC { FOURCC_J400 = FOURCC('J', '4', '0', '0'), // unofficial fourcc FOURCC_H420 = FOURCC('H', '4', '2', '0'), // unofficial fourcc FOURCC_H422 = FOURCC('H', '4', '2', '2'), // 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 // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc. FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420. diff --git a/source/convert_argb.cc b/source/convert_argb.cc index f46b4309d..47fed0a36 100644 --- a/source/convert_argb.cc +++ b/source/convert_argb.cc @@ -234,6 +234,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, @@ -516,6 +533,23 @@ int H010ToAR30(const uint16_t* src_y, &kYuvH709Constants, width, height); } +// Convert U010 to AR30. +LIBYUV_API +int U010ToAR30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ar30, + int dst_stride_ar30, + int width, + int height) { + return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v, + src_stride_v, dst_ar30, dst_stride_ar30, + &kYuv2020Constants, width, height); +} + // Convert I010 to AB30. LIBYUV_API int I010ToAB30(const uint16_t* src_y, @@ -550,6 +584,23 @@ int H010ToAB30(const uint16_t* src_y, &kYvuH709Constants, width, height); } +// Convert U010 to AB30. +LIBYUV_API +int U010ToAB30(const uint16_t* src_y, + int src_stride_y, + const uint16_t* src_u, + int src_stride_u, + const uint16_t* src_v, + int src_stride_v, + uint8_t* dst_ab30, + int dst_stride_ab30, + int width, + int height) { + return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u, + src_stride_u, dst_ab30, dst_stride_ab30, + &kYuv2020Constants, width, height); +} + // Convert 10 bit YUV to ARGB with matrix static int I010ToARGBMatrix(const uint16_t* src_y, int src_stride_y, @@ -684,6 +735,23 @@ int H010ToABGR(const uint16_t* src_y, width, 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) { + 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, @@ -785,6 +853,23 @@ int I444ToARGB(const uint8_t* src_y, &kYuvI601Constants, width, height); } +// Convert U444 to ARGB. +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) { + 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, diff --git a/source/row_common.cc b/source/row_common.cc index 41c8bea55..70aa2e13c 100644 --- a/source/row_common.cc +++ b/source/row_common.cc @@ -1355,6 +1355,87 @@ 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 */ + +// TODO(fbarchard): Improve accuracy; the B channel is off by 7%. +#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.