From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <ffmpeg-devel-bounces@ffmpeg.org>
Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100])
	by master.gitmailbox.com (Postfix) with ESMTPS id 9CD4D4D925
	for <ffmpegdev@gitmailbox.com>; Mon, 21 Apr 2025 10:57:17 +0000 (UTC)
Received: from [127.0.1.1] (localhost [127.0.0.1])
	by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 6254B687D26;
	Mon, 21 Apr 2025 13:57:13 +0300 (EEST)
Received: from smtp.waider.ie (smtp.waider.ie [52.31.250.228])
 by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id E909E687BFE
 for <ffmpeg-devel@ffmpeg.org>; Mon, 21 Apr 2025 13:57:06 +0300 (EEST)
Received: from localhost.localdomain (unknown [109.255.224.49])
 (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
 (No client certificate requested)
 by smtp.waider.ie (Postfix) with ESMTPSA id 423394B0D3;
 Mon, 21 Apr 2025 10:56:54 +0000 (UTC)
DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=waider.ie;
 s=waider_ie; t=1745233026;
 bh=0VFdmnrh9KsHf7Qv6ExsYD9ovaBsv5q+r6eCJmGyBvc=;
 h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:
 MIME-Version:Content-Transfer-Encoding;
 b=DCiKRyTOPY0MX43rnHOYSwnw4F4M5+oNA3RXkor/TCNRlo+3vvmdH1r5uNlwAYFgC
 AiYIl1egKncIiD4+x6rQjGYLs97aU98OP/DZ7N4TvKLH9LW+X90LAmw3ljrXmSNJCr
 QdgaL+skNOFeDV9jNQ+Ef4Db9EUKbdrSttf4sZVg=
From: Ronan Waide <waider@waider.ie>
To: ffmpeg-devel@ffmpeg.org
Date: Mon, 21 Apr 2025 11:56:23 +0100
Message-Id: <20250421105622.26944-1-waider@waider.ie>
X-Mailer: git-send-email 2.39.5 (Apple Git-154)
In-Reply-To: <20250302172331.57779-1-waider@waider.ie>
References: <20250302172331.57779-1-waider@waider.ie>
MIME-Version: 1.0
X-Spam-Status: No, score=-102.9 required=5.0 tests=ALL_TRUSTED,BAYES_00,
 USER_IN_WELCOMELIST,USER_IN_WHITELIST autolearn=ham autolearn_force=no
 version=3.4.3
X-Spam-Checker-Version: SpamAssassin 3.4.3 (2019-12-06) on ec2.waider.ie
Subject: [FFmpeg-devel] [PATCH v6] avcodec/dvbsubenc: add a disable_2bpp
 option to work around some decoders.
X-BeenThere: ffmpeg-devel@ffmpeg.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org>
List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe>
List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel>
List-Post: <mailto:ffmpeg-devel@ffmpeg.org>
List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help>
List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>,
 <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe>
Reply-To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org>
Cc: Ronan Waide <waider@waider.ie>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: ffmpeg-devel-bounces@ffmpeg.org
Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org>
Archived-At: <https://master.gitmailbox.com/ffmpegdev/20250421105622.26944-1-waider@waider.ie/>
List-Archive: <https://master.gitmailbox.com/ffmpegdev/>
List-Post: <mailto:ffmpegdev@gitmailbox.com>

[rebasing against current HEAD since there were some conflicting changes]

As noted in the code in several places, some DVB subtitle decoders
don't handle 2bpp color. This patch adds a disable_2bpp option which
disables the 2bpp format; subtitles which would use 2bpp will be bumped
up to 4bpp. Per suggestion from sw, disable_2pp defaults to true.

Signed-off-by: Ronan Waide <waider@waider.ie>
---
 doc/encoders.texi      | 27 +++++++++++++++++
 libavcodec/dvbsubenc.c | 68 +++++++++++++++++++++++++++++++-----------
 2 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/doc/encoders.texi b/doc/encoders.texi
index 128e81a2e7..7dcf0d1f92 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -4497,6 +4497,33 @@ Reduces detail but attempts to preserve color at extremely low bitrates.
 @chapter Subtitles Encoders
 @c man begin SUBTITLES ENCODERS
 
+@section dvbsub
+
+This codec encodes the bitmap subtitle format that is used in DVB
+broadcasts and recordings. The bitmaps are typically embedded in a
+container such as MPEG-TS as a separate stream.
+
+@subsection Options
+
+@table @option
+@item disable_2bpp @var{boolean}
+Disable the 2 bits-per-pixel encoding format.
+
+DVB supports 2, 4, and 8 bits-per-pixel color lookup tables. However,
+not all players support or properly support 2 bits-per-pixel,
+resulting in unusable subtitles.
+@table @option
+@item 0
+The 2 bits-per-pixel encoding format will be used for subtitles with 4
+colors or less.
+
+@item 1
+The 2 bits-per-pixel encoding format will be disabled, and subtitles
+with 4 colors or less will use a 4 bits-per-pixel format. (default)
+@end table
+
+@end table
+
 @section dvdsub
 
 This codec encodes the bitmap subtitle format that is used in DVDs.
diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c
index 113bb320a9..5c02074484 100644
--- a/libavcodec/dvbsubenc.c
+++ b/libavcodec/dvbsubenc.c
@@ -22,9 +22,12 @@
 #include "bytestream.h"
 #include "codec_internal.h"
 #include "libavutil/colorspace.h"
+#include "libavutil/opt.h"
 
 typedef struct DVBSubtitleContext {
+    AVClass * class;
     int object_version;
+    int disable_2bpp;
 } DVBSubtitleContext;
 
 #define PUTBITS2(val)\
@@ -274,13 +277,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
 {
     DVBSubtitleContext *s = avctx->priv_data;
     uint8_t *q, *pseg_len;
-    int page_id, region_id, clut_id, object_id, i, bpp_index, page_state;
+    int page_id, region_id, clut_id, object_id, i, bpp_index, page_state, min_colors;
 
 
     q = outbuf;
 
     page_id = 1;
 
+    min_colors = s->disable_2bpp ? 16 : 0;
+
     if (h->num_rects && !h->rects)
         return AVERROR(EINVAL);
 
@@ -330,21 +335,22 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
     if (h->num_rects) {
         for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
             /* CLUT segment */
+            int nb_colors = FFMAX(min_colors, h->rects[clut_id]->nb_colors);
 
-            if (h->rects[clut_id]->nb_colors <= 4U) {
+            if (nb_colors <= 4U) {
                 /* 2 bpp, some decoders do not support it correctly */
                 bpp_index = 0;
-            } else if (h->rects[clut_id]->nb_colors <= 16U) {
+            } else if (nb_colors <= 16U) {
                 /* 4 bpp, standard encoding */
                 bpp_index = 1;
-            } else if (h->rects[clut_id]->nb_colors <= 256U) {
+            } else if (nb_colors <= 256U) {
                 /* 8 bpp, standard encoding */
                 bpp_index = 2;
             } else {
                 return AVERROR(EINVAL);
             }
 
-            if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6)
+            if (buf_size < 6 + nb_colors * 6)
                 return AVERROR_BUFFER_TOO_SMALL;
 
             /* CLUT segment */
@@ -356,16 +362,24 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
             *q++ = clut_id;
             *q++ = (0 << 4) | 0xf; /* version = 0 */
 
-            for(i = 0; i < h->rects[clut_id]->nb_colors; i++) {
+            for(i = 0; i < nb_colors; i++) {
                 *q++ = i; /* clut_entry_id */
                 *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */
                 {
                     int a, r, g, b;
-                    uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i];
-                    a = (x >> 24) & 0xff;
-                    r = (x >> 16) & 0xff;
-                    g = (x >>  8) & 0xff;
-                    b = (x >>  0) & 0xff;
+                    if (i < h->rects[clut_id]->nb_colors) {
+                        uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i];
+                        a = (x >> 24) & 0xff;
+                        r = (x >> 16) & 0xff;
+                        g = (x >>  8) & 0xff;
+                        b = (x >>  0) & 0xff;
+                    } else {
+                        /* pad out the CLUT */
+                        a = 0;
+                        r = 0;
+                        g = 0;
+                        b = 0;
+                    }
 
                     *q++ = RGB_TO_Y_CCIR(r, g, b);
                     *q++ = RGB_TO_V_CCIR(r, g, b, 0);
@@ -375,7 +389,7 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
             }
 
             bytestream_put_be16(&pseg_len, q - pseg_len - 2);
-            buf_size -= 6 + h->rects[clut_id]->nb_colors * 6;
+            buf_size -= 6 + nb_colors * 6;
         }
 
         if (buf_size < h->num_rects * 22)
@@ -383,14 +397,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
         for (region_id = 0; region_id < h->num_rects; region_id++) {
 
             /* region composition segment */
+            int nb_colors = FFMAX(min_colors, h->rects[region_id]->nb_colors);
 
-            if (h->rects[region_id]->nb_colors <= 4) {
+            if (nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
                 bpp_index = 0;
-            } else if (h->rects[region_id]->nb_colors <= 16) {
+            } else if (nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
                 bpp_index = 1;
-            } else if (h->rects[region_id]->nb_colors <= 256) {
+            } else if (nb_colors <= 256) {
                 /* 8 bpp, standard encoding */
                 bpp_index = 2;
             } else {
@@ -426,17 +441,19 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
                                   const uint8_t *bitmap, int linesize,
                                   int w, int h);
 
+            int nb_colors = FFMAX(min_colors, h->rects[object_id]->nb_colors);
+
             if (buf_size < 13)
                 return AVERROR_BUFFER_TOO_SMALL;
 
             /* bpp_index maths */
-            if (h->rects[object_id]->nb_colors <= 4) {
+            if (nb_colors <= 4) {
                 /* 2 bpp, some decoders do not support it correctly */
                 dvb_encode_rle = dvb_encode_rle2;
-            } else if (h->rects[object_id]->nb_colors <= 16) {
+            } else if (nb_colors <= 16) {
                 /* 4 bpp, standard encoding */
                 dvb_encode_rle = dvb_encode_rle4;
-            } else if (h->rects[object_id]->nb_colors <= 256) {
+            } else if (nb_colors <= 256) {
                 /* 8 bpp, standard encoding */
                 dvb_encode_rle = dvb_encode_rle8;
             } else {
@@ -508,6 +525,20 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
     return q - outbuf;
 }
 
+#define OFFSET(x) offsetof(DVBSubtitleContext, x)
+#define SE AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_ENCODING_PARAM
+static const AVOption options[] = {
+    {"disable_2bpp", "disable the 2bpp subtitle encoder", OFFSET(disable_2bpp), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, SE},
+    { NULL },
+};
+
+static const AVClass dvbsubenc_class = {
+    .class_name = "DVBSUB subtitle encoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 const FFCodec ff_dvbsub_encoder = {
     .p.name         = "dvbsub",
     CODEC_LONG_NAME("DVB subtitles"),
@@ -515,4 +546,5 @@ const FFCodec ff_dvbsub_encoder = {
     .p.id           = AV_CODEC_ID_DVB_SUBTITLE,
     .priv_data_size = sizeof(DVBSubtitleContext),
     FF_CODEC_ENCODE_SUB_CB(dvbsub_encode),
+    .p.priv_class   = &dvbsubenc_class,
 };
-- 
2.39.5 (Apple Git-154)

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".