Hook up basic libdav1d support (very lightly tested)
diff --git a/src/codec_dav1d.c b/src/codec_dav1d.c
new file mode 100644
index 0000000..64212e8
--- /dev/null
+++ b/src/codec_dav1d.c
@@ -0,0 +1,153 @@
+// Copyright 2019 Joe Drago. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause
+
+#include "avif/internal.h"
+
+#include "dav1d/dav1d.h"
+
+#include <string.h>
+
+struct avifCodecInternal
+{
+    Dav1dSettings dav1dSettings;
+    Dav1dContext * dav1dContext[AVIF_CODEC_PLANES_COUNT];
+    Dav1dPicture dav1dPicture[AVIF_CODEC_PLANES_COUNT];
+    avifBool hasPicture[AVIF_CODEC_PLANES_COUNT];
+    avifRange colorRange[AVIF_CODEC_PLANES_COUNT];
+};
+
+static void dav1dCodecDestroyInternal(avifCodec * codec)
+{
+    for (int i = 0; i < AVIF_CODEC_PLANES_COUNT; ++i) {
+        if (codec->internal->dav1dContext[i]) {
+            dav1d_close(&codec->internal->dav1dContext[i]);
+        }
+    }
+    avifFree(codec->internal);
+}
+
+static avifBool dav1dCodecDecode(avifCodec * codec, avifCodecPlanes planes, avifRawData * obu)
+{
+    if (codec->internal->dav1dContext[planes] == NULL) {
+        if (dav1d_open(&codec->internal->dav1dContext[planes], &codec->internal->dav1dSettings) != 0) {
+            return AVIF_FALSE;
+        }
+    }
+
+    avifBool result = AVIF_FALSE;
+
+    // OPTIMIZE: Carefully switch this to use dav1d_data_wrap or dav1d_data_wrap_user_data
+    Dav1dData dav1dData;
+    uint8_t * dav1dDataPtr = dav1d_data_create(&dav1dData, obu->size);
+    memcpy(dav1dDataPtr, obu->data, obu->size);
+    if (dav1d_send_data(codec->internal->dav1dContext[planes], &dav1dData) != 0) { // This could return DAV1D_ERR(EAGAIN) and not be a failure if we weren't sending the entire payload
+        goto cleanup;
+    }
+
+    if (dav1d_get_picture(codec->internal->dav1dContext[planes], &codec->internal->dav1dPicture[planes]) != 0) {
+        goto cleanup;
+    }
+
+    codec->internal->hasPicture[planes] = AVIF_TRUE;
+    codec->internal->colorRange[planes] = codec->internal->dav1dPicture[planes].seq_hdr->color_range ? AVIF_RANGE_FULL : AVIF_RANGE_LIMITED;
+    result = AVIF_TRUE;
+cleanup:
+    dav1d_data_unref(&dav1dData);
+    return result;
+}
+
+static avifCodecImageSize dav1dCodecGetImageSize(avifCodec * codec, avifCodecPlanes planes)
+{
+    avifCodecImageSize size;
+    size.width = codec->internal->dav1dPicture[planes].p.w;
+    size.height = codec->internal->dav1dPicture[planes].p.h;
+    return size;
+}
+
+static avifBool dav1dCodecAlphaLimitedRange(avifCodec * codec)
+{
+    if (codec->internal->hasPicture[AVIF_CODEC_PLANES_ALPHA] && (codec->internal->colorRange[AVIF_CODEC_PLANES_ALPHA] == AVIF_RANGE_LIMITED)) {
+        return AVIF_TRUE;
+    }
+    return AVIF_FALSE;
+}
+
+static avifResult dav1dCodecGetDecodedImage(avifCodec * codec, avifImage * image)
+{
+    Dav1dPicture * colorImage = &codec->internal->dav1dPicture[AVIF_CODEC_PLANES_COLOR];
+    Dav1dPicture * alphaImage = &codec->internal->dav1dPicture[AVIF_CODEC_PLANES_ALPHA];
+    avifBool hasAlpha = codec->internal->hasPicture[AVIF_CODEC_PLANES_ALPHA];
+
+    avifPixelFormat yuvFormat = AVIF_PIXEL_FORMAT_NONE;
+    switch (colorImage->p.layout) {
+        case DAV1D_PIXEL_LAYOUT_I400:
+        case DAV1D_PIXEL_LAYOUT_I420:
+            yuvFormat = AVIF_PIXEL_FORMAT_YUV420;
+            break;
+        case DAV1D_PIXEL_LAYOUT_I422:
+            yuvFormat = AVIF_PIXEL_FORMAT_YUV422;
+            break;
+        case DAV1D_PIXEL_LAYOUT_I444:
+            yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
+            break;
+    }
+
+    image->width = colorImage->p.w;
+    image->height = colorImage->p.h;
+    image->depth = colorImage->p.bpc;
+    image->yuvFormat = yuvFormat;
+    image->yuvRange = codec->internal->colorRange[AVIF_CODEC_PLANES_COLOR];
+
+    avifPixelFormatInfo formatInfo;
+    avifGetPixelFormatInfo(yuvFormat, &formatInfo);
+
+    int uvHeight = image->height >> formatInfo.chromaShiftY;
+    avifImageAllocatePlanes(image, AVIF_PLANES_YUV);
+
+    for (int yuvPlane = 0; yuvPlane < 3; ++yuvPlane) {
+        int planeHeight = image->height;
+        if (yuvPlane != AVIF_CHAN_Y) {
+            planeHeight = uvHeight;
+        }
+
+        uint8_t * srcPixels = (uint8_t *)colorImage->data[yuvPlane];
+        ptrdiff_t stride = colorImage->stride[(yuvPlane == AVIF_CHAN_Y) ? 0 : 1];
+        for (int j = 0; j < planeHeight; ++j) {
+            uint8_t * srcRow = &srcPixels[j * stride];
+            uint8_t * dstRow = &image->yuvPlanes[yuvPlane][j * image->yuvRowBytes[yuvPlane]];
+            memcpy(dstRow, srcRow, image->yuvRowBytes[yuvPlane]);
+        }
+
+        if (colorImage->p.layout == DAV1D_PIXEL_LAYOUT_I400) {
+            // Don't memcpy the chroma, its not going to be there
+            break;
+        }
+    }
+
+    if (hasAlpha) {
+        avifImageAllocatePlanes(image, AVIF_PLANES_A);
+        uint8_t * srcAlphaPixels = (uint8_t *)&alphaImage->data[0];
+        for (int j = 0; j < image->height; ++j) {
+            uint8_t * srcAlphaRow = &srcAlphaPixels[j * alphaImage->stride[0]];
+            uint8_t * dstAlphaRow = &image->alphaPlane[j * image->alphaRowBytes];
+            memcpy(dstAlphaRow, srcAlphaRow, image->alphaRowBytes);
+        }
+    }
+    return AVIF_RESULT_OK;
+}
+
+avifCodec * avifCodecCreateDav1d()
+{
+    avifCodec * codec = (avifCodec *)avifAlloc(sizeof(avifCodec));
+    memset(codec, 0, sizeof(struct avifCodec));
+    codec->decode = dav1dCodecDecode;
+    codec->getImageSize = dav1dCodecGetImageSize;
+    codec->alphaLimitedRange = dav1dCodecAlphaLimitedRange;
+    codec->getDecodedImage = dav1dCodecGetDecodedImage;
+    codec->destroyInternal = dav1dCodecDestroyInternal;
+
+    codec->internal = (struct avifCodecInternal *)avifAlloc(sizeof(struct avifCodecInternal));
+    memset(codec->internal, 0, sizeof(struct avifCodecInternal));
+    dav1d_default_settings(&codec->internal->dav1dSettings);
+    return codec;
+}
diff --git a/src/read.c b/src/read.c
index 9fb2099..7b61446 100644
--- a/src/read.c
+++ b/src/read.c
@@ -554,7 +554,7 @@
 {
     avifCodec * codec = NULL;
 
-#ifndef AVIF_CODEC_AOM
+#if !defined(AVIF_CODEC_AOM) && !defined(AVIF_CODEC_DAV1D)
     // Just bail out early, we're not surviving this function without a decoder compiled in
     return AVIF_RESULT_NO_CODEC_AVAILABLE;
 #endif
@@ -652,7 +652,9 @@
     }
     avifBool hasAlpha = (alphaOBU.size > 0) ? AVIF_TRUE : AVIF_FALSE;
 
-#ifdef AVIF_CODEC_AOM
+#if defined(AVIF_CODEC_DAV1D)
+    codec = avifCodecCreateDav1d();
+#elif defined(AVIF_CODEC_AOM)
     codec = avifCodecCreateAOM();
 #else
 // #error No decoder available!