Do not copy input image when encoding with libaom

Avoid the heap allocation of aomImage plane buffers and copying of input
image in aomCodecEncodeImage(). This requires manually setting up the
aom_image_t struct 'aomImage'.

Fix https://github.com/AOMediaCodec/libavif/issues/694.
diff --git a/src/codec_aom.c b/src/codec_aom.c
index 2212eb6..922fa40 100644
--- a/src/codec_aom.c
+++ b/src/codec_aom.c
@@ -727,55 +727,71 @@
 #endif
     }
 
-    int yShift = codec->internal->formatInfo.chromaShiftY;
-    uint32_t uvHeight = (image->height + yShift) >> yShift;
-    aom_image_t * aomImage = aom_img_alloc(NULL, codec->internal->aomFormat, image->width, image->height, 16);
+    aom_image_t aomImage;
+    memset(&aomImage, 0, sizeof(aomImage));
+    aomImage.fmt = codec->internal->aomFormat;
+    aomImage.bit_depth = (image->depth > 8) ? 16 : 8;
+    aomImage.w = image->width;
+    aomImage.h = image->height;
+    aomImage.d_w = image->width;
+    aomImage.d_h = image->height;
+    // Get sample size for this format.
+    unsigned int bps;
+    if (codec->internal->aomFormat == AOM_IMG_FMT_I420) {
+        bps = 12;
+    } else if (codec->internal->aomFormat == AOM_IMG_FMT_I422) {
+        bps = 16;
+    } else if (codec->internal->aomFormat == AOM_IMG_FMT_I444) {
+        bps = 24;
+    } else if (codec->internal->aomFormat == AOM_IMG_FMT_I42016) {
+        bps = 24;
+    } else if (codec->internal->aomFormat == AOM_IMG_FMT_I42216) {
+        bps = 32;
+    } else if (codec->internal->aomFormat == AOM_IMG_FMT_I44416) {
+        bps = 48;
+    } else {
+        bps = 16;
+    }
+    aomImage.bps = bps;
+
     avifBool monochromeRequested = AVIF_FALSE;
 
     if (alpha) {
-        aomImage->range = (image->alphaRange == AVIF_RANGE_FULL) ? AOM_CR_FULL_RANGE : AOM_CR_STUDIO_RANGE;
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, aomImage->range);
+        aomImage.x_chroma_shift = 1;
+        aomImage.y_chroma_shift = 1;
+        aomImage.range = (image->alphaRange == AVIF_RANGE_FULL) ? AOM_CR_FULL_RANGE : AOM_CR_STUDIO_RANGE;
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, aomImage.range);
         monochromeRequested = AVIF_TRUE;
-        for (uint32_t j = 0; j < image->height; ++j) {
-            uint8_t * srcAlphaRow = &image->alphaPlane[j * image->alphaRowBytes];
-            uint8_t * dstAlphaRow = &aomImage->planes[0][j * aomImage->stride[0]];
-            memcpy(dstAlphaRow, srcAlphaRow, image->alphaRowBytes);
-        }
+        aomImage.planes[0] = image->alphaPlane;
+        aomImage.stride[0] = image->alphaRowBytes;
 
         // Ignore UV planes when monochrome
     } else {
-        aomImage->range = (image->yuvRange == AVIF_RANGE_FULL) ? AOM_CR_FULL_RANGE : AOM_CR_STUDIO_RANGE;
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, aomImage->range);
+        aomImage.x_chroma_shift = codec->internal->formatInfo.chromaShiftX;
+        aomImage.y_chroma_shift = codec->internal->formatInfo.chromaShiftY;
+        aomImage.range = (image->yuvRange == AVIF_RANGE_FULL) ? AOM_CR_FULL_RANGE : AOM_CR_STUDIO_RANGE;
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_RANGE, aomImage.range);
         int yuvPlaneCount = 3;
         if (image->yuvFormat == AVIF_PIXEL_FORMAT_YUV400) {
             yuvPlaneCount = 1; // Ignore UV planes when monochrome
             monochromeRequested = AVIF_TRUE;
         }
-        int xShift = codec->internal->formatInfo.chromaShiftX;
-        uint32_t uvWidth = (image->width + xShift) >> xShift;
-        uint32_t bytesPerPixel = (image->depth > 8) ? 2 : 1;
         for (int yuvPlane = 0; yuvPlane < yuvPlaneCount; ++yuvPlane) {
-            uint32_t planeWidth = (yuvPlane == AVIF_CHAN_Y) ? image->width : uvWidth;
-            uint32_t planeHeight = (yuvPlane == AVIF_CHAN_Y) ? image->height : uvHeight;
-            uint32_t bytesPerRow = bytesPerPixel * planeWidth;
-
-            for (uint32_t j = 0; j < planeHeight; ++j) {
-                uint8_t * srcRow = &image->yuvPlanes[yuvPlane][j * image->yuvRowBytes[yuvPlane]];
-                uint8_t * dstRow = &aomImage->planes[yuvPlane][j * aomImage->stride[yuvPlane]];
-                memcpy(dstRow, srcRow, bytesPerRow);
-            }
+            aomImage.planes[yuvPlane] = image->yuvPlanes[yuvPlane];
+            aomImage.stride[yuvPlane] = image->yuvRowBytes[yuvPlane];
         }
 
-        aomImage->cp = (aom_color_primaries_t)image->colorPrimaries;
-        aomImage->tc = (aom_transfer_characteristics_t)image->transferCharacteristics;
-        aomImage->mc = (aom_matrix_coefficients_t)image->matrixCoefficients;
-        aomImage->csp = (aom_chroma_sample_position_t)image->yuvChromaSamplePosition;
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_PRIMARIES, aomImage->cp);
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_TRANSFER_CHARACTERISTICS, aomImage->tc);
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_MATRIX_COEFFICIENTS, aomImage->mc);
-        aom_codec_control(&codec->internal->encoder, AV1E_SET_CHROMA_SAMPLE_POSITION, aomImage->csp);
+        aomImage.cp = (aom_color_primaries_t)image->colorPrimaries;
+        aomImage.tc = (aom_transfer_characteristics_t)image->transferCharacteristics;
+        aomImage.mc = (aom_matrix_coefficients_t)image->matrixCoefficients;
+        aomImage.csp = (aom_chroma_sample_position_t)image->yuvChromaSamplePosition;
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_COLOR_PRIMARIES, aomImage.cp);
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_TRANSFER_CHARACTERISTICS, aomImage.tc);
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_MATRIX_COEFFICIENTS, aomImage.mc);
+        aom_codec_control(&codec->internal->encoder, AV1E_SET_CHROMA_SAMPLE_POSITION, aomImage.csp);
     }
 
+    unsigned char * monoUVPlane = NULL;
     if (monochromeRequested && !codec->internal->monochromeEnabled) {
         // The user requested monochrome (via alpha or YUV400) but libaom cannot currently support
         // monochrome (see chroma_check comment above). Manually set UV planes to 0.5.
@@ -783,21 +799,26 @@
         // aomImage is always 420 when we're monochrome
         uint32_t monoUVWidth = (image->width + 1) >> 1;
         uint32_t monoUVHeight = (image->height + 1) >> 1;
+        uint32_t channelSize = avifImageUsesU16(image) ? 2 : 1;
+        uint32_t monoUVRowBytes = channelSize * monoUVWidth;
+        size_t monoUVSize = (size_t)monoUVHeight * monoUVRowBytes;
 
-        for (int yuvPlane = 1; yuvPlane < 3; ++yuvPlane) {
-            if (image->depth > 8) {
-                const uint16_t half = 1 << (image->depth - 1);
-                for (uint32_t j = 0; j < monoUVHeight; ++j) {
-                    uint16_t * dstRow = (uint16_t *)&aomImage->planes[yuvPlane][j * aomImage->stride[yuvPlane]];
-                    for (uint32_t i = 0; i < monoUVWidth; ++i) {
-                        dstRow[i] = half;
-                    }
+        monoUVPlane = avifAlloc(monoUVSize);
+        if (image->depth > 8) {
+            const uint16_t half = 1 << (image->depth - 1);
+            for (uint32_t j = 0; j < monoUVHeight; ++j) {
+                uint16_t * dstRow = (uint16_t *)&monoUVPlane[(size_t)j * monoUVRowBytes];
+                for (uint32_t i = 0; i < monoUVWidth; ++i) {
+                    dstRow[i] = half;
                 }
-            } else {
-                const uint8_t half = 128;
-                size_t planeSize = (size_t)monoUVHeight * aomImage->stride[yuvPlane];
-                memset(aomImage->planes[yuvPlane], half, planeSize);
             }
+        } else {
+            const uint8_t half = 128;
+            memset(monoUVPlane, half, monoUVSize);
+        }
+        for (int yuvPlane = 1; yuvPlane < 3; ++yuvPlane) {
+            aomImage.planes[yuvPlane] = monoUVPlane;
+            aomImage.stride[yuvPlane] = monoUVRowBytes;
         }
     }
 
@@ -805,7 +826,9 @@
     if (addImageFlags & AVIF_ADD_IMAGE_FLAG_FORCE_KEYFRAME) {
         encodeFlags |= AOM_EFLAG_FORCE_KF;
     }
-    if (aom_codec_encode(&codec->internal->encoder, aomImage, 0, 1, encodeFlags) != AOM_CODEC_OK) {
+    aom_codec_err_t encodeErr = aom_codec_encode(&codec->internal->encoder, &aomImage, 0, 1, encodeFlags);
+    avifFree(monoUVPlane);
+    if (encodeErr != AOM_CODEC_OK) {
         avifDiagnosticsPrintf(codec->diag,
                               "aom_codec_encode() failed: %s: %s",
                               aom_codec_error(&codec->internal->encoder),
@@ -824,8 +847,6 @@
         }
     }
 
-    aom_img_free(aomImage);
-
     if (addImageFlags & AVIF_ADD_IMAGE_FLAG_SINGLE) {
         // Flush and clean up encoder resources early to save on overhead when encoding alpha or grid images