PR #23522 opened by mkver
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23522
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23522.patch


>From 114ec661084966e36c51209108582c22fb98ca19 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 17 Jun 2026 22:11:53 +0200
Subject: [PATCH 1/2] avformat/matroskaenc: Extend EBML writer to write lists
 of buffers

This is intended for LCEVC where an EBML buffer is assembled
by prepending a short header to an already existing buffer.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/matroskaenc.c | 42 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 97d66558f8..0d0cd0832b 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -116,8 +116,15 @@ typedef enum EbmlType {
     EBML_BIN,
     EBML_BLOCK,   ///< pseudo-type for writing (Simple)Blocks
     EBML_MASTER,
+    EBML_BUFARRAY, ///< pseudo-type for writing an array of BufEntry,
+                   ///< terminated by a BufEntry with data == NULL.
 } EbmlType;
 
+typedef struct BufEntry {
+    const void *data;
+    size_t      size;
+} BufEntry;
+
 typedef struct BlockContext {
     struct mkv_track *track;
     const AVPacket   *pkt;
@@ -144,6 +151,7 @@ typedef struct EbmlElement {
         const uint8_t *bin;
         struct MatroskaMuxContext *mkv; ///< used by EBML_BLOCK
         EbmlMaster master;
+        const BufEntry *bufs;
     } priv;
 } EbmlElement;
 
@@ -585,6 +593,14 @@ static void ebml_writer_add_block(EbmlWriter *writer, 
MatroskaMuxContext *mkv)
     elem->priv.mkv = mkv;
 }
 
+static void ebml_writer_add_bufarray(EbmlWriter *writer, uint32_t id,
+                                     const BufEntry *bufs)
+{
+    EbmlElement *elem = ebml_writer_add(writer, id, EBML_BUFARRAY);
+    av_assert2(bufs && bufs->data);
+    elem->priv.bufs = bufs;
+}
+
 static int ebml_writer_str_len(EbmlElement *elem)
 {
     size_t len = strlen(elem->priv.str);
@@ -676,6 +692,22 @@ static int ebml_writer_block_len(EbmlElement *elem)
     return 0;
 }
 
+static int ebml_writer_buf_array_len(EbmlElement *elem)
+{
+    const BufEntry *bufs = elem->priv.bufs;
+    uint64_t total_size = 0;
+
+    do {
+        if (bufs->size > UINT64_MAX - total_size)
+            return AVERROR(ERANGE);
+        total_size += bufs->size;
+    } while ((++bufs)->data);
+
+    elem->size = total_size;
+
+    return 0;
+}
+
 static void ebml_writer_write_block(const EbmlElement *elem, AVIOContext *pb)
 {
     MatroskaMuxContext *const mkv = elem->priv.mkv;
@@ -722,6 +754,9 @@ static int ebml_writer_elem_len(EbmlWriter *writer, 
EbmlElement *elem,
         case EBML_MASTER:
             ret = ebml_writer_master_len(writer, elem, remaining_elems);
             break;
+        case EBML_BUFARRAY:
+            ret = ebml_writer_buf_array_len(elem);
+            break;
     }
     if (ret < 0)
         return ret;
@@ -770,6 +805,13 @@ static int ebml_writer_elem_write(const EbmlElement *elem, 
AVIOContext *pb)
 
             return nb_elems;
         }
+        case EBML_BUFARRAY: {
+            const BufEntry *bufs = elem->priv.bufs;
+            do {
+                avio_write(pb, bufs->data, bufs->size);
+            } while ((++bufs)->data);
+            break;
+        }
     }
     return 0;
 }
-- 
2.52.0


>From 1c090a57ea7a3a03c391258c74393239af0596c2 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <[email protected]>
Date: Wed, 17 Jun 2026 22:51:41 +0200
Subject: [PATCH 2/2] avformat/matroskaenc: Avoid tmp buffer when writing LCEVC
 side data

Also avoid an av_free() call in the ordinary case when there is
no LCEVC side data.

Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 libavformat/matroskaenc.c | 40 +++++++++++++++++++++------------------
 1 file changed, 22 insertions(+), 18 deletions(-)

diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c
index 0d0cd0832b..e091761ba9 100644
--- a/libavformat/matroskaenc.c
+++ b/libavformat/matroskaenc.c
@@ -2903,6 +2903,16 @@ static void mkv_write_blockadditional(EbmlWriter 
*writer, const uint8_t *buf,
     ebml_writer_close_master(writer);
 }
 
+static void mkv_add_blockadditional_bufarray(EbmlWriter *writer,
+                                             const BufEntry *bufs,
+                                             uint64_t additional_id)
+{
+    ebml_writer_open_master(writer, MATROSKA_ID_BLOCKMORE);
+    ebml_writer_add_uint(writer, MATROSKA_ID_BLOCKADDID, additional_id);
+    ebml_writer_add_bufarray(writer, MATROSKA_ID_BLOCKADDITIONAL, bufs);
+    ebml_writer_close_master(writer);
+}
+
 static int mkv_write_block(void *logctx, MatroskaMuxContext *mkv,
                            AVIOContext *pb, const AVStream *st,
                            mkv_track *track, const AVPacket *pkt,
@@ -2913,7 +2923,8 @@ static int mkv_write_block(void *logctx, 
MatroskaMuxContext *mkv,
     uint8_t t35_buf[6 + AV_HDR_PLUS_MAX_PAYLOAD_SIZE];
 #define SMPTE_2094_APP5_MAX_SIZE 855
     uint8_t smpte_2094_app5_buf[5 + SMPTE_2094_APP5_MAX_SIZE];
-    uint8_t *lcevc = NULL;
+    BufEntry lcevc_buffers[3];
+    uint8_t lcevc_header[4];
     uint8_t *side_data;
     size_t side_data_size;
     uint64_t additional_id;
@@ -3033,19 +3044,16 @@ static int mkv_write_block(void *logctx, 
MatroskaMuxContext *mkv,
         side_data = av_packet_get_side_data(pkt, AV_PKT_DATA_LCEVC,
                                             &side_data_size);
         if (side_data) {
-            size_t payload_size = side_data_size + 4;
+            AV_WB8 (lcevc_header + 0, ITU_T_T35_COUNTRY_CODE_UK);
+            AV_WB8 (lcevc_header + 1, 0); // t35_uk_country_code_second_octet
+            AV_WB16(lcevc_header + 2, ITU_T_T35_PROVIDER_CODE_VNOVA);
+            lcevc_buffers[0] = (BufEntry){ .data = lcevc_header, .size = 4 };
+            lcevc_buffers[1] = (BufEntry){ .data = side_data,
+                                           .size = side_data_size };
+            lcevc_buffers[2].data = NULL;
 
-            lcevc = av_malloc(payload_size);
-            if (!lcevc)
-                return AVERROR(ENOMEM);
-
-            AV_WB8 (lcevc + 0, ITU_T_T35_COUNTRY_CODE_UK);
-            AV_WB8 (lcevc + 1, 0); // t35_uk_country_code_second_octet
-            AV_WB16(lcevc + 2, ITU_T_T35_PROVIDER_CODE_VNOVA);
-            memcpy (lcevc + 4, side_data, side_data_size);
-
-            mkv_write_blockadditional(&writer, lcevc, payload_size,
-                                      MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
+            mkv_add_blockadditional_bufarray(&writer, lcevc_buffers,
+                                             MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
             track->max_blockaddid = FFMAX(track->max_blockaddid,
                                           MATROSKA_BLOCK_ADD_ID_ITU_T_T35);
         }
@@ -3065,11 +3073,7 @@ static int mkv_write_block(void *logctx, 
MatroskaMuxContext *mkv,
         ebml_writer_add_sint(&writer, MATROSKA_ID_BLOCKREFERENCE,
                              track->last_timestamp - ts);
 
-    ret = ebml_writer_write(&writer, pb);
-
-    av_free(lcevc);
-
-    return ret;
+    return ebml_writer_write(&writer, pb);
 }
 
 static int mkv_end_cluster(AVFormatContext *s)
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to