Refactor avifChromaDownsampling into avifRGBToYUVFlag
Refactor avifChromaUpsampling into avifYUVToRGBFlag.
diff --git a/apps/avifdec.c b/apps/avifdec.c
index 055a919..6617187 100644
--- a/apps/avifdec.c
+++ b/apps/avifdec.c
@@ -61,7 +61,7 @@
int pngCompressionLevel = -1; // -1 is a sentinel to avifPNGWrite() to skip calling png_set_compression_level()
avifCodecChoice codecChoice = AVIF_CODEC_CHOICE_AUTO;
avifBool infoOnly = AVIF_FALSE;
- avifChromaUpsampling chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
+ avifYUVToRGBFlags upsamplingFlags = AVIF_YUV_TO_RGB_DEFAULT;
avifBool ignoreICC = AVIF_FALSE;
avifBool rawColor = AVIF_FALSE;
avifBool allowProgressive = AVIF_FALSE;
@@ -134,15 +134,15 @@
} else if (!strcmp(arg, "-u") || !strcmp(arg, "--upsampling")) {
NEXTARG();
if (!strcmp(arg, "automatic")) {
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
+ upsamplingFlags = AVIF_YUV_TO_RGB_DEFAULT;
} else if (!strcmp(arg, "fastest")) {
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_FASTEST;
+ upsamplingFlags = AVIF_CHROMA_UPSAMPLING_NEAREST;
} else if (!strcmp(arg, "best")) {
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_BEST_QUALITY;
+ upsamplingFlags = AVIF_YUV_TO_RGB_AVOID_LIBYUV | AVIF_CHROMA_UPSAMPLING_BILINEAR;
} else if (!strcmp(arg, "nearest")) {
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_NEAREST;
+ upsamplingFlags = AVIF_CHROMA_UPSAMPLING_NEAREST;
} else if (!strcmp(arg, "bilinear")) {
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_BILINEAR;
+ upsamplingFlags = AVIF_CHROMA_UPSAMPLING_BILINEAR;
} else {
fprintf(stderr, "ERROR: invalid upsampling: %s\n", arg);
return 1;
@@ -324,11 +324,11 @@
if (rawColor) {
decoder->image->alphaPremultiplied = AVIF_TRUE;
}
- if (!avifJPEGWrite(outputFilename, decoder->image, jpegQuality, chromaUpsampling)) {
+ if (!avifJPEGWrite(outputFilename, decoder->image, jpegQuality, upsamplingFlags)) {
returnCode = 1;
}
} else if (outputFormat == AVIF_APP_FILE_FORMAT_PNG) {
- if (!avifPNGWrite(outputFilename, decoder->image, requestedDepth, chromaUpsampling, pngCompressionLevel)) {
+ if (!avifPNGWrite(outputFilename, decoder->image, requestedDepth, upsamplingFlags, pngCompressionLevel)) {
returnCode = 1;
}
} else {
diff --git a/apps/shared/avifjpeg.c b/apps/shared/avifjpeg.c
index 0934c4f..3ff9a1e 100644
--- a/apps/shared/avifjpeg.c
+++ b/apps/shared/avifjpeg.c
@@ -314,7 +314,7 @@
memcpy(pixelRow, buffer[0], rgb.rowBytes);
++row;
}
- if (avifImageRGBToYUV(avif, &rgb) != AVIF_RESULT_OK) {
+ if (avifImageRGBToYUV(avif, &rgb, AVIF_RGB_TO_YUV_DEFAULT) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to YUV failed: %s\n", inputFilename);
goto cleanup;
}
@@ -332,7 +332,7 @@
return ret;
}
-avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling)
+avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifYUVToRGBFlags conversionFlags)
{
avifBool ret = AVIF_FALSE;
FILE * f = NULL;
@@ -346,10 +346,9 @@
avifRGBImage rgb;
avifRGBImageSetDefaults(&rgb, avif);
rgb.format = AVIF_RGB_FORMAT_RGB;
- rgb.chromaUpsampling = chromaUpsampling;
rgb.depth = 8;
avifRGBImageAllocatePixels(&rgb);
- if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
+ if (avifImageYUVToRGB(avif, &rgb, conversionFlags) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
goto cleanup;
}
diff --git a/apps/shared/avifjpeg.h b/apps/shared/avifjpeg.h
index 305375d..a928fa4 100644
--- a/apps/shared/avifjpeg.h
+++ b/apps/shared/avifjpeg.h
@@ -11,7 +11,7 @@
#endif
avifBool avifJPEGRead(const char * inputFilename, avifImage * avif, avifPixelFormat requestedFormat, uint32_t requestedDepth);
-avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifChromaUpsampling chromaUpsampling);
+avifBool avifJPEGWrite(const char * outputFilename, const avifImage * avif, int jpegQuality, avifYUVToRGBFlags conversionFlags);
#ifdef __cplusplus
} // extern "C"
diff --git a/apps/shared/avifpng.c b/apps/shared/avifpng.c
index effaa6b..7f8ce45 100644
--- a/apps/shared/avifpng.c
+++ b/apps/shared/avifpng.c
@@ -153,7 +153,7 @@
rowPointers[y] = &rgb.pixels[y * rgb.rowBytes];
}
png_read_image(png, rowPointers);
- if (avifImageRGBToYUV(avif, &rgb) != AVIF_RESULT_OK) {
+ if (avifImageRGBToYUV(avif, &rgb, AVIF_RGB_TO_YUV_DEFAULT) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to YUV failed: %s\n", inputFilename);
goto cleanup;
}
@@ -173,7 +173,7 @@
return readResult;
}
-avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifChromaUpsampling chromaUpsampling, int compressionLevel)
+avifBool avifPNGWrite(const char * outputFilename, const avifImage * avif, uint32_t requestedDepth, avifYUVToRGBFlags conversionFlags, int compressionLevel)
{
volatile avifBool writeResult = AVIF_FALSE;
png_structp png = NULL;
@@ -200,9 +200,8 @@
colorType = PNG_COLOR_TYPE_RGB;
rgb.format = AVIF_RGB_FORMAT_RGB;
}
- rgb.chromaUpsampling = chromaUpsampling;
avifRGBImageAllocatePixels(&rgb);
- if (avifImageYUVToRGB(avif, &rgb) != AVIF_RESULT_OK) {
+ if (avifImageYUVToRGB(avif, &rgb, conversionFlags) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion to RGB failed: %s\n", outputFilename);
goto cleanup;
}
diff --git a/apps/shared/avifpng.h b/apps/shared/avifpng.h
index 5e130ce..20ffd93 100644
--- a/apps/shared/avifpng.h
+++ b/apps/shared/avifpng.h
@@ -15,7 +15,7 @@
avifBool avifPNGWrite(const char * outputFilename,
const avifImage * avif,
uint32_t requestedDepth,
- avifChromaUpsampling chromaUpsampling,
+ avifYUVToRGBFlags conversionFlags,
int compressionLevel);
#ifdef __cplusplus
diff --git a/contrib/gdk-pixbuf/loader.c b/contrib/gdk-pixbuf/loader.c
index 32c6eee..1ce68e6 100644
--- a/contrib/gdk-pixbuf/loader.c
+++ b/contrib/gdk-pixbuf/loader.c
@@ -448,7 +448,7 @@
rgb.format = AVIF_RGB_FORMAT_RGB;
}
- res = avifImageRGBToYUV(avif, &rgb);
+ res = avifImageRGBToYUV(avif, &rgb, AVIF_CONVERSION_AUTO);
if ( res != AVIF_RESULT_OK ) {
g_set_error(error,
GDK_PIXBUF_ERROR,
diff --git a/examples/avif_example_decode_file.c b/examples/avif_example_decode_file.c
index 12b0a7e..1f8d1fa 100644
--- a/examples/avif_example_decode_file.c
+++ b/examples/avif_example_decode_file.c
@@ -53,13 +53,14 @@
// * this frame's sequence timing
avifRGBImageSetDefaults(&rgb, decoder->image);
- // Override YUV(A)->RGB(A) defaults here: depth, format, chromaUpsampling, ignoreAlpha, alphaPremultiplied, libYUVUsage, etc
+ // Override YUV(A)->RGB(A) defaults here: depth, format, ignoreAlpha, alphaPremultiplied, etc
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
avifRGBImageAllocatePixels(&rgb);
- if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
+ // Other flags than AVIF_YUV_TO_RGB_DEFAULT, such as AVIF_CHROMA_UPSAMPLING_NEAREST, can be passed.
+ if (avifImageYUVToRGB(decoder->image, &rgb, AVIF_YUV_TO_RGB_DEFAULT) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
goto cleanup;
}
diff --git a/examples/avif_example_decode_memory.c b/examples/avif_example_decode_memory.c
index a50d248..d5a9aa9 100644
--- a/examples/avif_example_decode_memory.c
+++ b/examples/avif_example_decode_memory.c
@@ -75,13 +75,14 @@
// * this frame's sequence timing
avifRGBImageSetDefaults(&rgb, decoder->image);
- // Override YUV(A)->RGB(A) defaults here: depth, format, chromaUpsampling, ignoreAlpha, alphaPremultiplied, libYUVUsage, etc
+ // Override YUV(A)->RGB(A) defaults here: depth, format, ignoreAlpha, alphaPremultiplied, etc
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
avifRGBImageAllocatePixels(&rgb);
- if (avifImageYUVToRGB(decoder->image, &rgb) != AVIF_RESULT_OK) {
+ // Other flags than AVIF_YUV_TO_RGB_DEFAULT, such as AVIF_CHROMA_UPSAMPLING_NEAREST, can be passed.
+ if (avifImageYUVToRGB(decoder->image, &rgb, AVIF_YUV_TO_RGB_DEFAULT) != AVIF_RESULT_OK) {
fprintf(stderr, "Conversion from YUV failed: %s\n", inputFilename);
goto cleanup;
}
diff --git a/examples/avif_example_encode.c b/examples/avif_example_encode.c
index 36c4ca9..b95cf0a 100644
--- a/examples/avif_example_encode.c
+++ b/examples/avif_example_encode.c
@@ -57,7 +57,7 @@
printf("Encoding from converted RGBA\n");
avifRGBImageSetDefaults(&rgb, image);
- // Override RGB(A)->YUV(A) defaults here: depth, format, chromaDownsampling, ignoreAlpha, alphaPremultiplied, libYUVUsage, etc
+ // Override RGB(A)->YUV(A) defaults here: depth, format, ignoreAlpha, alphaPremultiplied, etc
// Alternative: set rgb.pixels and rgb.rowBytes yourself, which should match your chosen rgb.format
// Be sure to use uint16_t* instead of uint8_t* for rgb.pixels/rgb.rowBytes if (rgb.depth > 8)
@@ -66,7 +66,8 @@
// Fill your RGB(A) data here
memset(rgb.pixels, 255, rgb.rowBytes * image->height);
- avifResult convertResult = avifImageRGBToYUV(image, &rgb);
+ // Other flags than AVIF_RGB_TO_YUV_DEFAULT, such as AVIF_RGB_TO_YUV_AVOID_LIBYUV, can be passed.
+ avifResult convertResult = avifImageRGBToYUV(image, &rgb, AVIF_RGB_TO_YUV_DEFAULT);
if (convertResult != AVIF_RESULT_OK) {
fprintf(stderr, "Failed to convert to YUV(A): %s\n", avifResultToString(convertResult));
goto cleanup;
diff --git a/include/avif/avif.h b/include/avif/avif.h
index 08a1d50..71cf54f 100644
--- a/include/avif/avif.h
+++ b/include/avif/avif.h
@@ -528,12 +528,13 @@
// conversion, if necessary. Pixels in an avifRGBImage buffer are always full range, and conversion
// routines will fail if the width and height don't match the associated avifImage.
-// If libavif is built with libyuv fast paths enabled, libavif will use libyuv for conversion from
-// YUV to RGB if the following requirements are met:
-//
+// If libavif is built with libyuv fast paths enabled and the AVIF_RGB_TO_YUV_AVOID_LIBYUV or
+// AVIF_YUV_TO_RGB_AVOID_LIBYUV flag is not set, libavif will use libyuv for conversion between
+// RGB and YUV if the following requirements are met:
+
+// Conversion from YUV to RGB:
// * YUV depth: 8 or 10
// * RGB depth: 8
-// * rgb.chromaUpsampling: AVIF_CHROMA_UPSAMPLING_AUTOMATIC, AVIF_CHROMA_UPSAMPLING_FASTEST
// * rgb.format: AVIF_RGB_FORMAT_RGBA, AVIF_RGB_FORMAT_BGRA (420/422 support for
// AVIF_RGB_FORMAT_ABGR, AVIF_RGB_FORMAT_ARGB, AVIF_RGB_FORMAT_RGB_565)
// * CICP is one of the following combinations (CP/TC/MC/Range):
@@ -542,12 +543,9 @@
// * x/x/[1|2|5|6|9]/Limited
// * [1|2|5|6|9]/x/12/Limited
-// If libavif is built with libyuv fast paths enabled, libavif will use libyuv for conversion from
-// RGB to YUV if the following requirements are met:
-//
+// Conversion from RGB to YUV:
// * YUV depth: 8
// * RGB depth: 8
-// * rgb.chromaDownsampling: AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC, AVIF_CHROMA_DOWNSAMPLING_FASTEST
// * One of the following combinations (avifRGBFormat to avifPixelFormat/MC/Range):
// * BGRA to YUV400 / x /[Full|Limited]
// * BGRA to [YUV420|YUV422]/[5|6]/[Full|Limited]
@@ -582,33 +580,12 @@
AVIF_API uint32_t avifRGBFormatChannelCount(avifRGBFormat format);
AVIF_API avifBool avifRGBFormatHasAlpha(avifRGBFormat format);
-typedef enum avifChromaUpsampling
-{
- AVIF_CHROMA_UPSAMPLING_AUTOMATIC = 0, // Chooses best trade off of speed/quality (prefers libyuv, else uses BEST_QUALITY)
- AVIF_CHROMA_UPSAMPLING_FASTEST = 1, // Chooses speed over quality (prefers libyuv, else uses NEAREST)
- AVIF_CHROMA_UPSAMPLING_BEST_QUALITY = 2, // Chooses the best quality upsampling, given settings (avoids libyuv)
- AVIF_CHROMA_UPSAMPLING_NEAREST = 3, // Uses nearest-neighbor filter (built-in)
- AVIF_CHROMA_UPSAMPLING_BILINEAR = 4 // Uses bilinear filter (built-in)
-} avifChromaUpsampling;
-
-typedef enum avifChromaDownsampling
-{
- AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC = 0, // Chooses best trade off of speed/quality (prefers libyuv, else uses BEST_QUALITY)
- AVIF_CHROMA_DOWNSAMPLING_FASTEST = 1, // Chooses speed over quality (prefers libyuv, else uses AVERAGE)
- AVIF_CHROMA_DOWNSAMPLING_BEST_QUALITY = 2, // Chooses the best quality upsampling (avoids libyuv, uses AVERAGE)
- AVIF_CHROMA_DOWNSAMPLING_AVERAGE = 3 // Uses floating point RGB-to-YUV conversion then averaging (built-in)
-} avifChromaDownsampling;
-
typedef struct avifRGBImage
{
- uint32_t width; // must match associated avifImage
- uint32_t height; // must match associated avifImage
- uint32_t depth; // legal depths [8, 10, 12, 16]. if depth>8, pixels must be uint16_t internally
- avifRGBFormat format; // all channels are always full range
- avifChromaUpsampling chromaUpsampling; // Defaults to AVIF_CHROMA_UPSAMPLING_AUTOMATIC: How to upsample non-4:4:4 UV (ignored for 444) when converting to RGB.
- // Unused when converting to YUV. avifRGBImageSetDefaults() prefers quality over speed.
- avifChromaDownsampling chromaDownsampling; // How to convert (and downsample to non-4:4:4 UV) when converting to YUV.
- // Unused when converting to RGB. Defaults to AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC.
+ uint32_t width; // must match associated avifImage
+ uint32_t height; // must match associated avifImage
+ uint32_t depth; // legal depths [8, 10, 12, 16]. if depth>8, pixels must be uint16_t internally
+ avifRGBFormat format; // all channels are always full range
avifBool ignoreAlpha; // Used for XRGB formats, treats formats containing alpha (such as ARGB) as if they were
// RGB, treating the alpha bits as if they were all 1.
avifBool alphaPremultiplied; // indicates if RGB value is pre-multiplied by alpha. Default: false
@@ -628,9 +605,42 @@
AVIF_API void avifRGBImageAllocatePixels(avifRGBImage * rgb);
AVIF_API void avifRGBImageFreePixels(avifRGBImage * rgb);
-// The main conversion functions
-AVIF_API avifResult avifImageRGBToYUV(avifImage * image, const avifRGBImage * rgb);
-AVIF_API avifResult avifImageYUVToRGB(const avifImage * image, avifRGBImage * rgb);
+// Conversion options.
+typedef enum avifRGBToYUVFlag
+{
+ AVIF_RGB_TO_YUV_DEFAULT = 0, // Uses the first available upsampling filter among:
+ // libyuv average, built-in average
+
+ // libyuv preference
+
+ AVIF_RGB_TO_YUV_AVOID_LIBYUV = (1 << 0), // Only picks built-in paths. The default is to prefer libyuv if available.
+
+ // Conversion from RGB to YUV 4:2:2 or YUV 4:2:0 (ignored in all other cases)
+
+ // Chroma downsampling filter. Set at most one:
+ AVIF_CHROMA_DOWNSAMPLING_AVERAGE = (1 << 10), // only use the averaging filter (libyuv or built-in)
+} avifRGBToYUVFlag;
+typedef uint32_t avifRGBToYUVFlags;
+typedef enum avifYUVToRGBFlag
+{
+ AVIF_YUV_TO_RGB_DEFAULT = 0, // Uses the first available downsampling filter among:
+ // libyuv bilinear, libyuv nearest-neighbor, built-in bilinear
+
+ // libyuv preference
+
+ AVIF_YUV_TO_RGB_AVOID_LIBYUV = (1 << 0), // Only picks built-in paths. The default is to prefer libyuv if available.
+
+ // Conversion from YUV 4:2:2 or YUV 4:2:0 to RGB (ignored in all other cases)
+
+ // Chroma upsampling filter. Set at most one:
+ AVIF_CHROMA_UPSAMPLING_NEAREST = (1 << 10), // only use the fast nearest-neighbor filter (libyuv or built-in)
+ AVIF_CHROMA_UPSAMPLING_BILINEAR = (1 << 11) // only use the good-quality bilinear filter (libyuv or built-in)
+} avifYUVToRGBFlag;
+typedef uint32_t avifYUVToRGBFlags;
+
+// Conversion functions.
+AVIF_API avifResult avifImageRGBToYUV(avifImage * image, const avifRGBImage * rgb, avifRGBToYUVFlags flags);
+AVIF_API avifResult avifImageYUVToRGB(const avifImage * image, avifRGBImage * rgb, avifYUVToRGBFlags flags);
// Premultiply handling functions.
// (Un)premultiply is automatically done by the main conversion functions above,
diff --git a/include/avif/internal.h b/include/avif/internal.h
index da650ae..c3a2749 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -149,7 +149,7 @@
// * AVIF_RESULT_OK - Converted successfully with libyuv
// * AVIF_RESULT_NOT_IMPLEMENTED - The fast path for this combination is not implemented with libyuv, use built-in YUV conversion
// * [any other error] - Return error to caller
-avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb);
+avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb, avifYUVToRGBFlags flags);
// Returns:
// * AVIF_RESULT_OK - Converted successfully with libsharpyuv
diff --git a/src/avif.c b/src/avif.c
index fd4a9ed..5381b44 100644
--- a/src/avif.c
+++ b/src/avif.c
@@ -457,8 +457,6 @@
rgb->height = image->height;
rgb->depth = image->depth;
rgb->format = AVIF_RGB_FORMAT_RGBA;
- rgb->chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
- rgb->chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC;
rgb->ignoreAlpha = AVIF_FALSE;
rgb->pixels = NULL;
rgb->rowBytes = 0;
diff --git a/src/reformat.c b/src/reformat.c
index 7e5246a..9559fad 100644
--- a/src/reformat.c
+++ b/src/reformat.c
@@ -191,7 +191,7 @@
return AVIF_CLAMP(unorm, 0, state->yuvMaxChannel);
}
-avifResult avifImageRGBToYUV(avifImage * image, const avifRGBImage * rgb)
+avifResult avifImageRGBToYUV(avifImage * image, const avifRGBImage * rgb, avifRGBToYUVFlags flags)
{
if (!rgb->pixels || rgb->format == AVIF_RGB_FORMAT_RGB_565) {
return AVIF_RESULT_REFORMAT_FAILED;
@@ -222,7 +222,7 @@
}
avifBool convertedWithLibYUV = AVIF_FALSE;
- if (alphaMode == AVIF_ALPHA_MULTIPLY_MODE_NO_OP) {
+ if (!(flags & AVIF_RGB_TO_YUV_AVOID_LIBYUV) && (alphaMode == AVIF_ALPHA_MULTIPLY_MODE_NO_OP)) {
avifResult libyuvResult = avifImageRGBToYUVLibYUV(image, rgb);
if (libyuvResult == AVIF_RESULT_OK) {
convertedWithLibYUV = AVIF_TRUE;
@@ -465,10 +465,7 @@
}
// Note: This function handles alpha (un)multiply.
-static avifResult avifImageYUVAnyToRGBAnySlow(const avifImage * image,
- avifRGBImage * rgb,
- avifReformatState * state,
- const avifChromaUpsampling chromaUpsampling)
+static avifResult avifImageYUVAnyToRGBAnySlow(const avifImage * image, avifRGBImage * rgb, avifReformatState * state, avifYUVToRGBFlags flags)
{
// Aliases for some state
const float kr = state->kr;
@@ -494,9 +491,6 @@
const uint16_t yuvMaxChannel = (uint16_t)state->yuvMaxChannel;
const float rgbMaxChannelF = state->rgbMaxChannelF;
- // These are the only supported built-ins
- assert((chromaUpsampling == AVIF_CHROMA_UPSAMPLING_BILINEAR) || (chromaUpsampling == AVIF_CHROMA_UPSAMPLING_NEAREST));
-
// If toRGBAlphaMode is active (not no-op), assert that the alpha plane is present. The end of
// the avifPrepareReformatState() function should ensure this, but this assert makes it clear
// to clang's analyzer.
@@ -639,18 +633,16 @@
}
}
- if (chromaUpsampling == AVIF_CHROMA_UPSAMPLING_BILINEAR) {
+ if (flags & AVIF_CHROMA_UPSAMPLING_NEAREST) {
+ // Nearest neighbor; ignore all UVs but the closest one
+ Cb = unormFloatTableUV[unormU[0][0]];
+ Cr = unormFloatTableUV[unormV[0][0]];
+ } else {
// Bilinear filtering with weights
Cb = (unormFloatTableUV[unormU[0][0]] * (9.0f / 16.0f)) + (unormFloatTableUV[unormU[1][0]] * (3.0f / 16.0f)) +
(unormFloatTableUV[unormU[0][1]] * (3.0f / 16.0f)) + (unormFloatTableUV[unormU[1][1]] * (1.0f / 16.0f));
Cr = (unormFloatTableUV[unormV[0][0]] * (9.0f / 16.0f)) + (unormFloatTableUV[unormV[1][0]] * (3.0f / 16.0f)) +
(unormFloatTableUV[unormV[0][1]] * (3.0f / 16.0f)) + (unormFloatTableUV[unormV[1][1]] * (1.0f / 16.0f));
- } else {
- assert(chromaUpsampling == AVIF_CHROMA_UPSAMPLING_NEAREST);
-
- // Nearest neighbor; ignore all UVs but the closest one
- Cb = unormFloatTableUV[unormU[0][0]];
- Cr = unormFloatTableUV[unormV[0][0]];
}
}
}
@@ -1157,9 +1149,12 @@
return AVIF_RESULT_OK;
}
-static avifResult avifRGBImageToF16(avifRGBImage * rgb)
+static avifResult avifRGBImageToF16(avifRGBImage * rgb, avifYUVToRGBFlags flags)
{
- avifResult libyuvResult = avifRGBImageToF16LibYUV(rgb);
+ avifResult libyuvResult = AVIF_RESULT_NOT_IMPLEMENTED;
+ if (!(flags & AVIF_YUV_TO_RGB_AVOID_LIBYUV)) {
+ libyuvResult = avifRGBImageToF16LibYUV(rgb);
+ }
if (libyuvResult != AVIF_RESULT_NOT_IMPLEMENTED) {
return libyuvResult;
}
@@ -1186,7 +1181,7 @@
return AVIF_RESULT_OK;
}
-avifResult avifImageYUVToRGB(const avifImage * image, avifRGBImage * rgb)
+avifResult avifImageYUVToRGB(const avifImage * image, avifRGBImage * rgb, avifYUVToRGBFlags flags)
{
if (!image->yuvPlanes[AVIF_CHAN_Y]) {
return AVIF_RESULT_REFORMAT_FAILED;
@@ -1197,10 +1192,16 @@
return AVIF_RESULT_REFORMAT_FAILED;
}
+ // At most one filter can be specified.
+ if ((flags & AVIF_CHROMA_UPSAMPLING_NEAREST) && (flags & AVIF_CHROMA_UPSAMPLING_BILINEAR)) {
+ return AVIF_RESULT_REFORMAT_FAILED;
+ }
+
avifAlphaMultiplyMode alphaMultiplyMode = state.toRGBAlphaMode;
avifBool convertedWithLibYUV = AVIF_FALSE;
- if (alphaMultiplyMode == AVIF_ALPHA_MULTIPLY_MODE_NO_OP || avifRGBFormatHasAlpha(rgb->format)) {
- avifResult libyuvResult = avifImageYUVToRGBLibYUV(image, rgb);
+ if (!(flags & AVIF_YUV_TO_RGB_AVOID_LIBYUV) &&
+ ((alphaMultiplyMode == AVIF_ALPHA_MULTIPLY_MODE_NO_OP) || avifRGBFormatHasAlpha(rgb->format))) {
+ avifResult libyuvResult = avifImageYUVToRGBLibYUV(image, rgb, flags);
if (libyuvResult == AVIF_RESULT_OK) {
convertedWithLibYUV = AVIF_TRUE;
} else {
@@ -1245,25 +1246,10 @@
avifResult convertResult = AVIF_RESULT_NOT_IMPLEMENTED;
- avifChromaUpsampling chromaUpsampling;
- switch (rgb->chromaUpsampling) {
- case AVIF_CHROMA_UPSAMPLING_AUTOMATIC:
- case AVIF_CHROMA_UPSAMPLING_BEST_QUALITY:
- case AVIF_CHROMA_UPSAMPLING_BILINEAR:
- default:
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_BILINEAR;
- break;
-
- case AVIF_CHROMA_UPSAMPLING_FASTEST:
- case AVIF_CHROMA_UPSAMPLING_NEAREST:
- chromaUpsampling = AVIF_CHROMA_UPSAMPLING_NEAREST;
- break;
- }
-
const avifBool hasColor =
(image->yuvRowBytes[AVIF_CHAN_U] && image->yuvRowBytes[AVIF_CHAN_V] && (image->yuvFormat != AVIF_PIXEL_FORMAT_YUV400));
- if ((!hasColor || (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) || (chromaUpsampling == AVIF_CHROMA_UPSAMPLING_NEAREST)) &&
+ if ((!hasColor || (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV444) || (flags & AVIF_CHROMA_UPSAMPLING_NEAREST)) &&
(alphaMultiplyMode == AVIF_ALPHA_MULTIPLY_MODE_NO_OP || avifRGBFormatHasAlpha(rgb->format))) {
// Explanations on the above conditional:
// * None of these fast paths currently support bilinear upsampling, so avoid all of them
@@ -1325,7 +1311,7 @@
if (convertResult == AVIF_RESULT_NOT_IMPLEMENTED) {
// If we get here, there is no fast path for this combination. Time to be slow!
- convertResult = avifImageYUVAnyToRGBAnySlow(image, rgb, &state, chromaUpsampling);
+ convertResult = avifImageYUVAnyToRGBAnySlow(image, rgb, &state, flags);
// The slow path also handles alpha (un)multiply, so forget the operation here.
alphaMultiplyMode = AVIF_ALPHA_MULTIPLY_MODE_NO_OP;
@@ -1351,7 +1337,7 @@
// Convert pixels to half floats (F16), if necessary.
if (rgb->isFloat) {
- return avifRGBImageToF16(rgb);
+ return avifRGBImageToF16(rgb, flags);
}
return AVIF_RESULT_OK;
diff --git a/src/reformat_libyuv.c b/src/reformat_libyuv.c
index 3a37ba0..267fb02 100644
--- a/src/reformat_libyuv.c
+++ b/src/reformat_libyuv.c
@@ -12,10 +12,11 @@
(void)rgb;
return AVIF_RESULT_NOT_IMPLEMENTED;
}
-avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb)
+avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb, avifYUVToRGBFlags flags)
{
(void)image;
(void)rgb;
+ (void)flags;
return AVIF_RESULT_NOT_IMPLEMENTED;
}
avifResult avifRGBImagePremultiplyAlphaLibYUV(avifRGBImage * rgb)
@@ -61,15 +62,6 @@
avifResult avifImageRGBToYUVLibYUV(avifImage * image, const avifRGBImage * rgb)
{
- if ((rgb->chromaDownsampling != AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC) && (rgb->chromaDownsampling != AVIF_CHROMA_DOWNSAMPLING_FASTEST)) {
- // libyuv uses integer/fixed-point averaging and RGB-to-YUV conversion.
- // We do not ensure a specific ordering of these two steps and libyuv
- // may perform one or the other depending on the implementation or
- // platform. 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;
- }
-
if ((image->depth == 8) && (rgb->depth == 8)) {
return avifImageRGBToYUVLibYUV8bpc(image, rgb);
}
@@ -235,23 +227,18 @@
static avifResult avifImageYUVToRGBLibYUV8bpc(const avifImage * image,
avifRGBImage * rgb,
const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU);
+ const struct YuvConstants * matrixYVU,
+ avifYUVToRGBFlags flags);
static avifResult avifImageYUVToRGBLibYUVHighBitDepth(const avifImage * image,
avifRGBImage * rgb,
const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU);
+ const struct YuvConstants * matrixYVU,
+ avifYUVToRGBFlags flags);
-avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb)
+avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb, avifYUVToRGBFlags flags)
{
// See if the current settings can be accomplished with libyuv, and use it (if possible).
- if ((rgb->chromaUpsampling != AVIF_CHROMA_UPSAMPLING_AUTOMATIC) && (rgb->chromaUpsampling != AVIF_CHROMA_UPSAMPLING_FASTEST)) {
- // 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;
- }
-
// Find the correct libyuv YuvConstants, based on range and CP/MC
const struct YuvConstants * matrixYUV = NULL;
const struct YuvConstants * matrixYVU = NULL;
@@ -384,11 +371,11 @@
}
if ((image->depth == 8) && (rgb->depth == 8)) {
- return avifImageYUVToRGBLibYUV8bpc(image, rgb, matrixYUV, matrixYVU);
+ return avifImageYUVToRGBLibYUV8bpc(image, rgb, matrixYUV, matrixYVU, flags);
}
if (((image->depth == 10) || (image->depth == 12)) && (rgb->depth == 8)) {
- return avifImageYUVToRGBLibYUVHighBitDepth(image, rgb, matrixYUV, matrixYVU);
+ return avifImageYUVToRGBLibYUVHighBitDepth(image, rgb, matrixYUV, matrixYVU, flags);
}
// This function didn't do anything; use the built-in YUV conversion
@@ -432,7 +419,8 @@
avifResult avifImageYUVToRGBLibYUV8bpc(const avifImage * image,
avifRGBImage * rgb,
const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU)
+ const struct YuvConstants * matrixYVU,
+ avifYUVToRGBFlags flags)
{
// See if the current settings can be accomplished with libyuv, and use it (if possible).
@@ -507,8 +495,7 @@
};
YUVToRGBMatrixFilter yuvToRgbMatrixFilter = lutYuvToRgbMatrixFilter[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;
+ const enum FilterMode filter = (flags & AVIF_CHROMA_UPSAMPLING_NEAREST) ? kFilterNone : kFilterBilinear;
if (yuvToRgbMatrixFilter(image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y],
image->yuvPlanes[uPlaneIndex],
@@ -526,7 +513,11 @@
return AVIF_RESULT_OK;
}
- // Lookup table for YUV To RGB Matrix (without filter).
+ // Only proceed with the nearest-neighbor filter if explicitly specified or left as default.
+ if (flags & AVIF_CHROMA_UPSAMPLING_BILINEAR) {
+ return AVIF_RESULT_NOT_IMPLEMENTED;
+ }
+ // Lookup table for YUV To RGB Matrix (nearest-neighbor filter).
typedef int (
*YUVToRGBMatrix)(const uint8_t *, int, const uint8_t *, int, const uint8_t *, int, uint8_t *, int, const struct YuvConstants *, int, int);
YUVToRGBMatrix lutYuvToRgbMatrix[AVIF_RGB_FORMAT_COUNT][AVIF_PIXEL_FORMAT_COUNT] = {
@@ -564,7 +555,8 @@
avifResult avifImageYUVToRGBLibYUVHighBitDepth(const avifImage * image,
avifRGBImage * rgb,
const struct YuvConstants * matrixYUV,
- const struct YuvConstants * matrixYVU)
+ const struct YuvConstants * matrixYVU,
+ avifYUVToRGBFlags flags)
{
// See if the current settings can be accomplished with libyuv, and use it (if possible).
@@ -627,8 +619,7 @@
};
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;
+ const enum FilterMode filter = (flags & AVIF_CHROMA_UPSAMPLING_NEAREST) ? kFilterNone : kFilterBilinear;
if (yuvToRgbMatrixFilter((const uint16_t *)image->yuvPlanes[AVIF_CHAN_Y],
image->yuvRowBytes[AVIF_CHAN_Y] / 2,
(const uint16_t *)image->yuvPlanes[uPlaneIndex],
@@ -646,7 +637,11 @@
return AVIF_RESULT_OK;
}
- // Lookup table for YUV To RGB Matrix (without filter).
+ // Only proceed with the nearest-neighbor filter if explicitly specified or left as default.
+ if (flags & AVIF_CHROMA_UPSAMPLING_BILINEAR) {
+ return AVIF_RESULT_NOT_IMPLEMENTED;
+ }
+ // Lookup table for YUV To RGB Matrix (nearest-neighbor filter).
typedef int (
*YUVToRGBMatrix)(const uint16_t *, int, const uint16_t *, int, const uint16_t *, int, uint8_t *, int, const struct YuvConstants *, int, int);
// First index: 0: 10bpc, 1: 12bpc
diff --git a/tests/avifyuv.c b/tests/avifyuv.c
index b7e2df1..a98dad7 100644
--- a/tests/avifyuv.c
+++ b/tests/avifyuv.c
@@ -203,8 +203,8 @@
}
}
- avifImageRGBToYUV(image, &srcRGB);
- avifImageYUVToRGB(image, &dstRGB);
+ avifImageRGBToYUV(image, &srcRGB, AVIF_RGB_TO_YUV_DEFAULT);
+ avifImageYUVToRGB(image, &dstRGB, AVIF_YUV_TO_RGB_DEFAULT);
for (int y = 0; y < dim; ++y) {
const uint8_t * srcRow = &srcRGB.pixels[y * srcRGB.rowBytes];
@@ -344,23 +344,23 @@
avifImageFreePlanes(image, AVIF_PLANES_ALL);
image->depth = yuvDepth;
image->yuvRange = yuvRange;
- avifImageRGBToYUV(image, &srcRGB);
+ avifImageRGBToYUV(image, &srcRGB, AVIF_RGB_TO_YUV_DEFAULT);
avifRGBImage intermediateRGB;
avifRGBImageSetDefaults(&intermediateRGB, image);
intermediateRGB.depth = rgbDepth;
intermediateRGB.format = rgbFormat;
avifRGBImageAllocatePixels(&intermediateRGB);
- avifImageYUVToRGB(image, &intermediateRGB);
+ avifImageYUVToRGB(image, &intermediateRGB, AVIF_YUV_TO_RGB_DEFAULT);
avifImageFreePlanes(image, AVIF_PLANES_ALL);
- avifImageRGBToYUV(image, &intermediateRGB);
+ avifImageRGBToYUV(image, &intermediateRGB, AVIF_RGB_TO_YUV_DEFAULT);
avifRGBImage dstRGB;
avifRGBImageSetDefaults(&dstRGB, image);
dstRGB.depth = yuvDepth;
avifRGBImageAllocatePixels(&dstRGB);
- avifImageYUVToRGB(image, &dstRGB);
+ avifImageYUVToRGB(image, &dstRGB, AVIF_YUV_TO_RGB_DEFAULT);
avifBool moveOn = AVIF_FALSE;
for (uint32_t j = 0; j < originalHeight; ++j) {
diff --git a/tests/gtest/avifrgbtoyuvtest.cc b/tests/gtest/avifrgbtoyuvtest.cc
index 27f5607..b7bb0d2 100644
--- a/tests/gtest/avifrgbtoyuvtest.cc
+++ b/tests/gtest/avifrgbtoyuvtest.cc
@@ -182,12 +182,10 @@
ModifyImageChannel(&src_rgb, offsets.b, kBlueNoise);
}
- // Change these to BEST_QUALITY to force built-in over libyuv conversion.
- src_rgb.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC;
- dst_rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
-
- ASSERT_EQ(avifImageRGBToYUV(yuv.get(), &src_rgb), AVIF_RESULT_OK);
- ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &dst_rgb), AVIF_RESULT_OK);
+ ASSERT_EQ(avifImageRGBToYUV(yuv.get(), &src_rgb, AVIF_RGB_TO_YUV_DEFAULT),
+ AVIF_RESULT_OK);
+ ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &dst_rgb, AVIF_YUV_TO_RGB_DEFAULT),
+ AVIF_RESULT_OK);
GetDiffSumAndSqDiffSum(src_rgb, dst_rgb, &diff_sum, &abs_diff_sum,
&sq_diff_sum, &max_abs_diff);
num_diffs += src_rgb.width * src_rgb.height * 3; // Alpha is lossless.
@@ -205,13 +203,12 @@
ModifyImageChannel(&src_rgb, offsets.b, kBlueNoise);
}
- // Change these to BEST_QUALITY to force built-in over libyuv
- // conversion.
- src_rgb.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC;
- dst_rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
-
- ASSERT_EQ(avifImageRGBToYUV(yuv.get(), &src_rgb), AVIF_RESULT_OK);
- ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &dst_rgb), AVIF_RESULT_OK);
+ ASSERT_EQ(
+ avifImageRGBToYUV(yuv.get(), &src_rgb, AVIF_RGB_TO_YUV_DEFAULT),
+ AVIF_RESULT_OK);
+ ASSERT_EQ(
+ avifImageYUVToRGB(yuv.get(), &dst_rgb, AVIF_YUV_TO_RGB_DEFAULT),
+ AVIF_RESULT_OK);
GetDiffSumAndSqDiffSum(src_rgb, dst_rgb, &diff_sum, &abs_diff_sum,
&sq_diff_sum, &max_abs_diff);
num_diffs +=
@@ -276,9 +273,6 @@
yuv->yuvRange = yuv_range;
testutil::AvifRgbImage src_rgb(yuv.get(), rgb_depth, rgb_format);
testutil::AvifRgbImage dst_rgb(yuv.get(), rgb_depth, rgb_format);
- // Change these to BEST_QUALITY to force built-in over libyuv conversion.
- src_rgb.chromaDownsampling = AVIF_CHROMA_DOWNSAMPLING_AUTOMATIC;
- dst_rgb.chromaUpsampling = AVIF_CHROMA_UPSAMPLING_AUTOMATIC;
const testutil::RgbChannelOffsets offsets =
testutil::GetRgbChannelOffsets(rgb_format);
@@ -298,8 +292,10 @@
testutil::FillImageChannel(&src_rgb, offsets.a, rgb_max);
}
- ASSERT_EQ(avifImageRGBToYUV(yuv.get(), &src_rgb), AVIF_RESULT_OK);
- ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &dst_rgb), AVIF_RESULT_OK);
+ ASSERT_EQ(avifImageRGBToYUV(yuv.get(), &src_rgb, AVIF_RGB_TO_YUV_DEFAULT),
+ AVIF_RESULT_OK);
+ ASSERT_EQ(avifImageYUVToRGB(yuv.get(), &dst_rgb, AVIF_YUV_TO_RGB_DEFAULT),
+ AVIF_RESULT_OK);
GetDiffSumAndSqDiffSum(src_rgb, dst_rgb, &diff_sum, &abs_diff_sum,
&sq_diff_sum, &max_abs_diff);
num_diffs += src_rgb.width * src_rgb.height * 3;
diff --git a/tests/oss-fuzz/avif_decode_fuzzer.cc b/tests/oss-fuzz/avif_decode_fuzzer.cc
index 173040f..80e5d97 100644
--- a/tests/oss-fuzz/avif_decode_fuzzer.cc
+++ b/tests/oss-fuzz/avif_decode_fuzzer.cc
@@ -8,8 +8,8 @@
static avifRGBFormat rgbFormats[] = { AVIF_RGB_FORMAT_RGB, AVIF_RGB_FORMAT_RGBA };
static size_t rgbFormatsCount = sizeof(rgbFormats) / sizeof(rgbFormats[0]);
- static avifChromaUpsampling upsamplings[] = { AVIF_CHROMA_UPSAMPLING_BILINEAR, AVIF_CHROMA_UPSAMPLING_NEAREST };
- static size_t upsamplingsCount = sizeof(upsamplings) / sizeof(upsamplings[0]);
+ static avifYUVToRGBFlags upsamplingFlags[] = { AVIF_CHROMA_UPSAMPLING_BILINEAR, AVIF_CHROMA_UPSAMPLING_NEAREST };
+ static size_t upsamplingFlagsCount = sizeof(upsamplingFlags) / sizeof(upsamplingFlags[0]);
static uint32_t rgbDepths[] = { 8, 10 };
static size_t rgbDepthsCount = sizeof(rgbDepths) / sizeof(rgbDepths[0]);
@@ -43,24 +43,24 @@
avifRGBImageSetDefaults(&rgb, decoder->image);
for (size_t rgbFormatsIndex = 0; rgbFormatsIndex < rgbFormatsCount; ++rgbFormatsIndex) {
- for (size_t upsamplingsIndex = 0; upsamplingsIndex < upsamplingsCount; ++upsamplingsIndex) {
+ for (size_t upsamplingFlagsIndex = 0; upsamplingFlagsIndex < upsamplingFlagsCount; ++upsamplingFlagsIndex) {
for (size_t rgbDepthsIndex = 0; rgbDepthsIndex < rgbDepthsCount; ++rgbDepthsIndex) {
// Convert to RGB
rgb.format = rgbFormats[rgbFormatsIndex];
rgb.depth = rgbDepths[rgbDepthsIndex];
- rgb.chromaUpsampling = upsamplings[upsamplingsIndex];
avifRGBImageAllocatePixels(&rgb);
- avifResult rgbResult = avifImageYUVToRGB(decoder->image, &rgb);
- // Since avifImageRGBToYUV() ignores rgb.chromaUpsampling, we only need
- // to test avifImageRGBToYUV() with a single upsamplingsIndex.
- if ((rgbResult == AVIF_RESULT_OK) && (upsamplingsIndex == 0)) {
+ avifResult rgbResult =
+ avifImageYUVToRGB(decoder->image, &rgb, AVIF_YUV_TO_RGB_AVOID_LIBYUV | upsamplingFlags[upsamplingFlagsIndex]);
+ // Since avifImageRGBToYUV() ignores upsamplingFlags, we only need
+ // to test avifImageRGBToYUV() with a single upsamplingFlagsIndex.
+ if ((rgbResult == AVIF_RESULT_OK) && (upsamplingFlagsIndex == 0)) {
for (size_t yuvDepthsIndex = 0; yuvDepthsIndex < yuvDepthsCount; ++yuvDepthsIndex) {
// ... and back to YUV
avifImage * tempImage = avifImageCreate(decoder->image->width,
decoder->image->height,
yuvDepths[yuvDepthsIndex],
decoder->image->yuvFormat);
- avifResult yuvResult = avifImageRGBToYUV(tempImage, &rgb);
+ avifResult yuvResult = avifImageRGBToYUV(tempImage, &rgb, AVIF_RGB_TO_YUV_AVOID_LIBYUV);
if (yuvResult != AVIF_RESULT_OK) {
}
avifImageDestroy(tempImage);