Commit 4811625b5f for ffmpeg

commit 4811625b5f4e5aed528aed9225d0ca868a8e6e96
Author: Jun Zhao <barryjzhao@tencent.com>
Date:   Sat Oct 31 17:02:42 2026 +0800

    avcodec/dvbsubenc: provide the page ids in extradata

    The DVB subtitles written by this encoder always use page 1 as
    composition and ancillary page id, but the encoder never told the muxers
    about it: it never set any extradata.

    Muxers need it. The Matroska CodecPrivate of an S_DVBSUB track is
    mandatory and holds the composition page id, the ancillary page id and
    the subtitling type, five bytes in that order; MPEG-TS reorders these
    fields into its subtitling descriptor, which carries the language and
    the type before the page ids, and the decoder only reads the page ids.
    A file without them is invalid, and players that require them (VLC
    refuses to create such a track and then filters the segments by page id)
    show no subtitles at all, while players that do not, like mpv, are
    unaffected.

    Set the five bytes in the encoder so that every container gets them,
    including MPEG-TS, which previously filled in the page ids with the same
    hardcoded default. The encoded packets are unchanged; only the
    fate-sub-dvb reference gains the extradata line of the output stream.

    Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/25610
    Signed-off-by: Jun Zhao <barryjzhao@tencent.com>

diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c
index e40199472b..a750772356 100644
--- a/libavcodec/dvbsubenc.c
+++ b/libavcodec/dvbsubenc.c
@@ -23,8 +23,14 @@
 #include "codec_internal.h"
 #include "libavutil/avassert.h"
 #include "libavutil/colorspace.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
 #include "libavutil/opt.h"

+/* Every display set produced by this encoder uses this single page, i.e.
+ * the composition page id and the ancillary page id are both 1. */
+#define DVB_SUB_PAGE_ID 1
+
 typedef struct DVBSubtitleContext {
     AVClass * class;
     int object_version;
@@ -274,6 +280,30 @@ static int dvb_encode_rle8(uint8_t **pq, int buf_size,
     return len;
 }

+static av_cold int dvbsub_encode_init(AVCodecContext *avctx)
+{
+    /* Muxers use this FFmpeg/Matroska extradata layout: composition page
+     * id, ancillary page id, then subtitling type. MPEG-TS writes the
+     * type before the page ids in its subtitling descriptor. The decoder
+     * reads the page ids. Type 0x10 denotes normal subtitles with no
+     * monitor aspect ratio criticality. */
+    uint8_t *extradata = av_mallocz(5 + AV_INPUT_BUFFER_PADDING_SIZE);
+    if (!extradata)
+        return AVERROR(ENOMEM);
+
+    AV_WB16(extradata,     DVB_SUB_PAGE_ID);
+    AV_WB16(extradata + 2, DVB_SUB_PAGE_ID);
+    extradata[4]           = 0x10;
+
+    /* Extradata of the input stream has been copied into the context; it is
+     * of no use here, the page ids are always the ones above. */
+    av_freep(&avctx->extradata);
+    avctx->extradata      = extradata;
+    avctx->extradata_size = 5;
+
+    return 0;
+}
+
 static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
                          const AVSubtitle *h)
 {
@@ -284,7 +314,7 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,

     q = outbuf;

-    page_id = 1;
+    page_id = DVB_SUB_PAGE_ID;

     switch(s->min_bpp) {
     case 2:
@@ -555,6 +585,7 @@ const FFCodec ff_dvbsub_encoder = {
     .p.type         = AVMEDIA_TYPE_SUBTITLE,
     .p.id           = AV_CODEC_ID_DVB_SUBTITLE,
     .priv_data_size = sizeof(DVBSubtitleContext),
+    .init           = dvbsub_encode_init,
     FF_CODEC_ENCODE_SUB_CB(dvbsub_encode),
     .p.priv_class   = &dvbsubenc_class,
 };
diff --git a/tests/ref/fate/sub-dvb b/tests/ref/fate/sub-dvb
index cbd1801d64..8cd9270949 100644
--- a/tests/ref/fate/sub-dvb
+++ b/tests/ref/fate/sub-dvb
@@ -1,3 +1,4 @@
+#extradata 0:        5, 0x00160012
 #tb 0: 1/1000000
 #media_type 0: subtitle
 #codec_id 0: dvb_subtitle