mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-05-12 20:03:42 +03:00
Removed avifEncOptions (#14)
* Fixed indentation * Removed avifEncOptions * Destroy encoder on failure * Destroy image on failure * Delete encoder object on failure * Corrected comment * Allow libavif to install rav1e on manylinux2014 --------- Co-authored-by: Andrew Murray <radarhere@users.noreply.github.com>
This commit is contained in:
parent
3a9a3ab9cc
commit
93289324c6
6
.github/workflows/wheels-dependencies.sh
vendored
6
.github/workflows/wheels-dependencies.sh
vendored
|
@ -106,8 +106,7 @@ function build_harfbuzz {
|
||||||
function build_libavif {
|
function build_libavif {
|
||||||
if [ -e libavif-stamp ]; then return; fi
|
if [ -e libavif-stamp ]; then return; fi
|
||||||
|
|
||||||
if [[ "$MB_ML_VER" == 2014 ]] || [[ "$PLAT" == "aarch64" ]]; then
|
if [[ "$PLAT" == "aarch64" ]]; then
|
||||||
# Once Amazon 2 is EOL on 30 June 2025, manylinux2014 will no longer be needed
|
|
||||||
# Once GitHub Actions supports aarch64 without emulation, this will no longer needed as building will be faster
|
# Once GitHub Actions supports aarch64 without emulation, this will no longer needed as building will be faster
|
||||||
if [[ "$PLAT" == "aarch64" ]]; then
|
if [[ "$PLAT" == "aarch64" ]]; then
|
||||||
suffix="aarch64"
|
suffix="aarch64"
|
||||||
|
@ -137,6 +136,9 @@ EOF
|
||||||
|
|
||||||
if [ -z "$IS_ALPINE" ] && [ -z "$IS_MACOS" ]; then
|
if [ -z "$IS_ALPINE" ] && [ -z "$IS_MACOS" ]; then
|
||||||
yum install -y perl
|
yum install -y perl
|
||||||
|
if [[ "$MB_ML_VER" == 2014 ]]; then
|
||||||
|
yum install -y perl-IPC-Cmd
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rav1e=LOCAL
|
rav1e=LOCAL
|
||||||
|
|
245
src/_avif.c
245
src/_avif.c
|
@ -3,20 +3,6 @@
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include "avif/avif.h"
|
#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
|
// Encoder type
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD avifEncoder *encoder;
|
PyObject_HEAD avifEncoder *encoder;
|
||||||
|
@ -241,9 +227,8 @@ _add_codec_specific_options(avifEncoder *encoder, PyObject *opts) {
|
||||||
PyObject *
|
PyObject *
|
||||||
AvifEncoderNew(PyObject *self_, PyObject *args) {
|
AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
unsigned int width, height;
|
unsigned int width, height;
|
||||||
avifEncOptions enc_options;
|
|
||||||
AvifEncoderObject *self = NULL;
|
AvifEncoderObject *self = NULL;
|
||||||
avifEncoder *encoder = NULL;
|
avifEncoder *encoder;
|
||||||
|
|
||||||
char *subsampling;
|
char *subsampling;
|
||||||
int qmin;
|
int qmin;
|
||||||
|
@ -291,130 +276,115 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
return NULL;
|
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) {
|
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) {
|
} 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) {
|
} 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) {
|
} else if (strcmp(subsampling, "4:4:4") == 0) {
|
||||||
enc_options.subsampling = AVIF_PIXEL_FORMAT_YUV444;
|
image->yuvFormat = AVIF_PIXEL_FORMAT_YUV444;
|
||||||
} else {
|
} else {
|
||||||
PyErr_Format(PyExc_ValueError, "Invalid subsampling: %s", subsampling);
|
PyErr_Format(PyExc_ValueError, "Invalid subsampling: %s", subsampling);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qmin == -1 || qmax == -1) {
|
image->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
|
||||||
#if AVIF_VERSION >= 1000000
|
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
|
||||||
enc_options.qmin = -1;
|
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate canvas dimensions
|
// Validate canvas dimensions
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions");
|
PyErr_SetString(PyExc_ValueError, "invalid canvas dimensions");
|
||||||
|
avifImageDestroy(image);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
image->width = width;
|
||||||
|
image->height = height;
|
||||||
|
|
||||||
enc_options.tile_rows_log2 = normalize_tiles_log2(tile_rows_log2);
|
image->depth = 8;
|
||||||
enc_options.tile_cols_log2 = normalize_tiles_log2(tile_cols_log2);
|
#if AVIF_VERSION >= 90000
|
||||||
enc_options.alpha_premultiplied =
|
image->alphaPremultiplied = alpha_premultiplied == Py_True ? AVIF_TRUE : AVIF_FALSE;
|
||||||
(alpha_premultiplied == Py_True) ? AVIF_TRUE : AVIF_FALSE;
|
#endif
|
||||||
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;
|
|
||||||
|
|
||||||
encoder = avifEncoderCreate();
|
encoder = avifEncoderCreate();
|
||||||
|
|
||||||
int is_aom_encode = strcmp(codec, "aom") == 0 ||
|
int is_aom_encode = strcmp(codec, "aom") == 0 ||
|
||||||
(strcmp(codec, "auto") == 0 &&
|
(strcmp(codec, "auto") == 0 &&
|
||||||
_codec_available("aom", AVIF_CODEC_FLAG_CAN_ENCODE));
|
_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 AVIF_VERSION >= 1000000
|
||||||
if (enc_options.qmin != -1 && enc_options.qmax != -1) {
|
encoder->quality = quality;
|
||||||
encoder->minQuantizer = enc_options.qmin;
|
|
||||||
encoder->maxQuantizer = enc_options.qmax;
|
|
||||||
} else {
|
|
||||||
encoder->quality = enc_options.quality;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
encoder->minQuantizer = enc_options.qmin;
|
encoder->minQuantizer = normalize_quantize_value(64 - quality);
|
||||||
encoder->maxQuantizer = enc_options.qmax;
|
encoder->maxQuantizer = normalize_quantize_value(100 - quality);
|
||||||
#endif
|
#endif
|
||||||
encoder->codecChoice = enc_options.codec;
|
} else {
|
||||||
encoder->speed = enc_options.speed;
|
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->timescale = (uint64_t)1000;
|
||||||
encoder->tileRowsLog2 = enc_options.tile_rows_log2;
|
encoder->tileRowsLog2 = normalize_tiles_log2(tile_rows_log2);
|
||||||
encoder->tileColsLog2 = enc_options.tile_cols_log2;
|
encoder->tileColsLog2 = normalize_tiles_log2(tile_cols_log2);
|
||||||
|
|
||||||
#if AVIF_VERSION >= 110000
|
#if AVIF_VERSION >= 110000
|
||||||
encoder->autoTiling = enc_options.autotiling;
|
encoder->autoTiling = autotiling == Py_True ? AVIF_TRUE : AVIF_FALSE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (advanced != Py_None) {
|
if (advanced != Py_None) {
|
||||||
#if AVIF_VERSION >= 80200
|
#if AVIF_VERSION >= 80200
|
||||||
if (_add_codec_specific_options(encoder, advanced)) {
|
if (_add_codec_specific_options(encoder, advanced)) {
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2"
|
PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2"
|
||||||
);
|
);
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
self->encoder = encoder;
|
self = PyObject_New(AvifEncoderObject, &AvifEncoder_Type);
|
||||||
|
if (!self) {
|
||||||
avifImage *image = avifImageCreateEmpty();
|
PyErr_SetString(PyExc_RuntimeError, "could not create encoder object");
|
||||||
// Set these in advance so any upcoming RGB -> YUV use the proper coefficients
|
avifImageDestroy(image);
|
||||||
image->yuvRange = enc_options.range;
|
avifEncoderDestroy(encoder);
|
||||||
image->yuvFormat = enc_options.subsampling;
|
return NULL;
|
||||||
image->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
|
}
|
||||||
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
|
self->frame_index = -1;
|
||||||
image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
|
self->icc_bytes = NULL;
|
||||||
image->width = width;
|
self->exif_bytes = NULL;
|
||||||
image->height = height;
|
self->xmp_bytes = NULL;
|
||||||
image->depth = 8;
|
|
||||||
#if AVIF_VERSION >= 90000
|
|
||||||
image->alphaPremultiplied = enc_options.alpha_premultiplied;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
avifResult result;
|
avifResult result;
|
||||||
if (PyBytes_GET_SIZE(icc_bytes)) {
|
if (PyBytes_GET_SIZE(icc_bytes)) {
|
||||||
|
@ -422,9 +392,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
Py_INCREF(icc_bytes);
|
Py_INCREF(icc_bytes);
|
||||||
|
|
||||||
result = avifImageSetProfileICC(
|
result = avifImageSetProfileICC(
|
||||||
image,
|
image, (uint8_t *)PyBytes_AS_STRING(icc_bytes), PyBytes_GET_SIZE(icc_bytes)
|
||||||
(uint8_t *)PyBytes_AS_STRING(icc_bytes),
|
|
||||||
PyBytes_GET_SIZE(icc_bytes)
|
|
||||||
);
|
);
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -432,6 +400,10 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
"Setting ICC profile failed: %s",
|
"Setting ICC profile failed: %s",
|
||||||
avifResultToString(result)
|
avifResultToString(result)
|
||||||
);
|
);
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
|
Py_XDECREF(self->icc_bytes);
|
||||||
|
PyObject_Del(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -454,6 +426,11 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
"Setting EXIF data failed: %s",
|
"Setting EXIF data failed: %s",
|
||||||
avifResultToString(result)
|
avifResultToString(result)
|
||||||
);
|
);
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
|
Py_XDECREF(self->icc_bytes);
|
||||||
|
Py_XDECREF(self->exif_bytes);
|
||||||
|
PyObject_Del(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,9 +439,7 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
Py_INCREF(xmp_bytes);
|
Py_INCREF(xmp_bytes);
|
||||||
|
|
||||||
result = avifImageSetMetadataXMP(
|
result = avifImageSetMetadataXMP(
|
||||||
image,
|
image, (uint8_t *)PyBytes_AS_STRING(xmp_bytes), PyBytes_GET_SIZE(xmp_bytes)
|
||||||
(uint8_t *)PyBytes_AS_STRING(xmp_bytes),
|
|
||||||
PyBytes_GET_SIZE(xmp_bytes)
|
|
||||||
);
|
);
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -472,6 +447,12 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
"Setting XMP data failed: %s",
|
"Setting XMP data failed: %s",
|
||||||
avifResultToString(result)
|
avifResultToString(result)
|
||||||
);
|
);
|
||||||
|
avifImageDestroy(image);
|
||||||
|
avifEncoderDestroy(encoder);
|
||||||
|
Py_XDECREF(self->icc_bytes);
|
||||||
|
Py_XDECREF(self->exif_bytes);
|
||||||
|
Py_XDECREF(self->xmp_bytes);
|
||||||
|
PyObject_Del(self);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,12 +461,9 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
self->image = image;
|
self->image = image;
|
||||||
self->frame_index = -1;
|
self->encoder = encoder;
|
||||||
|
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
|
||||||
PyErr_SetString(PyExc_RuntimeError, "could not create encoder object");
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
|
@ -606,8 +584,9 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
|
||||||
// rgb.pixels is safe for writes
|
// rgb.pixels is safe for writes
|
||||||
memcpy(rgb.pixels, rgb_bytes, size);
|
memcpy(rgb.pixels, rgb_bytes, size);
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS result = avifImageRGBToYUV(frame, &rgb);
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
Py_END_ALLOW_THREADS
|
result = avifImageRGBToYUV(frame, &rgb);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -624,9 +603,9 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
|
||||||
addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE;
|
addImageFlags |= AVIF_ADD_IMAGE_FLAG_SINGLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS result =
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
avifEncoderAddImage(encoder, frame, duration, addImageFlags);
|
result = avifEncoderAddImage(encoder, frame, duration, addImageFlags);
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -660,8 +639,9 @@ _encoder_finish(AvifEncoderObject *self) {
|
||||||
avifResult result;
|
avifResult result;
|
||||||
PyObject *ret = NULL;
|
PyObject *ret = NULL;
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS result = avifEncoderFinish(encoder, &raw);
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
Py_END_ALLOW_THREADS
|
result = avifEncoderFinish(encoder, &raw);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -685,6 +665,7 @@ PyObject *
|
||||||
AvifDecoderNew(PyObject *self_, PyObject *args) {
|
AvifDecoderNew(PyObject *self_, PyObject *args) {
|
||||||
PyObject *avif_bytes;
|
PyObject *avif_bytes;
|
||||||
AvifDecoderObject *self = NULL;
|
AvifDecoderObject *self = NULL;
|
||||||
|
avifDecoder *decoder;
|
||||||
|
|
||||||
char *codec_str;
|
char *codec_str;
|
||||||
avifCodecChoice codec;
|
avifCodecChoice codec;
|
||||||
|
@ -707,29 +688,26 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
|
||||||
PyErr_SetString(PyExc_RuntimeError, "could not create decoder object");
|
PyErr_SetString(PyExc_RuntimeError, "could not create decoder object");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
self->decoder = NULL;
|
|
||||||
|
|
||||||
Py_INCREF(avif_bytes);
|
Py_INCREF(avif_bytes);
|
||||||
self->data = avif_bytes;
|
self->data = avif_bytes;
|
||||||
|
|
||||||
self->decoder = avifDecoderCreate();
|
decoder = avifDecoderCreate();
|
||||||
#if AVIF_VERSION >= 80400
|
#if AVIF_VERSION >= 80400
|
||||||
self->decoder->maxThreads = max_threads;
|
decoder->maxThreads = max_threads;
|
||||||
#endif
|
#endif
|
||||||
#if AVIF_VERSION >= 90200
|
#if AVIF_VERSION >= 90200
|
||||||
// Turn off libavif's 'clap' (clean aperture) property validation.
|
// 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
|
// 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
|
// items. libheif v1.11.0 and older does not add the 'pixi' item property to
|
||||||
// AV1 image items.
|
// AV1 image items.
|
||||||
self->decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED;
|
decoder->strictFlags &= ~AVIF_STRICT_PIXI_REQUIRED;
|
||||||
#endif
|
#endif
|
||||||
self->decoder->codecChoice = codec;
|
decoder->codecChoice = codec;
|
||||||
|
|
||||||
result = avifDecoderSetIOMemory(
|
result = avifDecoderSetIOMemory(
|
||||||
self->decoder,
|
decoder, (uint8_t *)PyBytes_AS_STRING(self->data), PyBytes_GET_SIZE(self->data)
|
||||||
(uint8_t *)PyBytes_AS_STRING(self->data),
|
|
||||||
PyBytes_GET_SIZE(self->data)
|
|
||||||
);
|
);
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -737,31 +715,31 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
|
||||||
"Setting IO memory failed: %s",
|
"Setting IO memory failed: %s",
|
||||||
avifResultToString(result)
|
avifResultToString(result)
|
||||||
);
|
);
|
||||||
avifDecoderDestroy(self->decoder);
|
avifDecoderDestroy(decoder);
|
||||||
self->decoder = NULL;
|
PyObject_Del(self);
|
||||||
Py_DECREF(self);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = avifDecoderParse(self->decoder);
|
result = avifDecoderParse(decoder);
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
exc_type_for_avif_result(result),
|
exc_type_for_avif_result(result),
|
||||||
"Failed to decode image: %s",
|
"Failed to decode image: %s",
|
||||||
avifResultToString(result)
|
avifResultToString(result)
|
||||||
);
|
);
|
||||||
avifDecoderDestroy(self->decoder);
|
avifDecoderDestroy(decoder);
|
||||||
self->decoder = NULL;
|
PyObject_Del(self);
|
||||||
Py_DECREF(self);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->decoder->alphaPresent) {
|
if (decoder->alphaPresent) {
|
||||||
self->mode = "RGBA";
|
self->mode = "RGBA";
|
||||||
} else {
|
} else {
|
||||||
self->mode = "RGB";
|
self->mode = "RGB";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->decoder = decoder;
|
||||||
|
|
||||||
return (PyObject *)self;
|
return (PyObject *)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,8 +854,9 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS result = avifImageYUVToRGB(image, &rgb);
|
Py_BEGIN_ALLOW_THREADS;
|
||||||
Py_END_ALLOW_THREADS
|
result = avifImageYUVToRGB(image, &rgb);
|
||||||
|
Py_END_ALLOW_THREADS;
|
||||||
|
|
||||||
if (result != AVIF_RESULT_OK) {
|
if (result != AVIF_RESULT_OK) {
|
||||||
PyErr_Format(
|
PyErr_Format(
|
||||||
|
@ -918,7 +897,7 @@ static struct PyMethodDef _encoder_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
// AvifDecoder type definition
|
// AvifEncoder type definition
|
||||||
static PyTypeObject AvifEncoder_Type = {
|
static PyTypeObject AvifEncoder_Type = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "AvifEncoder",
|
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "AvifEncoder",
|
||||||
.tp_basicsize = sizeof(AvifEncoderObject),
|
.tp_basicsize = sizeof(AvifEncoderObject),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user