Utilize bilinear chroma upsample in libyuv when possible (#873)
* Utilize bilinear chroma upsample in libyuv when possible
* Add more info to comment about -Wnewline-eof
* Add a comment about -Wnewline-eof
* Edit comment
Co-authored-by: Wan-Teh Chang <wtc@google.com>
diff --git a/ext/libyuv.cmd b/ext/libyuv.cmd
index 67cc5e3..010e925 100755
--- a/ext/libyuv.cmd
+++ b/ext/libyuv.cmd
@@ -10,7 +10,7 @@
git clone --single-branch https://chromium.googlesource.com/libyuv/libyuv
cd libyuv
-git checkout 2f0cbb9
+git checkout 3aebf69
mkdir build
cd build
diff --git a/src/reformat_libyuv.c b/src/reformat_libyuv.c
index 7984365..0bf5501 100644
--- a/src/reformat_libyuv.c
+++ b/src/reformat_libyuv.c
@@ -37,6 +37,11 @@
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes" // "this function declaration is not a prototype"
+// The newline at the end of libyuv/version.h was accidentally deleted in version 1792 and restored
+// in version 1813:
+// https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3183182
+// https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3527834
+#pragma clang diagnostic ignored "-Wnewline-eof" // "no newline at end of file"
#endif
#include <libyuv.h>
#if defined(__clang__)
@@ -52,7 +57,9 @@
}
if ((rgb->chromaUpsampling != AVIF_CHROMA_UPSAMPLING_AUTOMATIC) && (rgb->chromaUpsampling != AVIF_CHROMA_UPSAMPLING_FASTEST)) {
- // libyuv uses its own upsampling filter. If the enduser chose a specific one, avoid using libyuv.
+ // We do not ensure a specific upsampling filter is used when calling libyuv, so if the end
+ // user chose a specific one, avoid using libyuv. Also libyuv trades a bit of accuracy for
+ // speed, so if the end user requested best quality, avoid using libyuv as well.
return AVIF_RESULT_NOT_IMPLEMENTED;
}
@@ -187,6 +194,14 @@
return AVIF_RESULT_NOT_IMPLEMENTED;
}
+#if LIBYUV_VERSION >= 1813
+ enum FilterMode filter = kFilterBilinear;
+ if (rgb->chromaUpsampling == AVIF_CHROMA_UPSAMPLING_FASTEST) {
+ // 'None' (Nearest neighbor) filter is faster than bilinear.
+ filter = kFilterNone;
+ }
+#endif
+
// This following section might be a bit complicated to audit without a bit of explanation:
//
// libavif uses byte-order when describing pixel formats, such that the R in RGBA is the lowest address,
@@ -222,6 +237,22 @@
}
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV422) {
+#if LIBYUV_VERSION >= 1813
+ if (I422ToARGBMatrixFilter(image->yuvPlanes[AVIF_CHAN_Y],
+ image->yuvRowBytes[AVIF_CHAN_Y],
+ image->yuvPlanes[AVIF_CHAN_U],
+ image->yuvRowBytes[AVIF_CHAN_U],
+ image->yuvPlanes[AVIF_CHAN_V],
+ image->yuvRowBytes[AVIF_CHAN_V],
+ rgb->pixels,
+ rgb->rowBytes,
+ matrixYUV,
+ image->width,
+ image->height,
+ filter) != 0) {
+ return AVIF_RESULT_REFORMAT_FAILED;
+ }
+#else
if (I422ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y],
image->yuvPlanes[AVIF_CHAN_U],
@@ -235,8 +266,25 @@
image->height) != 0) {
return AVIF_RESULT_REFORMAT_FAILED;
}
+#endif
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420) {
+#if LIBYUV_VERSION >= 1813
+ if (I420ToARGBMatrixFilter(image->yuvPlanes[AVIF_CHAN_Y],
+ image->yuvRowBytes[AVIF_CHAN_Y],
+ image->yuvPlanes[AVIF_CHAN_U],
+ image->yuvRowBytes[AVIF_CHAN_U],
+ image->yuvPlanes[AVIF_CHAN_V],
+ image->yuvRowBytes[AVIF_CHAN_V],
+ rgb->pixels,
+ rgb->rowBytes,
+ matrixYUV,
+ image->width,
+ image->height,
+ filter) != 0) {
+ return AVIF_RESULT_REFORMAT_FAILED;
+ }
+#else
if (I420ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y],
image->yuvPlanes[AVIF_CHAN_U],
@@ -250,6 +298,7 @@
image->height) != 0) {
return AVIF_RESULT_REFORMAT_FAILED;
}
+#endif
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
if (I400ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
@@ -282,6 +331,22 @@
}
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV422) {
+#if LIBYUV_VERSION >= 1813
+ if (I422ToARGBMatrixFilter(image->yuvPlanes[AVIF_CHAN_Y],
+ image->yuvRowBytes[AVIF_CHAN_Y],
+ image->yuvPlanes[AVIF_CHAN_V],
+ image->yuvRowBytes[AVIF_CHAN_V],
+ image->yuvPlanes[AVIF_CHAN_U],
+ image->yuvRowBytes[AVIF_CHAN_U],
+ rgb->pixels,
+ rgb->rowBytes,
+ matrixYVU,
+ image->width,
+ image->height,
+ filter) != 0) {
+ return AVIF_RESULT_REFORMAT_FAILED;
+ }
+#else
if (I422ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y],
image->yuvPlanes[AVIF_CHAN_V],
@@ -295,8 +360,25 @@
image->height) != 0) {
return AVIF_RESULT_REFORMAT_FAILED;
}
+#endif
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV420) {
+#if LIBYUV_VERSION >= 1813
+ if (I420ToARGBMatrixFilter(image->yuvPlanes[AVIF_CHAN_Y],
+ image->yuvRowBytes[AVIF_CHAN_Y],
+ image->yuvPlanes[AVIF_CHAN_V],
+ image->yuvRowBytes[AVIF_CHAN_V],
+ image->yuvPlanes[AVIF_CHAN_U],
+ image->yuvRowBytes[AVIF_CHAN_U],
+ rgb->pixels,
+ rgb->rowBytes,
+ matrixYVU,
+ image->width,
+ image->height,
+ filter) != 0) {
+ return AVIF_RESULT_REFORMAT_FAILED;
+ }
+#else
if (I420ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y],
image->yuvPlanes[AVIF_CHAN_V],
@@ -310,6 +392,7 @@
image->height) != 0) {
return AVIF_RESULT_REFORMAT_FAILED;
}
+#endif
return AVIF_RESULT_OK;
} else if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
if (I400ToARGBMatrix(image->yuvPlanes[AVIF_CHAN_Y],
diff --git a/src/scale.c b/src/scale.c
index 1bbbdd8..23c7de6 100644
--- a/src/scale.c
+++ b/src/scale.c
@@ -22,6 +22,11 @@
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wstrict-prototypes" // "this function declaration is not a prototype"
+// The newline at the end of libyuv/version.h was accidentally deleted in version 1792 and restored
+// in version 1813:
+// https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3183182
+// https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3527834
+#pragma clang diagnostic ignored "-Wnewline-eof" // "no newline at end of file"
#endif
#include <libyuv.h>
#if defined(__clang__)