Add SharpYuv RGB->YUV conversion from libsharpyuv

Not used yet.
Use pkg-config to find libsharpyuv instead of WebP.cmake as it's not always present.
Update ci files.
diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml
index 48714a3..414cbe5 100644
--- a/.github/workflows/ci-windows.yml
+++ b/.github/workflows/ci-windows.yml
@@ -70,6 +70,10 @@
       if: steps.cache-ext.outputs.cache-hit != 'true'
       working-directory: ./ext
       run: ./libjpeg.cmd
+    - name: Build libsharpyuv
+      if: steps.cache-ext.outputs.cache-hit != 'true'
+      working-directory: ./ext
+      run: ./libsharpyuv.cmd
     - name: Build zlib and libpng
       if: steps.cache-ext.outputs.cache-hit != 'true'
       working-directory: ./ext
@@ -91,6 +95,7 @@
         -DAVIF_CODEC_SVT=ON -DAVIF_LOCAL_SVT=ON
         -DAVIF_CODEC_LIBGAV1=ON -DAVIF_LOCAL_LIBGAV1=ON
         -DAVIF_LOCAL_LIBYUV=ON -DAVIF_LOCAL_JPEG=ON
+        -DAVIF_LOCAL_LIBSHARPYUV=ON
         -DAVIF_LOCAL_ZLIBPNG=ON
         -DAVIF_BUILD_EXAMPLES=ON -DAVIF_BUILD_APPS=ON
         -DAVIF_BUILD_TESTS=ON -DAVIF_ENABLE_GTEST=ON -DAVIF_LOCAL_GTEST=ON
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6189feb..80d9e79 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,7 +26,7 @@
     - name: Setup cmake
       uses: jwlawson/actions-setup-cmake@v1.12
       with:
-        cmake-version: '3.13.x'
+        cmake-version: '3.17.x'
     - name: Print cmake version
       run: cmake --version
     - uses: ilammy/setup-nasm@v1
@@ -62,6 +62,10 @@
       if: steps.cache-ext.outputs.cache-hit != 'true'
       working-directory: ./ext
       run: bash libjpeg.cmd
+    - name: Build libsharpyuv
+      if: steps.cache-ext.outputs.cache-hit != 'true'
+      working-directory: ./ext
+      run: bash libsharpyuv.cmd
     - name: Build GoogleTest
       if: steps.cache-ext.outputs.cache-hit != 'true'
       working-directory: ./ext
@@ -80,6 +84,7 @@
         -DAVIF_CODEC_SVT=ON -DAVIF_LOCAL_SVT=ON
         -DAVIF_CODEC_LIBGAV1=ON -DAVIF_LOCAL_LIBGAV1=ON
         -DAVIF_LOCAL_LIBYUV=ON -DAVIF_LOCAL_JPEG=ON
+        -DAVIF_LOCAL_LIBSHARPYUV=ON
         -DAVIF_BUILD_EXAMPLES=ON -DAVIF_BUILD_APPS=ON
         -DAVIF_BUILD_TESTS=ON -DAVIF_ENABLE_GTEST=ON -DAVIF_LOCAL_GTEST=ON
     - name: Build libavif (ninja)
diff --git a/.gitignore b/.gitignore
index fa481e6..8d595f8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 /ext/libjpeg
 /ext/libgav1
 /ext/libpng
+/ext/libwebp
 /ext/libyuv
 /ext/rav1e
 /ext/SVT-AV1
diff --git a/.travis.yml b/.travis.yml
index 61327b9..9b2e077 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -26,11 +26,12 @@
   - bash rav1e.cmd
   - bash svt.cmd
   - bash libyuv.cmd
+  - bash libsharpyuv.cmd
   - cd ..
   - mkdir build
   - cd build
 script:
