You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-04 22:03:09 +02:00
avcodec/dvbsubenc: add a min_bpp option to work around some decoders
As noted in the code in several places, some DVB subtitle decoders don't handle 2bpp color. This patch adds a min_bpp option which sets a lower bound on the number of bits-per-pixel in the color tables. It defaults to 4 to avoid the problematic 2bpp decoders. Signed-off-by: Ronan Waide <waider@waider.ie>
This commit is contained in:
@ -4602,6 +4602,25 @@ Reduces detail but attempts to preserve color at extremely low bitrates.
|
|||||||
@chapter Subtitles Encoders
|
@chapter Subtitles Encoders
|
||||||
@c man begin 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 min_bpp @var{integer (2, 4, or 8)}
|
||||||
|
Set a minimum bits-per-pixel value for the subtitle color lookup tables.
|
||||||
|
|
||||||
|
DVB supports 2, 4, and 8 bits-per-pixel color lookup tables. This
|
||||||
|
option enables forcing a particular bits-per-pixel value regardless of
|
||||||
|
the number of colors. Since not all players support or properly
|
||||||
|
support 2 bits-per-pixel, this value defaults to 4.
|
||||||
|
|
||||||
|
@end table
|
||||||
|
|
||||||
@section dvdsub
|
@section dvdsub
|
||||||
|
|
||||||
This codec encodes the bitmap subtitle format that is used in DVDs.
|
This codec encodes the bitmap subtitle format that is used in DVDs.
|
||||||
|
@ -22,9 +22,12 @@
|
|||||||
#include "bytestream.h"
|
#include "bytestream.h"
|
||||||
#include "codec_internal.h"
|
#include "codec_internal.h"
|
||||||
#include "libavutil/colorspace.h"
|
#include "libavutil/colorspace.h"
|
||||||
|
#include "libavutil/opt.h"
|
||||||
|
|
||||||
typedef struct DVBSubtitleContext {
|
typedef struct DVBSubtitleContext {
|
||||||
|
AVClass * class;
|
||||||
int object_version;
|
int object_version;
|
||||||
|
int min_bpp;
|
||||||
} DVBSubtitleContext;
|
} DVBSubtitleContext;
|
||||||
|
|
||||||
#define PUTBITS2(val)\
|
#define PUTBITS2(val)\
|
||||||
@ -275,13 +278,24 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
|
|||||||
{
|
{
|
||||||
DVBSubtitleContext *s = avctx->priv_data;
|
DVBSubtitleContext *s = avctx->priv_data;
|
||||||
uint8_t *q, *pseg_len;
|
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;
|
q = outbuf;
|
||||||
|
|
||||||
page_id = 1;
|
page_id = 1;
|
||||||
|
|
||||||
|
switch(s->min_bpp) {
|
||||||
|
case 2:
|
||||||
|
case 4:
|
||||||
|
case 8:
|
||||||
|
min_colors = 1 << s->min_bpp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "Invalid min_bpp value %d.\n", s->min_bpp);
|
||||||
|
return AVERROR(EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
if (h->num_rects && !h->rects)
|
if (h->num_rects && !h->rects)
|
||||||
return AVERROR(EINVAL);
|
return AVERROR(EINVAL);
|
||||||
|
|
||||||
@ -331,14 +345,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
|
|||||||
if (h->num_rects) {
|
if (h->num_rects) {
|
||||||
for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
|
for (clut_id = 0; clut_id < h->num_rects; clut_id++) {
|
||||||
/* CLUT segment */
|
/* 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 */
|
/* 2 bpp, some decoders do not support it correctly */
|
||||||
bpp_index = 0;
|
bpp_index = 0;
|
||||||
} else if (h->rects[clut_id]->nb_colors <= 16U) {
|
} else if (nb_colors <= 16U) {
|
||||||
/* 4 bpp, standard encoding */
|
/* 4 bpp, standard encoding */
|
||||||
bpp_index = 1;
|
bpp_index = 1;
|
||||||
} else if (h->rects[clut_id]->nb_colors <= 256U) {
|
} else if (nb_colors <= 256U) {
|
||||||
/* 8 bpp, standard encoding */
|
/* 8 bpp, standard encoding */
|
||||||
bpp_index = 2;
|
bpp_index = 2;
|
||||||
} else {
|
} else {
|
||||||
@ -384,14 +399,15 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
|
|||||||
for (region_id = 0; region_id < h->num_rects; region_id++) {
|
for (region_id = 0; region_id < h->num_rects; region_id++) {
|
||||||
|
|
||||||
/* region composition segment */
|
/* 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 */
|
/* 2 bpp, some decoders do not support it correctly */
|
||||||
bpp_index = 0;
|
bpp_index = 0;
|
||||||
} else if (h->rects[region_id]->nb_colors <= 16) {
|
} else if (nb_colors <= 16) {
|
||||||
/* 4 bpp, standard encoding */
|
/* 4 bpp, standard encoding */
|
||||||
bpp_index = 1;
|
bpp_index = 1;
|
||||||
} else if (h->rects[region_id]->nb_colors <= 256) {
|
} else if (nb_colors <= 256) {
|
||||||
/* 8 bpp, standard encoding */
|
/* 8 bpp, standard encoding */
|
||||||
bpp_index = 2;
|
bpp_index = 2;
|
||||||
} else {
|
} else {
|
||||||
@ -427,17 +443,19 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
|
|||||||
const uint8_t *bitmap, int linesize,
|
const uint8_t *bitmap, int linesize,
|
||||||
int w, int h);
|
int w, int h);
|
||||||
|
|
||||||
|
int nb_colors = FFMAX(min_colors, h->rects[object_id]->nb_colors);
|
||||||
|
|
||||||
if (buf_size < 13)
|
if (buf_size < 13)
|
||||||
return AVERROR_BUFFER_TOO_SMALL;
|
return AVERROR_BUFFER_TOO_SMALL;
|
||||||
|
|
||||||
/* bpp_index maths */
|
/* bpp_index maths */
|
||||||
if (h->rects[object_id]->nb_colors <= 4) {
|
if (nb_colors <= 4) {
|
||||||
/* 2 bpp, some decoders do not support it correctly */
|
/* 2 bpp, some decoders do not support it correctly */
|
||||||
dvb_encode_rle = dvb_encode_rle2;
|
dvb_encode_rle = dvb_encode_rle2;
|
||||||
} else if (h->rects[object_id]->nb_colors <= 16) {
|
} else if (nb_colors <= 16) {
|
||||||
/* 4 bpp, standard encoding */
|
/* 4 bpp, standard encoding */
|
||||||
dvb_encode_rle = dvb_encode_rle4;
|
dvb_encode_rle = dvb_encode_rle4;
|
||||||
} else if (h->rects[object_id]->nb_colors <= 256) {
|
} else if (nb_colors <= 256) {
|
||||||
/* 8 bpp, standard encoding */
|
/* 8 bpp, standard encoding */
|
||||||
dvb_encode_rle = dvb_encode_rle8;
|
dvb_encode_rle = dvb_encode_rle8;
|
||||||
} else {
|
} else {
|
||||||
@ -509,6 +527,20 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size,
|
|||||||
return q - outbuf;
|
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[] = {
|
||||||
|
{"min_bpp", "minimum bits-per-pixel for subtitle colors (2, 4 or 8)", OFFSET(min_bpp), AV_OPT_TYPE_INT, {.i64 = 4}, 2, 8, 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 = {
|
const FFCodec ff_dvbsub_encoder = {
|
||||||
.p.name = "dvbsub",
|
.p.name = "dvbsub",
|
||||||
CODEC_LONG_NAME("DVB subtitles"),
|
CODEC_LONG_NAME("DVB subtitles"),
|
||||||
@ -516,4 +548,5 @@ const FFCodec ff_dvbsub_encoder = {
|
|||||||
.p.id = AV_CODEC_ID_DVB_SUBTITLE,
|
.p.id = AV_CODEC_ID_DVB_SUBTITLE,
|
||||||
.priv_data_size = sizeof(DVBSubtitleContext),
|
.priv_data_size = sizeof(DVBSubtitleContext),
|
||||||
FF_CODEC_ENCODE_SUB_CB(dvbsub_encode),
|
FF_CODEC_ENCODE_SUB_CB(dvbsub_encode),
|
||||||
|
.p.priv_class = &dvbsubenc_class,
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
#include "version_major.h"
|
#include "version_major.h"
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_MINOR 8
|
#define LIBAVCODEC_VERSION_MINOR 8
|
||||||
#define LIBAVCODEC_VERSION_MICRO 100
|
#define LIBAVCODEC_VERSION_MICRO 101
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||||
LIBAVCODEC_VERSION_MINOR, \
|
LIBAVCODEC_VERSION_MINOR, \
|
||||||
|
Reference in New Issue
Block a user