Commit d1434518fb for ffmpeg

commit d1434518fbd03789e3e5dc0657a7a9f1123ce074
Author: Michael Niedermayer <michael@niedermayer.cc>
Date:   Mon Sep 28 15:38:10 2026 +0200

    avutil/encryption_info: add av_encryption_init_info_append_side_data()

    Appends to already serialized init info side data, growing it with
    av_fast_realloc(), so a demuxer can collect pssh records in linear time
    without depending on the side data format.

diff --git a/doc/APIchanges b/doc/APIchanges
index 4e02c0996d..42d539990f 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2026-06-23.

 API changes, most recent first:

+2026-10-xx - xxxxxxxxxx - lavu 61.15.100 - encryption_info.h
+  Add av_encryption_init_info_append_side_data().
+
 2026-10-18 - xxxxxxxxxx - lavc 63.21.100 - codec_id.h
   Add AV_CODEC_ID_IMM6.

diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c
index 6fc3e33842..9643840157 100644
--- a/libavutil/encryption_info.c
+++ b/libavutil/encryption_info.c
@@ -19,6 +19,7 @@
 #include <string.h>

 #include "encryption_info.h"
+#include "error.h"
 #include "mem.h"
 #include "intreadwrite.h"

@@ -295,37 +296,36 @@ AVEncryptionInitInfo *av_encryption_init_info_get_side_data(
     return ret;
 }

-uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size)
+int av_encryption_init_info_append_side_data(uint8_t **side_data, size_t *side_data_size,
+                                             unsigned int *allocated_size,
+                                             const AVEncryptionInitInfo *info)
 {
     const AVEncryptionInitInfo *cur_info;
     uint8_t *buffer, *cur_buffer;
-    uint32_t i, init_info_count;
-    uint64_t temp_side_data_size;
+    uint32_t i;
+    uint64_t init_info_count    = *side_data ? AV_RB32(*side_data) : 0;
+    size_t   old_side_data_size = *side_data ? *side_data_size : 4;
+    uint64_t new_side_data_size = old_side_data_size;

-    temp_side_data_size = 4;
-    init_info_count = 0;
     for (cur_info = info; cur_info; cur_info = cur_info->next) {
-        temp_side_data_size += (uint64_t)FF_ENCRYPTION_INIT_INFO_EXTRA + cur_info->system_id_size + cur_info->data_size;
-        if (init_info_count == UINT32_MAX || temp_side_data_size > UINT32_MAX) {
-            return NULL;
-        }
+        new_side_data_size += (uint64_t)FF_ENCRYPTION_INIT_INFO_EXTRA + cur_info->system_id_size + cur_info->data_size;
+        if (init_info_count == UINT32_MAX || new_side_data_size > UINT32_MAX)
+            return AVERROR(EINVAL);
         init_info_count++;

         if (cur_info->num_key_ids) {
-            temp_side_data_size += (uint64_t)cur_info->num_key_ids * cur_info->key_id_size;
-            if (temp_side_data_size > UINT32_MAX) {
-                return NULL;
-            }
+            new_side_data_size += (uint64_t)cur_info->num_key_ids * cur_info->key_id_size;
+            if (new_side_data_size > UINT32_MAX)
+                return AVERROR(EINVAL);
         }
     }
-    *side_data_size = temp_side_data_size;

-    cur_buffer = buffer = av_malloc(*side_data_size);
+    buffer = av_fast_realloc(*side_data, allocated_size, new_side_data_size);
     if (!buffer)
-        return NULL;
+        return AVERROR(ENOMEM);

-    AV_WB32(cur_buffer, init_info_count);
-    cur_buffer += 4;
+    AV_WB32(buffer, init_info_count);
+    cur_buffer = buffer + old_side_data_size;
     for (cur_info = info; cur_info; cur_info = cur_info->next) {
         AV_WB32(cur_buffer,      cur_info->system_id_size);
         AV_WB32(cur_buffer +  4, cur_info->num_key_ids);
@@ -345,5 +345,17 @@ uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info,
         }
     }

