avifImageSplitGrid need not allocate cell planes avifImageSplitGrid() does not need to call avifImageAllocatePlanes() on the cell images. It can just point the cell images' planes to the pixel data of gridSplitImage. This issue was reported by Nicholas Hayes (0xC0000054) in https://github.com/AOMediaCodec/libavif/issues/331. Fix a bug in aomCodecEncodeImage() when copying pixel data from avifImage to aom_image_t. The number of bytes per row should be the width times bytesPerPixel, not image->yuvRowBytes[yuvPlane].
diff --git a/apps/avifenc.c b/apps/avifenc.c index f2a675c..7efa1b9 100644 --- a/apps/avifenc.c +++ b/apps/avifenc.c
@@ -303,21 +303,14 @@ avifImageCopy(cellImage, gridSplitImage, 0); cellImage->width = cellWidth; cellImage->height = cellHeight; - avifImageAllocatePlanes(cellImage, AVIF_PLANES_YUV); const uint32_t bytesPerPixel = avifImageUsesU16(cellImage) ? 2 : 1; const uint32_t bytesPerRowY = bytesPerPixel * cellWidth; const uint32_t srcRowBytesY = gridSplitImage->yuvRowBytes[AVIF_CHAN_Y]; - const uint8_t * srcPlaneY = + cellImage->yuvPlanes[AVIF_CHAN_Y] = &gridSplitImage->yuvPlanes[AVIF_CHAN_Y][(gridX * bytesPerRowY) + (gridY * cellHeight) * srcRowBytesY]; - const uint32_t dstRowBytesY = cellImage->yuvRowBytes[AVIF_CHAN_Y]; - uint8_t * dstPlaneY = cellImage->yuvPlanes[AVIF_CHAN_Y]; - for (uint32_t row = 0; row < cellHeight; ++row) { - const uint8_t * srcRow = &srcPlaneY[row * srcRowBytesY]; - uint8_t * dstRow = &dstPlaneY[row * dstRowBytesY]; - memcpy(dstRow, srcRow, bytesPerRowY); - } + cellImage->yuvRowBytes[AVIF_CHAN_Y] = srcRowBytesY; if (gridSplitImage->yuvFormat != AVIF_PIXEL_FORMAT_YUV400) { avifPixelFormatInfo info; @@ -328,41 +321,21 @@ const uint32_t bytesPerRowUV = bytesPerPixel * uvWidth; const uint32_t srcRowBytesU = gridSplitImage->yuvRowBytes[AVIF_CHAN_U]; - const uint8_t * srcPlaneU = + cellImage->yuvPlanes[AVIF_CHAN_U] = &gridSplitImage->yuvPlanes[AVIF_CHAN_U][(gridX * bytesPerRowUV) + (gridY * uvHeight) * srcRowBytesU]; - const uint32_t dstRowBytesU = cellImage->yuvRowBytes[AVIF_CHAN_U]; - uint8_t * dstPlaneU = cellImage->yuvPlanes[AVIF_CHAN_U]; - for (uint32_t row = 0; row < uvHeight; ++row) { - const uint8_t * srcRow = &srcPlaneU[row * srcRowBytesU]; - uint8_t * dstRow = &dstPlaneU[row * dstRowBytesU]; - memcpy(dstRow, srcRow, bytesPerRowUV); - } + cellImage->yuvRowBytes[AVIF_CHAN_U] = srcRowBytesU; const uint32_t srcRowBytesV = gridSplitImage->yuvRowBytes[AVIF_CHAN_V]; - const uint8_t * srcPlaneV = + cellImage->yuvPlanes[AVIF_CHAN_V] = &gridSplitImage->yuvPlanes[AVIF_CHAN_V][(gridX * bytesPerRowUV) + (gridY * uvHeight) * srcRowBytesV]; - const uint32_t dstRowBytesV = cellImage->yuvRowBytes[AVIF_CHAN_V]; - uint8_t * dstPlaneV = cellImage->yuvPlanes[AVIF_CHAN_V]; - for (uint32_t row = 0; row < uvHeight; ++row) { - const uint8_t * srcRow = &srcPlaneV[row * srcRowBytesV]; - uint8_t * dstRow = &dstPlaneV[row * dstRowBytesV]; - memcpy(dstRow, srcRow, bytesPerRowUV); - } + cellImage->yuvRowBytes[AVIF_CHAN_V] = srcRowBytesV; } if (gridSplitImage->alphaPlane) { - avifImageAllocatePlanes(cellImage, AVIF_PLANES_A); - const uint32_t bytesPerRowA = bytesPerPixel * cellWidth; const uint32_t srcRowBytesA = gridSplitImage->alphaRowBytes; - const uint8_t * srcPlaneA = &gridSplitImage->alphaPlane[(gridX * bytesPerRowA) + (gridY * cellHeight) * srcRowBytesA]; - const uint32_t dstRowBytesA = cellImage->alphaRowBytes; - uint8_t * dstPlaneA = cellImage->alphaPlane; - for (uint32_t row = 0; row < cellHeight; ++row) { - const uint8_t * srcRow = &srcPlaneA[row * srcRowBytesA]; - uint8_t * dstRow = &dstPlaneA[row * dstRowBytesA]; - memcpy(dstRow, srcRow, bytesPerRowA); - } + cellImage->alphaPlane = &gridSplitImage->alphaPlane[(gridX * bytesPerRowA) + (gridY * cellHeight) * srcRowBytesA]; + cellImage->alphaRowBytes = srcRowBytesA; } } }
diff --git a/src/codec_aom.c b/src/codec_aom.c index c2a3eb2..6655e4d 100644 --- a/src/codec_aom.c +++ b/src/codec_aom.c
@@ -570,13 +570,18 @@ 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, image->yuvRowBytes[yuvPlane]); + memcpy(dstRow, srcRow, bytesPerRow); } }