Commit 871526f0 for libheif
commit 871526f0cfd6800dd065419c814b9536178b912d
Author: DarthSim <darthsim@gmail.com>
Date: Tue Mar 17 01:58:59 2026 +0300
AOM/Kvazaar/Rav1e/SVT/uvg266/vvenc: fix memory leak when encoder is reused for alpha encoding
diff --git a/libheif/plugins/encoder_aom.cc b/libheif/plugins/encoder_aom.cc
index 0cb18746..0dfe8f7e 100644
--- a/libheif/plugins/encoder_aom.cc
+++ b/libheif/plugins/encoder_aom.cc
@@ -912,6 +912,10 @@ static heif_error aom_start_sequence_encoding_intern(void* encoder_raw, const he
{
encoder_struct_aom* encoder = (encoder_struct_aom*) encoder_raw;
+ // destroy the codec in case it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ aom_codec_destroy(&encoder->codec);
+
heif_error err;
const int source_width = heif_image_get_width(image, heif_channel_Y);
diff --git a/libheif/plugins/encoder_kvazaar.cc b/libheif/plugins/encoder_kvazaar.cc
index 9248f296..e79d20eb 100644
--- a/libheif/plugins/encoder_kvazaar.cc
+++ b/libheif/plugins/encoder_kvazaar.cc
@@ -463,6 +463,19 @@ static heif_error kvazaar_start_sequence_encoding_intern(void* encoder_raw, cons
{
encoder_struct_kvazaar* encoder = (encoder_struct_kvazaar*) encoder_raw;
+ // close the encoder if it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ if (encoder->api) {
+ if (encoder->kvzencoder) {
+ encoder->api->encoder_close(encoder->kvzencoder);
+ encoder->kvzencoder = nullptr;
+ }
+ if (encoder->config) {
+ encoder->api->config_destroy(encoder->config);
+ encoder->config = nullptr;
+ }
+ }
+
int bit_depth = heif_image_get_bits_per_pixel_range(image, heif_channel_Y);
// Kvazaar uses a hard-coded bit depth (https://github.com/ultravideo/kvazaar/issues/399).
diff --git a/libheif/plugins/encoder_rav1e.cc b/libheif/plugins/encoder_rav1e.cc
index 641618b7..c2850dfd 100644
--- a/libheif/plugins/encoder_rav1e.cc
+++ b/libheif/plugins/encoder_rav1e.cc
@@ -509,6 +509,13 @@ heif_error rav1e_start_sequence_encoding_intern(void* encoder_raw, const heif_im
{
auto* encoder = (encoder_struct_rav1e*) encoder_raw;
+ // unref the context if it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ if (encoder->rav1eContextRaw) {
+ rav1e_context_unref(encoder->rav1eContextRaw);
+ encoder->rav1eContextRaw = nullptr;
+ }
+
const heif_chroma chroma = heif_image_get_chroma_format(image);
RaChromaSampling chromaSampling;
diff --git a/libheif/plugins/encoder_svt.cc b/libheif/plugins/encoder_svt.cc
index cc4c1140..b794c8c7 100644
--- a/libheif/plugins/encoder_svt.cc
+++ b/libheif/plugins/encoder_svt.cc
@@ -706,6 +706,14 @@ static heif_error svt_start_sequence_encoding_intern(void* encoder_raw, const he
EbErrorType res = EB_ErrorNone;
heif_error err;
+ // deinit the encoder if it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ if (encoder->svt_encoder) {
+ svt_av1_enc_deinit(encoder->svt_encoder);
+ svt_av1_enc_deinit_handle(encoder->svt_encoder);
+ encoder->svt_encoder = nullptr;
+ }
+
// encoder->compressed_data.clear();
int w = heif_image_get_width(image, heif_channel_Y);
diff --git a/libheif/plugins/encoder_uvg266.cc b/libheif/plugins/encoder_uvg266.cc
index 360fad3d..75efea88 100644
--- a/libheif/plugins/encoder_uvg266.cc
+++ b/libheif/plugins/encoder_uvg266.cc
@@ -465,6 +465,19 @@ static heif_error uvg266_start_sequence_encoding_intern(void* encoder_raw, const
{
encoder_struct_uvg266* encoder = (encoder_struct_uvg266*) encoder_raw;
+ // close the encoder if it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ if (encoder->api) {
+ if (encoder->kvzencoder) {
+ encoder->api->encoder_close(encoder->kvzencoder);
+ encoder->kvzencoder = nullptr;
+ }
+ if (encoder->config) {
+ encoder->api->config_destroy(encoder->config);
+ encoder->config = nullptr;
+ }
+ }
+
int bit_depth = heif_image_get_bits_per_pixel_range(image, heif_channel_Y);
const uvg_api* api = uvg_api_get(bit_depth);
diff --git a/libheif/plugins/encoder_vvenc.cc b/libheif/plugins/encoder_vvenc.cc
index 4367d6e1..01bc3670 100644
--- a/libheif/plugins/encoder_vvenc.cc
+++ b/libheif/plugins/encoder_vvenc.cc
@@ -434,6 +434,13 @@ static heif_error vvenc_start_sequence_encoding_intern(void* encoder_raw, const
{
encoder_struct_vvenc* encoder = (encoder_struct_vvenc*) encoder_raw;
+ // close the encoder if it was already initialized
+ // (e.g. when the encoder is reused for alpha encoding after being used for YUV encoding)
+ if (encoder->vvencoder) {
+ vvenc_encoder_close(encoder->vvencoder);
+ encoder->vvencoder = nullptr;
+ }
+
vvenc_config params;
int bit_depth = heif_image_get_bits_per_pixel_range(image, heif_channel_Y);