-    return buffer;
+    *side_data      = buffer;
+    *side_data_size = new_side_data_size;
+    return 0;
+}
+
+uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size)
+{
+    uint8_t *side_data = NULL;
+    unsigned int allocated_size = 0;
+
+    if (av_encryption_init_info_append_side_data(&side_data, side_data_size, &allocated_size, info) < 0)
+        return NULL;
+    return side_data;
 }
diff --git a/libavutil/encryption_info.h b/libavutil/encryption_info.h
index 8fe7ebfe43..6fd39cf02c 100644
--- a/libavutil/encryption_info.h
+++ b/libavutil/encryption_info.h
@@ -202,4 +202,21 @@ AVEncryptionInitInfo *av_encryption_init_info_get_side_data(
 uint8_t *av_encryption_init_info_add_side_data(
     const AVEncryptionInitInfo *info, size_t *side_data_size);

+/**
+ * Appends a copy of the given encryption init info list to encryption init
+ * info side data, growing the side data with av_fast_realloc().
+ *
+ * @param side_data      Side data created by this function or
+ *                       av_encryption_init_info_add_side_data(), *side_data
+ *                       may be NULL to create new side data.
+ * @param side_data_size Size of *side_data.
+ * @param allocated_size Allocated size of *side_data, as for av_fast_realloc().
+ * @param info           The list to append.
+ * @return 0 on success, a negative AVERROR code on failure, in which case
+ *         *side_data and *side_data_size are unchanged.
+ */
+int av_encryption_init_info_append_side_data(
+    uint8_t **side_data, size_t *side_data_size, unsigned int *allocated_size,
+    const AVEncryptionInitInfo *info);
+
 #endif /* AVUTIL_ENCRYPTION_INFO_H */
diff --git a/libavutil/tests/encryption_info.c b/libavutil/tests/encryption_info.c
index 55c668c6d5..d8f0187ef9 100644
--- a/libavutil/tests/encryption_info.c
+++ b/libavutil/tests/encryption_info.c
@@ -141,8 +141,9 @@ static AVEncryptionInitInfo *create_init_info(void)
 static void run_encryption_init_info_test(void)
 {
     AVEncryptionInitInfo *info, *copy;
-    uint8_t *side_data;
-    size_t side_data_size;
+    uint8_t *side_data, *appended;
+    size_t side_data_size, appended_size;
+    unsigned int allocated_size = 0;

     info = create_init_info();

@@ -157,6 +158,8 @@ static void run_encryption_init_info_test(void)

     // Make the first init info different from the second to test the correct order.
     memset(info->system_id, 0, info->system_id_size);
+    appended = av_encryption_init_info_add_side_data(info, &appended_size);
+    av_assert0(appended);
     info->next = create_init_info();
     side_data = av_encryption_init_info_add_side_data(info, &side_data_size);
     av_assert0(side_data);
@@ -164,6 +167,11 @@ static void run_encryption_init_info_test(void)
     av_assert0(copy);
     av_assert0(compare_encryption_init_info(info, copy) == 0);
     av_encryption_init_info_free(copy);
+
+    av_assert0(av_encryption_init_info_append_side_data(&appended, &appended_size, &allocated_size, info->next) == 0);
+    av_assert0(appended_size == side_data_size);
+    av_assert0(memcmp(appended, side_data, side_data_size) == 0);
+    av_free(appended);
     av_free(side_data);

     av_encryption_init_info_free(info);
diff --git a/libavutil/version.h b/libavutil/version.h
index ed6abeab78..9f1429987a 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
  */

 #define LIBAVUTIL_VERSION_MAJOR  61
-#define LIBAVUTIL_VERSION_MINOR  14
+#define LIBAVUTIL_VERSION_MINOR  15
 #define LIBAVUTIL_VERSION_MICRO 100

 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \