From 903bd943e323463e4bbd0768507f313194e3b5bf Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 10:54:31 +1100 Subject: [PATCH 1/7] Fixed indentation --- src/_avif.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/_avif.c b/src/_avif.c index d86ab340a42..a8bd4b3ef1b 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -606,10 +606,11 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) { // rgb.pixels is safe for writes memcpy(rgb.pixels, rgb_bytes, size); - Py_BEGIN_ALLOW_THREADS result = avifImageRGBToYUV(frame, &rgb); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS; + result = avifImageRGBToYUV(frame, &rgb); + Py_END_ALLOW_THREADS; - if (result != AVIF_RESULT_OK) { + if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), "Conversion to YUV failed: %s", @@ -624,11 +625,11 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) { addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE; } - Py_BEGIN_ALLOW_THREADS result = - avifEncoderAddImage(encoder, frame, duration, addImageFlags); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS; + result = avifEncoderAddImage(encoder, frame, duration, addImageFlags); + Py_END_ALLOW_THREADS; - if (result != AVIF_RESULT_OK) { + if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), "Failed to encode image: %s", @@ -660,10 +661,11 @@ _encoder_finish(AvifEncoderObject *self) { avifResult result; PyObject *ret = NULL; - Py_BEGIN_ALLOW_THREADS result = avifEncoderFinish(encoder, &raw); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS; + result = avifEncoderFinish(encoder, &raw); + Py_END_ALLOW_THREADS; - if (result != AVIF_RESULT_OK) { + if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), "Failed to finish encoding: %s", @@ -876,10 +878,11 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) { return NULL; } - Py_BEGIN_ALLOW_THREADS result = avifImageYUVToRGB(image, &rgb); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS; + result = avifImageYUVToRGB(image, &rgb); + Py_END_ALLOW_THREADS; - if (result != AVIF_RESULT_OK) { + if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), "Conversion from YUV failed: %s", From 9eac4698c69641e7a388554b25d607d27153cdbe Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 12:52:40 +1100 Subject: [PATCH 2/7] Removed avifEncOptions --- src/_avif.c | 293 ++++++++++++++++++++++------------------------------ 1 file changed, 124 insertions(+), 169 deletions(-) diff --git a/src/_avif.c b/src/_avif.c index a8bd4b3ef1b..e0a87e8c56f 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -3,20 +3,6 @@ #include #include "avif/avif.h" -typedef struct { - avifPixelFormat subsampling; - int qmin; - int qmax; - int quality; - int speed; - avifCodecChoice codec; - avifRange range; - avifBool alpha_premultiplied; - int tile_rows_log2; - int tile_cols_log2; - avifBool autotiling; -} avifEncOptions; - // Encoder type typedef struct { PyObject_HEAD avifEncoder *encoder; @@ -241,7 +227,6 @@ _add_codec_specific_options(avifEncoder *encoder, PyObject *opts) { PyObject * AvifEncoderNew(PyObject *self_, PyObject *args) { unsigned int width, height; - avifEncOptions enc_options; AvifEncoderObject *self = NULL; avifEncoder *encoder = NULL; @@ -291,201 +276,171 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { return NULL; } + // Create a new animation encoder and picture frame + avifImage *image = avifImageCreateEmpty(); + + // Set these in advance so any upcoming RGB -> YUV use the proper coefficients + if (strcmp(range, "full") == 0) { + image->yuvRange = AVIF_RANGE_FULL; + } else if (strcmp(range, "limited") == 0) { + image->yuvRange = AVIF_RANGE_LIMITED; + } else { + PyErr_SetString(PyExc_ValueError, "Invalid range"); + return NULL; + } if (strcmp(subsampling, "4:0:0") == 0) { - enc_options.subsampling = AVIF_PIXEL_FORMAT_YUV400; + image->yuvFormat = AVIF_PIXEL_FORMAT_YUV400; } else if (strcmp(subsampling, "4:2:0") == 0) { - enc_options.subsampling = AVIF_PIXEL_FORMAT_YUV420; + image->yuvFormat = AVIF_PIXEL_FORMAT_YUV420; } else if (strcmp(subsampling, "4:2:2") == 0) { - enc_options.subsampling = AVIF_PIXEL_FORMAT_YUV422; + image->yuvFormat = AVIF_PIXEL_FORMAT_YUV422; } else if (strcmp(subsampling, "4:4:4") == 0) { - enc_options.subsampling = AVIF_PIXEL_FORMAT_YUV444; + image->yuvFormat = AVIF_PIXEL_FORMAT_YUV444; } else { PyErr_Format(PyExc_ValueError, "Invalid subsampling: %s", subsampling); return NULL; } - if (qmin == -1 || qmax == -1) { -#if AVIF_VERSION >= 1000000 - enc_options.qmin = -1; - enc_options.qmax = -1; -#else - enc_options.qmin = normalize_quantize_value(64 - quality); - enc_options.qmax = normalize_quantize_value(100 - quality); -#endif - } else { - enc_options.qmin = normalize_quantize_value(qmin); - enc_options.qmax = normalize_quantize_value(qmax); - } - enc_options.quality = quality; - - if (speed < AVIF_SPEED_SLOWEST) { - speed = AVIF_SPEED_SLOWEST; - } else if (speed > AVIF_SPEED_FASTEST) { - speed = AVIF_SPEED_FASTEST; - } - enc_options.speed = speed; - - if (strcmp(codec, "auto") == 0) { - enc_options.codec = AVIF_CODEC_CHOICE_AUTO; - } else { - enc_options.codec = avifCodecChoiceFromName(codec); - } - - if (strcmp(range, "full") == 0) { - enc_options.range = AVIF_RANGE_FULL; - } else if (strcmp(range, "limited") == 0) { - enc_options.range = AVIF_RANGE_LIMITED; - } else { - PyErr_SetString(PyExc_ValueError, "Invalid range"); - return NULL; - } + image->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; + image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; + image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601; // Validate canvas dimensions if (width <= 0 || height <= 0) { PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions"); return NULL; } + image->width = width; + image->height = height; - enc_options.tile_rows_log2 = normalize_tiles_log2(tile_rows_log2); - enc_options.tile_cols_log2 = normalize_tiles_log2(tile_cols_log2); - enc_options.alpha_premultiplied = - (alpha_premultiplied == Py_True) ? AVIF_TRUE : AVIF_FALSE; - enc_options.autotiling = (autotiling == Py_True) ? AVIF_TRUE : AVIF_FALSE; - - // Create a new animation encoder and picture frame - self = PyObject_New(AvifEncoderObject, &AvifEncoder_Type); - if (self) { - self->icc_bytes = NULL; - self->exif_bytes = NULL; - self->xmp_bytes = NULL; + image->depth = 8; +#if AVIF_VERSION >= 90000 + image->alphaPremultiplied = alpha_premultiplied == Py_True ? AVIF_TRUE : AVIF_FALSE; +#endif - encoder = avifEncoderCreate(); + encoder = avifEncoderCreate(); - int is_aom_encode = strcmp(codec, "aom") == 0 || - (strcmp(codec, "auto") == 0 && - _codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE)); + int is_aom_encode = strcmp(codec, "aom") == 0 || + (strcmp(codec, "auto") == 0 && + _codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE)); + encoder->maxThreads = is_aom_encode && max_threads > 64 ? 64 : max_threads; - encoder->maxThreads = is_aom_encode && max_threads > 64 ? 64 : max_threads; + if (qmin == -1 || qmax == -1) { #if AVIF_VERSION >= 1000000 - if (enc_options.qmin != -1 && enc_options.qmax != -1) { - encoder->minQuantizer = enc_options.qmin; - encoder->maxQuantizer = enc_options.qmax; - } else { - encoder->quality = enc_options.quality; - } + encoder->quality = quality; #else - encoder->minQuantizer = enc_options.qmin; - encoder->maxQuantizer = enc_options.qmax; + encoder->minQuantizer = normalize_quantize_value(64 - quality); + encoder->maxQuantizer = normalize_quantize_value(100 - quality); #endif - encoder->codecChoice = enc_options.codec; - encoder->speed = enc_options.speed; - encoder->timescale = (uint64_t)1000; - encoder->tileRowsLog2 = enc_options.tile_rows_log2; - encoder->tileColsLog2 = enc_options.tile_cols_log2; + } else { + encoder->minQuantizer = normalize_quantize_value(qmin); + encoder->maxQuantizer = normalize_quantize_value(qmax); + } + + if (strcmp(codec, "auto") == 0) { + encoder->codecChoice = AVIF_CODEC_CHOICE_AUTO; + } else { + encoder->codecChoice = avifCodecChoiceFromName(codec); + } + if (speed < AVIF_SPEED_SLOWEST) { + speed = AVIF_SPEED_SLOWEST; + } else if (speed > AVIF_SPEED_FASTEST) { + speed = AVIF_SPEED_FASTEST; + } + encoder->speed = speed; + encoder->timescale = (uint64_t)1000; + encoder->tileRowsLog2 = normalize_tiles_log2(tile_rows_log2); + encoder->tileColsLog2 = normalize_tiles_log2(tile_cols_log2); #if AVIF_VERSION >= 110000 - encoder->autoTiling = enc_options.autotiling; + encoder->autoTiling = autotiling == Py_True ? AVIF_TRUE : AVIF_FALSE; #endif - if (advanced != Py_None) { + if (advanced != Py_None) { #if AVIF_VERSION >= 80200 - if (_add_codec_specific_options(encoder, advanced)) { - return NULL; - } -#else - PyErr_SetString( - PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2" - ); + if (_add_codec_specific_options(encoder, advanced)) { return NULL; -#endif } - - self->encoder = encoder; - - avifImage *image = avifImageCreateEmpty(); - // Set these in advance so any upcoming RGB -> YUV use the proper coefficients - image->yuvRange = enc_options.range; - image->yuvFormat = enc_options.subsampling; - image->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED; - image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED; - image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601; - image->width = width; - image->height = height; - image->depth = 8; -#if AVIF_VERSION >= 90000 - image->alphaPremultiplied = enc_options.alpha_premultiplied; +#else + PyErr_SetString( + PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2" + ); + return NULL; #endif + } - avifResult result; - if (PyBytes_GET_SIZE(icc_bytes)) { - self->icc_bytes = icc_bytes; - Py_INCREF(icc_bytes); + self = PyObject_New(AvifEncoderObject, &AvifEncoder_Type); + if (!self) { + PyErr_SetString(PyExc_RuntimeError, "could not create encoder object"); + return NULL; + } + self->frame_index = -1; + self->icc_bytes = NULL; + self->exif_bytes = NULL; + self->xmp_bytes = NULL; + self->image = image; + self->encoder = encoder; - result = avifImageSetProfileICC( - image, - (uint8_t *)PyBytes_AS_STRING(icc_bytes), - PyBytes_GET_SIZE(icc_bytes) + avifResult result; + if (PyBytes_GET_SIZE(icc_bytes)) { + self->icc_bytes = icc_bytes; + Py_INCREF(icc_bytes); + + result = avifImageSetProfileICC( + image, (uint8_t *)PyBytes_AS_STRING(icc_bytes), PyBytes_GET_SIZE(icc_bytes) + ); + if (result != AVIF_RESULT_OK) { + PyErr_Format( + exc_type_for_avif_result(result), + "Setting ICC profile failed: %s", + avifResultToString(result) ); - if (result != AVIF_RESULT_OK) { - PyErr_Format( - exc_type_for_avif_result(result), - "Setting ICC profile failed: %s", - avifResultToString(result) - ); - return NULL; - } - } else { - image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; - image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + return NULL; } + } else { + image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; + image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; + } - if (PyBytes_GET_SIZE(exif_bytes)) { - self->exif_bytes = exif_bytes; - Py_INCREF(exif_bytes); + if (PyBytes_GET_SIZE(exif_bytes)) { + self->exif_bytes = exif_bytes; + Py_INCREF(exif_bytes); - result = avifImageSetMetadataExif( - image, - (uint8_t *)PyBytes_AS_STRING(exif_bytes), - PyBytes_GET_SIZE(exif_bytes) + result = avifImageSetMetadataExif( + image, + (uint8_t *)PyBytes_AS_STRING(exif_bytes), + PyBytes_GET_SIZE(exif_bytes) + ); + if (result != AVIF_RESULT_OK) { + PyErr_Format( + exc_type_for_avif_result(result), + "Setting EXIF data failed: %s", + avifResultToString(result) ); - if (result != AVIF_RESULT_OK) { - PyErr_Format( - exc_type_for_avif_result(result), - "Setting EXIF data failed: %s", - avifResultToString(result) - ); - return NULL; - } + return NULL; } - if (PyBytes_GET_SIZE(xmp_bytes)) { - self->xmp_bytes = xmp_bytes; - Py_INCREF(xmp_bytes); - - result = avifImageSetMetadataXMP( - image, - (uint8_t *)PyBytes_AS_STRING(xmp_bytes), - PyBytes_GET_SIZE(xmp_bytes) + } + if (PyBytes_GET_SIZE(xmp_bytes)) { + self->xmp_bytes = xmp_bytes; + Py_INCREF(xmp_bytes); + + result = avifImageSetMetadataXMP( + image, (uint8_t *)PyBytes_AS_STRING(xmp_bytes), PyBytes_GET_SIZE(xmp_bytes) + ); + if (result != AVIF_RESULT_OK) { + PyErr_Format( + exc_type_for_avif_result(result), + "Setting XMP data failed: %s", + avifResultToString(result) ); - if (result != AVIF_RESULT_OK) { - PyErr_Format( - exc_type_for_avif_result(result), - "Setting XMP data failed: %s", - avifResultToString(result) - ); - return NULL; - } - } - if (exif_orientation > 1) { - exif_orientation_to_irot_imir(image, exif_orientation); + return NULL; } - - self->image = image; - self->frame_index = -1; - - return (PyObject *)self; } - PyErr_SetString(PyExc_RuntimeError, "could not create encoder object"); - return NULL; + if (exif_orientation > 1) { + exif_orientation_to_irot_imir(image, exif_orientation); + } + + return (PyObject *)self; } PyObject * From d40682303b81d16af66a847a29a1260e24759731 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 13:01:07 +1100 Subject: [PATCH 3/7] Destroy encoder on failure --- src/_avif.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/_avif.c b/src/_avif.c index e0a87e8c56f..847bb6afb12 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -359,12 +359,14 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { if (advanced != Py_None) { #if AVIF_VERSION >= 80200 if (_add_codec_specific_options(encoder, advanced)) { + avifEncoderDestroy(encoder); return NULL; } #else PyErr_SetString( PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2" ); + avifEncoderDestroy(encoder); return NULL; #endif } @@ -372,6 +374,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { self = PyObject_New(AvifEncoderObject, &AvifEncoder_Type); if (!self) { PyErr_SetString(PyExc_RuntimeError, "could not create encoder object"); + avifEncoderDestroy(encoder); return NULL; } self->frame_index = -1; @@ -379,7 +382,6 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { self->exif_bytes = NULL; self->xmp_bytes = NULL; self->image = image; - self->encoder = encoder; avifResult result; if (PyBytes_GET_SIZE(icc_bytes)) { @@ -395,6 +397,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting ICC profile failed: %s", avifResultToString(result) ); + avifEncoderDestroy(encoder); return NULL; } } else { @@ -417,6 +420,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting EXIF data failed: %s", avifResultToString(result) ); + avifEncoderDestroy(encoder); return NULL; } } @@ -433,6 +437,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting XMP data failed: %s", avifResultToString(result) ); + avifEncoderDestroy(encoder); return NULL; } } @@ -440,6 +445,8 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { exif_orientation_to_irot_imir(image, exif_orientation); } + self->encoder = encoder; + return (PyObject *)self; } From ea22f87529b96feda4fad0e6b8b726b49e03fd79 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 13:04:18 +1100 Subject: [PATCH 4/7] Destroy image on failure --- src/_avif.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/_avif.c b/src/_avif.c index 847bb6afb12..ebce7957a88 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -308,6 +308,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { // Validate canvas dimensions if (width <= 0 || height <= 0) { PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions"); + avifImageDestroy(image); return NULL; } image->width = width; @@ -359,6 +360,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { if (advanced != Py_None) { #if AVIF_VERSION >= 80200 if (_add_codec_specific_options(encoder, advanced)) { + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; } @@ -366,6 +368,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { PyErr_SetString( PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2" ); + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; #endif @@ -374,6 +377,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { self = PyObject_New(AvifEncoderObject, &AvifEncoder_Type); if (!self) { PyErr_SetString(PyExc_RuntimeError, "could not create encoder object"); + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; } @@ -397,6 +401,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting ICC profile failed: %s", avifResultToString(result) ); + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; } @@ -420,6 +425,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting EXIF data failed: %s", avifResultToString(result) ); + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; } @@ -437,6 +443,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { "Setting XMP data failed: %s", avifResultToString(result) ); + avifImageDestroy(image); avifEncoderDestroy(encoder); return NULL; } From 5f4d0b1efe3151249be0ca395cc408270efd3a1a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 13:40:45 +1100 Subject: [PATCH 5/7] Delete encoder object on failure --- src/_avif.c | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/_avif.c b/src/_avif.c index ebce7957a88..298f4e132bc 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -228,7 +228,7 @@ PyObject * AvifEncoderNew(PyObject *self_, PyObject *args) { unsigned int width, height; AvifEncoderObject *self = NULL; - avifEncoder *encoder = NULL; + avifEncoder *encoder; char *subsampling; int qmin; @@ -385,7 +385,6 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { self->icc_bytes = NULL; self->exif_bytes = NULL; self->xmp_bytes = NULL; - self->image = image; avifResult result; if (PyBytes_GET_SIZE(icc_bytes)) { @@ -403,6 +402,8 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { ); avifImageDestroy(image); avifEncoderDestroy(encoder); + Py_XDECREF(self->icc_bytes); + PyObject_Del(self); return NULL; } } else { @@ -427,6 +428,9 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { ); avifImageDestroy(image); avifEncoderDestroy(encoder); + Py_XDECREF(self->icc_bytes); + Py_XDECREF(self->exif_bytes); + PyObject_Del(self); return NULL; } } @@ -445,6 +449,10 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { ); avifImageDestroy(image); avifEncoderDestroy(encoder); + Py_XDECREF(self->icc_bytes); + Py_XDECREF(self->exif_bytes); + Py_XDECREF(self->xmp_bytes); + PyObject_Del(self); return NULL; } } @@ -452,6 +460,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { exif_orientation_to_irot_imir(image, exif_orientation); } + self->image = image; self->encoder = encoder; return (PyObject *)self; @@ -656,6 +665,7 @@ PyObject * AvifDecoderNew(PyObject *self_, PyObject *args) { PyObject *avif_bytes; AvifDecoderObject *self = NULL; + avifDecoder *decoder; char *codec_str; avifCodecChoice codec; @@ -678,29 +688,26 @@ AvifDecoderNew(PyObject *self_, PyObject *args) { PyErr_SetString(PyExc_RuntimeError, "could not create decoder object"); return NULL; } - self->decoder = NULL; Py_INCREF(avif_bytes); self->data = avif_bytes; - self->decoder = avifDecoderCreate(); + decoder = avifDecoderCreate(); #if AVIF_VERSION >= 80400 - self->decoder->maxThreads = max_threads; + decoder->maxThreads = max_threads; #endif #if AVIF_VERSION >= 90200 // Turn off libavif's 'clap' (clean aperture) property validation. - self->decoder->strictFlags &= ~AVIF_STRICT_CLAP_VALID; + decoder->strictFlags &= ~AVIF_STRICT_CLAP_VALID; // Allow the PixelInformationProperty ('pixi') to be missing in AV1 image // items. libheif v1.11.0 and older does not add the 'pixi' item property to // AV1 image items. - self->decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED; + decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED; #endif - self->decoder->codecChoice = codec; + decoder->codecChoice = codec; result = avifDecoderSetIOMemory( - self->decoder, - (uint8_t *)PyBytes_AS_STRING(self->data), - PyBytes_GET_SIZE(self->data) + decoder, (uint8_t *)PyBytes_AS_STRING(self->data), PyBytes_GET_SIZE(self->data) ); if (result != AVIF_RESULT_OK) { PyErr_Format( @@ -708,31 +715,31 @@ AvifDecoderNew(PyObject *self_, PyObject *args) { "Setting IO memory failed: %s", avifResultToString(result) ); - avifDecoderDestroy(self->decoder); - self->decoder = NULL; - Py_DECREF(self); + avifDecoderDestroy(decoder); + PyObject_Del(self); return NULL; } - result = avifDecoderParse(self->decoder); + result = avifDecoderParse(decoder); if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), "Failed to decode image: %s", avifResultToString(result) ); - avifDecoderDestroy(self->decoder); - self->decoder = NULL; - Py_DECREF(self); + avifDecoderDestroy(decoder); + PyObject_Del(self); return NULL; } - if (self->decoder->alphaPresent) { + if (decoder->alphaPresent) { self->mode = "RGBA"; } else { self->mode = "RGB"; } + self->decoder = decoder; + return (PyObject *)self; } From 0b9a90af049aee1ea116dd0f18af138be59a206f Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 27 Dec 2024 13:45:55 +1100 Subject: [PATCH 6/7] Corrected comment --- src/_avif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_avif.c b/src/_avif.c index 298f4e132bc..e1509a16134 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -897,7 +897,7 @@ static struct PyMethodDef _encoder_methods[] = { {NULL, NULL} /* sentinel */ }; -// AvifDecoder type definition +// AvifEncoder type definition static PyTypeObject AvifEncoder_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "AvifEncoder", .tp_basicsize = sizeof(AvifEncoderObject), From a6ab8e9a9c77f4c202571f97e97f8b5e9d7ec4f9 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Fri, 3 Jan 2025 00:14:37 +1100 Subject: [PATCH 7/7] Allow libavif to install rav1e on manylinux2014 --- .github/workflows/wheels-dependencies.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels-dependencies.sh b/.github/workflows/wheels-dependencies.sh index 3310902bec5..eb09e30d5f6 100755 --- a/.github/workflows/wheels-dependencies.sh +++ b/.github/workflows/wheels-dependencies.sh @@ -106,8 +106,7 @@ function build_harfbuzz { function build_libavif { if [ -e libavif-stamp ]; then return; fi - if [[ "$MB_ML_VER" == 2014 ]] || [[ "$PLAT" == "aarch64" ]]; then - # Once Amazon 2 is EOL on 30 June 2025, manylinux2014 will no longer be needed + if [[ "$PLAT" == "aarch64" ]]; then # Once GitHub Actions supports aarch64 without emulation, this will no longer needed as building will be faster if [[ "$PLAT" == "aarch64" ]]; then suffix="aarch64" @@ -137,6 +136,9 @@ EOF if [ -z "$IS_ALPINE" ] && [ -z "$IS_MACOS" ]; then yum install -y perl + if [[ "$MB_ML_VER" == 2014 ]]; then + yum install -y perl-IPC-Cmd + fi fi rav1e=LOCAL