chromium/third_party/libavif/src/src/reformat_libyuv.c

// Copyright 2019 Joe Drago. All rights reserved.
// SPDX-License-Identifier: BSD-2-Clause

#include "avif/internal.h"

#if !defined(AVIF_LIBYUV_ENABLED)

// No libyuv!
avifResult avifImageRGBToYUVLibYUV(avifImage * image, const avifRGBImage * rgb)
{
    (void)image;
    (void)rgb;
    return AVIF_RESULT_NOT_IMPLEMENTED;
}
avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb, avifBool reformatAlpha, avifBool * alphaReformattedWithLibYUV)
{
    (void)image;
    (void)rgb;
    (void)reformatAlpha;
    *alphaReformattedWithLibYUV = AVIF_FALSE;
    return AVIF_RESULT_NOT_IMPLEMENTED;
}
avifResult avifRGBImagePremultiplyAlphaLibYUV(avifRGBImage * rgb)
{
    (void)rgb;
    return AVIF_RESULT_NOT_IMPLEMENTED;
}
avifResult avifRGBImageUnpremultiplyAlphaLibYUV(avifRGBImage * rgb)
{
    (void)rgb;
    return AVIF_RESULT_NOT_IMPLEMENTED;
}
avifResult avifRGBImageToF16LibYUV(avifRGBImage * rgb)
{
    (void)rgb;
    return AVIF_RESULT_NOT_IMPLEMENTED;
}
unsigned int avifLibYUVVersion(void)
{
    return 0;
}

#else

#include <assert.h>
#include <limits.h>
#include <string.h>

#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__)
#pragma clang diagnostic pop
#endif

// libyuv is a C++ library and defines custom types (struct, enum, etc) in the libyuv namespace when the libyuv header files are
// included by C++ code. When accessed from a C library like libavif, via a function pointer, this leads to signature mismatches
// in the CFI sanitizers since libyuv itself, compiled as C++ code, has the types within the namespace and the C code has the
// types without the namespace. The same thing happens with clang's undefined behavior sanitizer as well when invoked with
// -fsanitize=function. So we suppress both of these sanitizers in functions that call libyuv functions via a pointer.
// For a simpler example of this bug, please see: https://github.com/vigneshvg/cpp_c_potential_cfi_bug.
// For more details on clang's CFI see: https://clang.llvm.org/docs/ControlFlowIntegrity.html.
// For more details on clang's UBSan see: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
#if defined(__clang__)
#define IGNORE_CFI_ICALL
#else
#define IGNORE_CFI_ICALL
#endif

//--------------------------------------------------------------------------------------------------
// libyuv API availability management

// These defines are used to create a NULL reference to libyuv functions that
// did not exist prior to a particular version of libyuv.
// Versions prior to 1755 are considered too old and not used (see CMakeLists.txt).
#if LIBYUV_VERSION < 1844
// I444ToRGB24Matrix() and I422ToRGB24MatrixFilter() were added in libyuv version 1844.
//
// Note: Between the following two commits, libyuv version jumped from 1841 to 1844, down to 1843,
// and back to 1844. See https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3906082 and
// https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3906091.
#define I444ToRGB24Matrix
#define I422ToRGB24MatrixFilter
#endif
#if LIBYUV_VERSION < 1841
// I420ToRGB24MatrixFilter() was added in libyuv version 1841.
// See https://chromium-review.googlesource.com/c/libyuv/libyuv/+/3900298.
#define I420ToRGB24MatrixFilter
#endif
#if LIBYUV_VERSION < 1840
#define ABGRToJ400
#endif
#if LIBYUV_VERSION < 1838
#define I422ToRGB565Matrix
#endif
#if LIBYUV_VERSION < 1813
#define I422ToARGBMatrixFilter
#define I420ToARGBMatrixFilter
#define I210ToARGBMatrixFilter
#define I010ToARGBMatrixFilter
#define I420AlphaToARGBMatrixFilter
#define I422AlphaToARGBMatrixFilter
#define I010AlphaToARGBMatrixFilter
#define I210AlphaToARGBMatrixFilter
#endif
#if LIBYUV_VERSION < 1782
#define RAWToJ420
#endif
#if LIBYUV_VERSION < 1781
#define I012ToARGBMatrix
#endif
#if LIBYUV_VERSION < 1780
#define I410ToARGBMatrix
#define I410AlphaToARGBMatrix
#define I210AlphaToARGBMatrix
#define I010AlphaToARGBMatrix
#endif
#if LIBYUV_VERSION < 1771
#define I422AlphaToARGBMatrix
#define I444AlphaToARGBMatrix
#endif
#if LIBYUV_VERSION < 1756
#define I400ToARGBMatrix
#endif