-  - cmake -G Ninja -DCMAKE_BUILD_TYPE=$config -DBUILD_SHARED_LIBS=OFF -DAVIF_CODEC_AOM=ON -DAVIF_LOCAL_AOM=ON -DAVIF_CODEC_DAV1D=ON -DAVIF_LOCAL_DAV1D=ON -DAVIF_CODEC_RAV1E=ON -DAVIF_LOCAL_RAV1E=ON -DAVIF_CODEC_LIBGAV1=ON -DAVIF_LOCAL_LIBGAV1=ON -DAVIF_CODEC_SVT=ON -DAVIF_LOCAL_SVT=ON -DAVIF_LOCAL_LIBYUV=ON -DAVIF_BUILD_EXAMPLES=ON -DAVIF_BUILD_APPS=ON -DAVIF_BUILD_TESTS=ON ..
+  - cmake -G Ninja -DCMAKE_BUILD_TYPE=$config -DBUILD_SHARED_LIBS=OFF -DAVIF_CODEC_AOM=ON -DAVIF_LOCAL_AOM=ON -DAVIF_CODEC_DAV1D=ON -DAVIF_LOCAL_DAV1D=ON -DAVIF_CODEC_RAV1E=ON -DAVIF_LOCAL_RAV1E=ON -DAVIF_CODEC_LIBGAV1=ON -DAVIF_LOCAL_LIBGAV1=ON -DAVIF_CODEC_SVT=ON -DAVIF_LOCAL_SVT=ON -DAVIF_LOCAL_LIBYUV=ON -DAVIF_LOCAL_LIBSHARPYUV=ON -DAVIF_BUILD_EXAMPLES=ON -DAVIF_BUILD_APPS=ON -DAVIF_BUILD_TESTS=ON ..
   - ninja
 
 matrix:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f5ec52..3efaac1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -124,6 +124,23 @@
         set(LIBYUV_LIBRARY ${LIB_FILENAME} PARENT_SCOPE)
     endif()
 endif()
