From b10d2697e9ed2fb09cb722335ff4342c353612b8 Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Mon, 12 Feb 2024 10:29:02 +0000 Subject: [PATCH] Encode alpha as 4:2:0 with SVT (#2004) --- src/codec_svt.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/codec_svt.c b/src/codec_svt.c index 58a92cdce..ea9efc2b5 100644 --- a/src/codec_svt.c +++ b/src/codec_svt.c @@ -7,6 +7,7 @@ #include "svt-av1/EbSvtAv1Enc.h" +#include #include // The SVT_AV1_VERSION_MAJOR, SVT_AV1_VERSION_MINOR, SVT_AV1_VERSION_PATCHLEVEL, and @@ -76,6 +77,7 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, avifResult result = AVIF_RESULT_UNKNOWN_ERROR; EbColorFormat color_format = EB_YUV420; + uint8_t * uvPlanes = NULL; // 4:2:0 U and V placeholder for alpha because SVT-AV1 does not support 4:0:0. EbBufferHeaderType * input_buffer = NULL; EbErrorType res = EB_ErrorNone; @@ -98,6 +100,7 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, y_shift = 1; break; case AVIF_PIXEL_FORMAT_YUV400: + // Setting color_format = EB_YUV400; results in "Svt[error]: Instance 1: Only support 420 now". case AVIF_PIXEL_FORMAT_NONE: case AVIF_PIXEL_FORMAT_COUNT: default: @@ -198,16 +201,38 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, } EbSvtIOFormat * input_picture_buffer = (EbSvtIOFormat *)input_buffer->p_buffer; - int bytesPerPixel = image->depth > 8 ? 2 : 1; + const uint32_t bytesPerPixel = image->depth > 8 ? 2 : 1; + const uint32_t uvHeight = (image->height + y_shift) >> y_shift; if (alpha) { input_picture_buffer->y_stride = image->alphaRowBytes / bytesPerPixel; input_picture_buffer->luma = image->alphaPlane; input_buffer->n_filled_len = image->alphaRowBytes * image->height; + +#if SVT_AV1_CHECK_VERSION(1, 8, 0) + // Simulate 4:2:0 UV planes. SVT-AV1 does not support 4:0:0 samples. + const uint32_t uvWidth = (image->width + y_shift) >> y_shift; + const uint32_t uvRowBytes = uvWidth * bytesPerPixel; + const uint32_t uvSize = uvRowBytes * uvHeight; + uvPlanes = avifAlloc(uvSize); + if (uvPlanes == NULL) { + goto cleanup; + } + memset(uvPlanes, 0, uvSize); + input_picture_buffer->cb = uvPlanes; + input_buffer->n_filled_len += uvSize; + input_picture_buffer->cr = uvPlanes; + input_buffer->n_filled_len += uvSize; + input_picture_buffer->cb_stride = uvWidth; + input_picture_buffer->cr_stride = uvWidth; +#else + // This workaround was not needed before SVT-AV1 1.8.0. + // See https://github.com/AOMediaCodec/libavif/issues/1992. + (void)uvPlanes; +#endif } else { input_picture_buffer->y_stride = image->yuvRowBytes[0] / bytesPerPixel; input_picture_buffer->luma = image->yuvPlanes[0]; input_buffer->n_filled_len = image->yuvRowBytes[0] * image->height; - uint32_t uvHeight = (image->height + y_shift) >> y_shift; input_picture_buffer->cb = image->yuvPlanes[1]; input_buffer->n_filled_len += image->yuvRowBytes[1] * uvHeight; input_picture_buffer->cr = image->yuvPlanes[2]; @@ -232,6 +257,9 @@ static avifResult svtCodecEncodeImage(avifCodec * codec, result = dequeue_frame(codec, output, AVIF_FALSE); cleanup: + if (uvPlanes) { + avifFree(uvPlanes); + } if (input_buffer) { if (input_buffer->p_buffer) { avifFree(input_buffer->p_buffer);