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);