// Two-step replacement for the conversions to 8-bit BT.601 YUV which are missing from libyuv.
static int avifReorderARGBThenConvertToYUV(int (*ReorderARGB)(const uint8_t *, int, uint8_t *, int, int, int),
                                           int (*ConvertToYUV)(const uint8_t *, int, uint8_t *, int, uint8_t *, int, uint8_t *, int, int, int),
                                           const uint8_t * src_abgr,
                                           int src_stride_abgr,
                                           uint8_t * dst_y,
                                           int dst_stride_y,
                                           uint8_t * dst_u,
                                           int dst_stride_u,
                                           uint8_t * dst_v,
                                           int dst_stride_v,
                                           avifPixelFormat dst_format,
                                           int width,
                                           int height)
{}

#define AVIF_DEFINE_CONVERSION(NAME, REORDER_ARGB, CONVERT_TO_YUV, YUV_FORMAT)

#if LIBYUV_VERSION < 1840
// AVIF_RGB_FORMAT_RGBA
AVIF_DEFINE_CONVERSION(ABGRToJ422, ABGRToARGB, ARGBToJ422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(ABGRToJ420, ABGRToARGB, ARGBToJ420, AVIF_PIXEL_FORMAT_YUV420)
#endif

// These are not yet implemented in libyuv so they cannot be guarded by a version check.
// The "avif" prefix avoids any redefinition if they are available in libyuv one day.
// AVIF_RGB_FORMAT_RGB
AVIF_DEFINE_CONVERSION(avifRAWToI444, RAWToARGB, ARGBToI444, AVIF_PIXEL_FORMAT_YUV444)
AVIF_DEFINE_CONVERSION(avifRAWToI422, RAWToARGB, ARGBToI422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifRAWToJ422, RAWToARGB, ARGBToJ422, AVIF_PIXEL_FORMAT_YUV422)
// AVIF_RGB_FORMAT_RGBA
AVIF_DEFINE_CONVERSION(avifABGRToI444, ABGRToARGB, ARGBToI444, AVIF_PIXEL_FORMAT_YUV444)
AVIF_DEFINE_CONVERSION(avifABGRToI422, ABGRToARGB, ARGBToI422, AVIF_PIXEL_FORMAT_YUV422)
// AVIF_RGB_FORMAT_ARGB
AVIF_DEFINE_CONVERSION(avifBGRAToI444, BGRAToARGB, ARGBToI444, AVIF_PIXEL_FORMAT_YUV444)
AVIF_DEFINE_CONVERSION(avifBGRAToI422, BGRAToARGB, ARGBToI422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifBGRAToJ422, BGRAToARGB, ARGBToJ422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifBGRAToJ420, BGRAToARGB, ARGBToJ420, AVIF_PIXEL_FORMAT_YUV420)
// AVIF_RGB_FORMAT_BGR
AVIF_DEFINE_CONVERSION(avifRGB24ToI444, RGB24ToARGB, ARGBToI444, AVIF_PIXEL_FORMAT_YUV444)
AVIF_DEFINE_CONVERSION(avifRGB24ToI422, RGB24ToARGB, ARGBToI422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifRGB24ToJ422, RGB24ToARGB, ARGBToJ422, AVIF_PIXEL_FORMAT_YUV422)
// AVIF_RGB_FORMAT_ABGR
AVIF_DEFINE_CONVERSION(avifRGBAToI444, RGBAToARGB, ARGBToI444, AVIF_PIXEL_FORMAT_YUV444)
AVIF_DEFINE_CONVERSION(avifRGBAToI422, RGBAToARGB, ARGBToI422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifRGBAToJ422, RGBAToARGB, ARGBToJ422, AVIF_PIXEL_FORMAT_YUV422)
AVIF_DEFINE_CONVERSION(avifRGBAToJ420, RGBAToARGB, ARGBToJ420, AVIF_PIXEL_FORMAT_YUV420)

//--------------------------------------------------------------------------------------------------
// RGB to YUV

static avifResult avifImageRGBToYUVLibYUV8bpc(avifImage * image, const avifRGBImage * rgb);

avifResult avifImageRGBToYUVLibYUV(avifImage * image, const avifRGBImage * rgb)
{}

avifResult avifImageRGBToYUVLibYUV8bpc(avifImage * image, const avifRGBImage * rgb)
{}

//--------------------------------------------------------------------------------------------------
// YUV to RGB

// Note about the libyuv look up tables used for YUV-to-RGB conversion:
// 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.  In addition, swapping U and V in any of the
// calls, along with using the Yvu matrix instead of Yuv matrix, swaps B and R in these orderings as well.
//
// libavif format            libyuv Func      UV matrix (and UV argument ordering)
// --------------------      -------------    ------------------------------------
// For 8-bit YUV:
// AVIF_RGB_FORMAT_RGB       *ToRGB24Matrix   matrixYVU
// AVIF_RGB_FORMAT_RGBA      *ToARGBMatrix    matrixYVU
// AVIF_RGB_FORMAT_ARGB      *ToRGBAMatrix    matrixYVU
// AVIF_RGB_FORMAT_BGR       *ToRGB24Matrix   matrixYUV
// AVIF_RGB_FORMAT_BGRA      *ToARGBMatrix    matrixYUV
// AVIF_RGB_FORMAT_ABGR      *ToRGBAMatrix    matrixYUV
// AVIF_RGB_FORMAT_RGB_565   *ToRGB565Matrix  matrixYUV
//
// For 10-bit and 12-bit YUV:
// AVIF_RGB_FORMAT_RGB       n/a              n/a
// AVIF_RGB_FORMAT_RGBA      *ToARGBMatrix    matrixYVU
// AVIF_RGB_FORMAT_ARGB      n/a              n/a
// AVIF_RGB_FORMAT_BGR       n/a              n/a
// AVIF_RGB_FORMAT_BGRA      *ToARGBMatrix    matrixYUV
// AVIF_RGB_FORMAT_ABGR      n/a              n/a
// AVIF_RGB_FORMAT_RGB_565   n/a              n/a

// 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,
// which requires U and V planes also be swapped.
static const avifBool lutIsYVU[AVIF_RGB_FORMAT_COUNT] =;

YUV400ToRGBMatrix;
YUVToRGBMatrixFilter;
YUVAToRGBMatrixFilter;
YUVToRGBMatrix;
YUVAToRGBMatrix;
YUVToRGBMatrixFilterHighBitDepth;
YUVAToRGBMatrixFilterHighBitDepth;
YUVToRGBMatrixHighBitDepth;
YUVAToRGBMatrixHighBitDepth;

// At most one pointer in this struct will be not-NULL.
LibyuvConversionFunction;

// Only allow nearest-neighbor filter if explicitly specified or left as default.
static avifBool nearestNeighborFilterAllowed(int chromaUpsampling)
{}

// Returns AVIF_TRUE if the given yuvFormat and yuvDepth can be converted to 8-bit RGB using libyuv, AVIF_FALSE otherwise. When
// AVIF_TRUE is returned, exactly one function pointers will be populated with the appropriate conversion function. If
// alphaPreferred is set to AVIF_TRUE, then a function that can also copy the alpha channel will be preferred if available.
static avifBool getLibYUVConversionFunction(avifPixelFormat yuvFormat,
                                            int yuvDepth,
                                            avifRGBImage * rgb,
                                            avifBool alphaPreferred,
                                            LibyuvConversionFunction * lcf)
{}

static void getLibYUVConstants(const avifImage * image, const struct YuvConstants ** matrixYUV, const struct YuvConstants ** matrixYVU)
{}

static avifResult avifImageDownshiftTo8bpc(const avifImage * image, avifImage * image8, avifBool downshiftAlpha)
{}

IGNORE_CFI_ICALL avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb, avifBool reformatAlpha, avifBool * alphaReformattedWithLibYUV)
{}

//--------------------------------------------------------------------------------------------------

avifResult avifRGBImagePremultiplyAlphaLibYUV(avifRGBImage * rgb)
{}

avifResult avifRGBImageUnpremultiplyAlphaLibYUV(avifRGBImage * rgb)
{}

avifResult avifRGBImageToF16LibYUV(avifRGBImage * rgb)
{}

unsigned int avifLibYUVVersion(void)
{}

#endif