Use libyuv for 12-bit YUV->RGB when available
Generalize avifImageYUVToRGBLibYUV10bpc() to
avifImageYUVToRGBLibYUVHighBitDepth() and use it for both 10bpc and
12bpc. The 12bpc part currently uses I012ToARGBMatrix() only.
I012ToARGBMatrix() was added in
https://chromium-review.googlesource.com/c/libyuv/libyuv/+/2727775. That
commit is between version 1780 and version 1781. See
https://chromium-review.googlesource.com/c/libyuv/libyuv/+/2707003 and
https://chromium-review.googlesource.com/c/libyuv/libyuv/+/2746780.
diff --git a/src/reformat_libyuv.c b/src/reformat_libyuv.c
index 88a67f9..3a37ba0 100644
--- a/src/reformat_libyuv.c
+++ b/src/reformat_libyuv.c
@@ -236,10 +236,10 @@
avifRGBImage * rgb,
const struct YuvConstants * matrixYUV,
const struct YuvConstants * matrixYVU);
-static avifResult avifImageYUVToRGBLibYUV10bpc(const avifImage * image,
- avifRGBImage * rgb,
- const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU);
+static avifResult avifImageYUVToRGBLibYUVHighBitDepth(const avifImage * image,
+ avifRGBImage * rgb,
+ const struct YuvConstants * matrixYUV,
+ const struct YuvConstants * matrixYVU);
avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb)
{
@@ -387,8 +387,8 @@
return avifImageYUVToRGBLibYUV8bpc(image, rgb, matrixYUV, matrixYVU);
}
- if ((image->depth == 10) && (rgb->depth == 8)) {
- return avifImageYUVToRGBLibYUV10bpc(image, rgb, matrixYUV, matrixYVU);
+ if (((image->depth == 10) || (image->depth == 12)) && (rgb->depth == 8)) {
+ return avifImageYUVToRGBLibYUVHighBitDepth(image, rgb, matrixYUV, matrixYVU);
}
// This function didn't do anything; use the built-in YUV conversion
@@ -412,6 +412,9 @@
#if LIBYUV_VERSION < 1756
#define I400ToARGBMatrix NULL
#endif
+#if LIBYUV_VERSION < 1781
+#define I012ToARGBMatrix NULL
+#endif
// Lookup table for isYVU. If the entry in this table is AVIF_TRUE, then it
// means that we are using a libyuv function with R and B channels swapped,
@@ -558,14 +561,15 @@
return AVIF_RESULT_NOT_IMPLEMENTED;
}
-avifResult avifImageYUVToRGBLibYUV10bpc(const avifImage * image,
- avifRGBImage * rgb,
- const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU)
+avifResult avifImageYUVToRGBLibYUVHighBitDepth(const avifImage * image,
+ avifRGBImage * rgb,
+ const struct YuvConstants * matrixYUV,
+ const struct YuvConstants * matrixYVU)
{
// See if the current settings can be accomplished with libyuv, and use it (if possible).
- assert((image->depth == 10) && (rgb->depth == 8));
+ assert(((image->depth == 10) || (image->depth == 12)) && (rgb->depth == 8));
+ int depthIndex = (image->depth == 10) ? 0 : 1;
// libavif uses byte-order when describing pixel formats, such that the R in RGBA is the lowest address,
// similar to PNG. libyuv orders in word-order, so libavif's RGBA would be referred to in libyuv as ABGR.
@@ -600,16 +604,28 @@
int,
int,
enum FilterMode);
- YUVToRGBMatrixFilter lutYuvToRgbMatrixFilter[AVIF_RGB_FORMAT_COUNT][AVIF_PIXEL_FORMAT_COUNT] = {
- { NULL, NULL, NULL, NULL, NULL }, // RGB
- { NULL, NULL, I210ToARGBMatrixFilter, I010ToARGBMatrixFilter, NULL }, // RGBA
- { NULL, NULL, NULL, NULL, NULL }, // ARGB
- { NULL, NULL, NULL, NULL, NULL }, // BGR
- { NULL, NULL, I210ToARGBMatrixFilter, I010ToARGBMatrixFilter, NULL }, // BGRA
- { NULL, NULL, NULL, NULL, NULL }, // ABGR
- { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ // First index: 0: 10bpc, 1: 12bpc
+ YUVToRGBMatrixFilter lutYuvToRgbMatrixFilter[2][AVIF_RGB_FORMAT_COUNT][AVIF_PIXEL_FORMAT_COUNT] = {
+ {
+ { NULL, NULL, NULL, NULL, NULL }, // RGB
+ { NULL, NULL, I210ToARGBMatrixFilter, I010ToARGBMatrixFilter, NULL }, // RGBA
+ { NULL, NULL, NULL, NULL, NULL }, // ARGB
+ { NULL, NULL, NULL, NULL, NULL }, // BGR
+ { NULL, NULL, I210ToARGBMatrixFilter, I010ToARGBMatrixFilter, NULL }, // BGRA
+ { NULL, NULL, NULL, NULL, NULL }, // ABGR
+ { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ },
+ {
+ { NULL, NULL, NULL, NULL, NULL }, // RGB
+ { NULL, NULL, NULL, NULL, NULL }, // RGBA
+ { NULL, NULL, NULL, NULL, NULL }, // ARGB
+ { NULL, NULL, NULL, NULL, NULL }, // BGR
+ { NULL, NULL, NULL, NULL, NULL }, // BGRA
+ { NULL, NULL, NULL, NULL, NULL }, // ABGR
+ { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ },
};
- YUVToRGBMatrixFilter yuvToRgbMatrixFilter = lutYuvToRgbMatrixFilter[rgb->format][image->yuvFormat];
+ YUVToRGBMatrixFilter yuvToRgbMatrixFilter = lutYuvToRgbMatrixFilter[depthIndex][rgb->format][image->yuvFormat];
if (yuvToRgbMatrixFilter != NULL) {
// 'None' (Nearest neighbor) filter is faster than bilinear.
enum FilterMode filter = (rgb->chromaUpsampling == AVIF_CHROMA_UPSAMPLING_FASTEST) ? kFilterNone : kFilterBilinear;
@@ -633,16 +649,28 @@
// Lookup table for YUV To RGB Matrix (without filter).
typedef int (
*YUVToRGBMatrix)(const uint16_t *, int, const uint16_t *, int, const uint16_t *, int, uint8_t *, int, const struct YuvConstants *, int, int);
- YUVToRGBMatrix lutYuvToRgbMatrix[AVIF_RGB_FORMAT_COUNT][AVIF_PIXEL_FORMAT_COUNT] = {
- { NULL, NULL, NULL, NULL, NULL }, // RGB
- { NULL, I410ToARGBMatrix, I210ToARGBMatrix, I010ToARGBMatrix, NULL }, // RGBA
- { NULL, NULL, NULL, NULL, NULL }, // ARGB
- { NULL, NULL, NULL, NULL, NULL }, // BGR
- { NULL, I410ToARGBMatrix, I210ToARGBMatrix, I010ToARGBMatrix, NULL }, // BGRA
- { NULL, NULL, NULL, NULL, NULL }, // ABGR
- { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ // First index: 0: 10bpc, 1: 12bpc
+ YUVToRGBMatrix lutYuvToRgbMatrix[2][AVIF_RGB_FORMAT_COUNT][AVIF_PIXEL_FORMAT_COUNT] = {
+ {
+ { NULL, NULL, NULL, NULL, NULL }, // RGB
+ { NULL, I410ToARGBMatrix, I210ToARGBMatrix, I010ToARGBMatrix, NULL }, // RGBA
+ { NULL, NULL, NULL, NULL, NULL }, // ARGB
+ { NULL, NULL, NULL, NULL, NULL }, // BGR
+ { NULL, I410ToARGBMatrix, I210ToARGBMatrix, I010ToARGBMatrix, NULL }, // BGRA
+ { NULL, NULL, NULL, NULL, NULL }, // ABGR
+ { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ },
+ {
+ { NULL, NULL, NULL, NULL, NULL }, // RGB
+ { NULL, NULL, NULL, I012ToARGBMatrix, NULL }, // RGBA
+ { NULL, NULL, NULL, NULL, NULL }, // ARGB
+ { NULL, NULL, NULL, NULL, NULL }, // BGR
+ { NULL, NULL, NULL, I012ToARGBMatrix, NULL }, // BGRA
+ { NULL, NULL, NULL, NULL, NULL }, // ABGR
+ { NULL, NULL, NULL, NULL, NULL }, // RGB_565
+ },
};
- YUVToRGBMatrix yuvToRgbMatrix = lutYuvToRgbMatrix[rgb->format][image->yuvFormat];
+ YUVToRGBMatrix yuvToRgbMatrix = lutYuvToRgbMatrix[depthIndex][rgb->format][image->yuvFormat];
if (yuvToRgbMatrix != NULL) {
if (yuvToRgbMatrix((const uint16_t *)image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y] / 2,