+option(AVIF_LOCAL_LIBSHARPYUV "Build libsharpyuv by providing your own copy inside the ext subdir." OFF)
+if(AVIF_LOCAL_LIBSHARPYUV)
+    set(LIB_FILENAME
+        "${CMAKE_CURRENT_SOURCE_DIR}/ext/libwebp/build/libsharpyuv${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    )
+    message(STATUS "AVIF_LOCAL_LIBSHARPYUV LIB_FILENAME ${LIB_FILENAME}")
+    if(NOT EXISTS "${LIB_FILENAME}")
+        message(FATAL_ERROR "libavif(AVIF_LOCAL_LIBSHARPYUV): ${LIB_FILENAME} is missing, bailing out")
+    endif()
+    if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+        set(LIBSHARPYUV_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/libwebp")
+        set(LIBSHARPYUV_LIBRARY ${LIB_FILENAME})
+    else()
+        set(LIBSHARPYUV_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/libwebp" PARENT_SCOPE)
+        set(LIBSHARPYUV_LIBRARY ${LIB_FILENAME} PARENT_SCOPE)
+    endif()
+endif()
 # ---------------------------------------------------------------------------------------
 
 # Enable all warnings
@@ -187,6 +204,7 @@
     src/read.c
     src/reformat.c
     src/reformat_libyuv.c
+    src/reformat_libsharpyuv.c
     src/scale.c
     src/stream.c
     src/utils.c
@@ -226,6 +244,16 @@
     message(STATUS "libavif: libyuv not found; libyuv-based fast paths disabled.")
 endif()
 
+find_package(libsharpyuv QUIET) # not required
+if (libsharpyuv_FOUND)
+    message(STATUS "libavif: libsharpyuv found; sharp rgb to yuv conversion enabled.")
+    set(AVIF_PLATFORM_DEFINITIONS ${AVIF_PLATFORM_DEFINITIONS} -DAVIF_LIBSHARPYUV_ENABLED=1)
+    set(AVIF_PLATFORM_INCLUDES ${AVIF_PLATFORM_INCLUDES} ${LIBSHARPYUV_INCLUDE_DIR})
+    set(AVIF_PLATFORM_LIBRARIES ${AVIF_PLATFORM_LIBRARIES} ${LIBSHARPYUV_LIBRARY})
+else()
+    message(STATUS "libavif: libsharpyuv not found")
+endif()
+
 set(AVIF_CODEC_DEFINITIONS)
 set(AVIF_CODEC_INCLUDES)
 set(AVIF_CODEC_LIBRARIES)
diff --git a/ext/libsharpyuv.cmd b/ext/libsharpyuv.cmd
new file mode 100755
index 0000000..b4e70c7
--- /dev/null
+++ b/ext/libsharpyuv.cmd
@@ -0,0 +1,21 @@
+: # If you want to use a local build of libsharpyuv, you must clone the libwebp repo in this directory first,
+: # then enable CMake's AVIF_LOCAL_LIBSHARPYUV option.
+
+: # The odd choice of comment style in this file is to try to share this script between *nix and win32.
+
+: # cmake and ninja must be in your PATH.
+
+: # If you're running this on Windows, be sure you've already run this (from your VC2019 install dir):
+: #     "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat"
+
+: # libsharpyuv is part of the libwebp repo.
+git clone --single-branch https://chromium.googlesource.com/webm/libwebp
+
+cd libwebp
+git checkout 15a91ab
+
+mkdir build
+cd build
+cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DWEBP_BUILD_CWEBP=OFF -DCMAKE_BUILD_TYPE=Release ..
+ninja
+cd ../..
diff --git a/include/avif/internal.h b/include/avif/internal.h
index 87bb374..8b1ef22 100644
--- a/include/avif/internal.h
+++ b/include/avif/internal.h
@@ -152,6 +152,12 @@
 avifResult avifImageYUVToRGBLibYUV(const avifImage * image, avifRGBImage * rgb);
 
 // Returns:
+// * AVIF_RESULT_OK              - Converted successfully with libsharpyuv
+// * AVIF_RESULT_NOT_IMPLEMENTED - libsharpyuv is not compiled in, or doesn't support this type of input
+// * [any other error]           - Return error to caller
+avifResult avifImageRGBToYUVLibSharpYUV(avifImage * image, const avifRGBImage * rgb, const avifReformatState * state);
+
+// Returns:
 // * AVIF_RESULT_OK               - Converted successfully with libyuv.
 // * AVIF_RESULT_NOT_IMPLEMENTED  - The fast path for this conversion is not implemented with libyuv, use built-in conversion.
 // * AVIF_RESULT_INVALID_ARGUMENT - Return error to caller.
diff --git a/src/reformat_libsharpyuv.c b/src/reformat_libsharpyuv.c
new file mode 100644
index 0000000..c9ce2dc
--- /dev/null
+++ b/src/reformat_libsharpyuv.c
@@ -0,0 +1,50 @@
+// Copyright 2022 Google LLC. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include "avif/internal.h"
+
+#if defined(AVIF_LIBSHARPYUV_ENABLED)
+#include <sharpyuv/sharpyuv.h>
+#include <sharpyuv/sharpyuv_csp.h>
+
+avifResult avifImageRGBToYUVLibSharpYUV(avifImage * image, const avifRGBImage * rgb, const avifReformatState * state)
+{
+    const SharpYuvColorSpace color_space = {
+        state->kr, state->kb, image->depth, (state->yuvRange == AVIF_RANGE_LIMITED) ? kSharpYuvRangeLimited : kSharpYuvRangeFull
+    };
+
+    SharpYuvConversionMatrix matrix;
+    // Fills in 'matrix' for the given YUVColorSpace.
+    SharpYuvComputeConversionMatrix(&color_space, &matrix);
+    if (!SharpYuvConvert(&rgb->pixels[state->rgbOffsetBytesR],
+                         &rgb->pixels[state->rgbOffsetBytesG],
+                         &rgb->pixels[state->rgbOffsetBytesB],
+                         state->rgbPixelBytes,
+                         rgb->rowBytes,
+                         rgb->depth,
+                         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],
+                         image->depth,
+                         rgb->width,
+                         rgb->height,
+                         &matrix)) {
+        return AVIF_RESULT_REFORMAT_FAILED;
+    }
+
+    return AVIF_RESULT_OK;
+}
+
+#else
+
+avifResult avifImageRGBToYUVLibSharpYUV(avifImage * image, const avifRGBImage * rgb, const avifReformatState * state)
+{
+    (void)image;
+    (void)rgb;
+    (void)state;
+    return AVIF_RESULT_NOT_IMPLEMENTED;
+}
+#endif