summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
Diffstat (limited to 'sub')
-rw-r--r--sub/dec_sub.c25
-rw-r--r--sub/dec_sub.h1
-rw-r--r--sub/filter_jsre.c2
-rw-r--r--sub/filter_regex.c2
-rw-r--r--sub/lavc_conv.c56
-rw-r--r--sub/osd.c14
-rw-r--r--sub/osd.h1
-rw-r--r--sub/osd_font.otfbin4460 -> 4504 bytes
-rw-r--r--sub/sd.h12
-rw-r--r--sub/sd_ass.c153
-rw-r--r--sub/sd_lavc.c26
11 files changed, 188 insertions, 104 deletions
diff --git a/sub/dec_sub.c b/sub/dec_sub.c
index 94ff3ba4dd..c03393a007 100644
--- a/sub/dec_sub.c
+++ b/sub/dec_sub.c
@@ -123,7 +123,7 @@ static void wakeup_demux(void *ctx)
mp_dispatch_interrupt(q);
}
-static void sub_destroy_cached_pkts(struct dec_sub *sub)
+static void destroy_cached_pkts(struct dec_sub *sub)
{
int index = 0;
while (index < sub->num_cached_pkts) {
@@ -204,7 +204,7 @@ struct dec_sub *sub_create(struct mpv_global *global, struct track *track,
};
sub->opts = sub->opts_cache->opts;
sub->shared_opts = sub->shared_opts_cache->opts;
- mp_mutex_init_type(&sub->lock, MP_MUTEX_RECURSIVE);
+ mp_mutex_init(&sub->lock);
sub->sd = init_decoder(sub);
if (sub->sd) {
@@ -445,11 +445,16 @@ char *sub_get_text(struct dec_sub *sub, double pts, enum sd_text_type type)
char *sub_ass_get_extradata(struct dec_sub *sub)
{
+ char *data = NULL;
+ mp_mutex_lock(&sub->lock);
if (strcmp(sub->sd->codec->codec, "ass") != 0)
- return NULL;
+ goto done;
char *extradata = sub->sd->codec->extradata;
int extradata_size = sub->sd->codec->extradata_size;
- return talloc_strndup(NULL, extradata, extradata_size);
+ data = talloc_strndup(NULL, extradata, extradata_size);
+done:
+ mp_mutex_unlock(&sub->lock);
+ return data;
}
struct sd_times sub_get_times(struct dec_sub *sub, double pts)
@@ -476,7 +481,7 @@ void sub_reset(struct dec_sub *sub)
sub->sd->driver->reset(sub->sd);
sub->last_pkt_pts = MP_NOPTS_VALUE;
sub->last_vo_pts = MP_NOPTS_VALUE;
- sub_destroy_cached_pkts(sub);
+ destroy_cached_pkts(sub);
TA_FREEP(&sub->new_segment);
mp_mutex_unlock(&sub->lock);
}
@@ -548,10 +553,16 @@ void sub_set_play_dir(struct dec_sub *sub, int dir)
bool sub_is_primary_visible(struct dec_sub *sub)
{
- return sub->shared_opts->sub_visibility[0];
+ mp_mutex_lock(&sub->lock);
+ bool ret = sub->shared_opts->sub_visibility[0];
+ mp_mutex_unlock(&sub->lock);
+ return ret;
}
bool sub_is_secondary_visible(struct dec_sub *sub)
{
- return sub->shared_opts->sub_visibility[1];
+ mp_mutex_lock(&sub->lock);
+ bool ret = sub->shared_opts->sub_visibility[1];
+ mp_mutex_unlock(&sub->lock);
+ return ret;
}
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index eb8406cb14..a40aa9bbfd 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -24,6 +24,7 @@ enum sd_ctrl {
enum sd_text_type {
SD_TEXT_TYPE_PLAIN,
SD_TEXT_TYPE_ASS,
+ SD_TEXT_TYPE_ASS_FULL,
};
struct sd_times {
diff --git a/sub/filter_jsre.c b/sub/filter_jsre.c
index f956000d55..fb711814e3 100644
--- a/sub/filter_jsre.c
+++ b/sub/filter_jsre.c
@@ -115,7 +115,7 @@ static struct demux_packet *jsre_filter(struct sd_filter *ft,
bool drop = false;
if (ft->opts->rf_plain)
- sd_ass_to_plaintext(text, strlen(text), text);
+ sd_ass_to_plaintext(&text, text);
for (int n = 0; n < p->num_regexes; n++) {
int found, err = p_regexec(p->J, n, text, &found);
diff --git a/sub/filter_regex.c b/sub/filter_regex.c
index 8e299918ce..1d29ea1ac1 100644
--- a/sub/filter_regex.c
+++ b/sub/filter_regex.c
@@ -64,7 +64,7 @@ static struct demux_packet *rf_filter(struct sd_filter *ft,
bool drop = false;
if (ft->opts->rf_plain)
- sd_ass_to_plaintext(text, strlen(text), text);
+ sd_ass_to_plaintext(&text, text);
for (int n = 0; n < p->num_regexes; n++) {
int err = regexec(&p->regexes[n], text, 0, NULL, 0);
diff --git a/sub/lavc_conv.c b/sub/lavc_conv.c
index 532e91d508..3a33933605 100644
--- a/sub/lavc_conv.c
+++ b/sub/lavc_conv.c
@@ -32,6 +32,8 @@
struct lavc_conv {
struct mp_log *log;
+ struct mp_subtitle_opts *opts;
+ bool styled;
AVCodecContext *avctx;
AVPacket *avpkt;
AVPacket *avpkt_vtt;
@@ -52,27 +54,13 @@ static const char *get_lavc_format(const char *format)
return format;
}
-// Disable style definitions generated by the libavcodec converter.
-// We always want the user defined style instead.
-static void disable_styles(bstr header)
-{
- bstr style = bstr0("\nStyle: ");
- while (header.len) {
- int n = bstr_find(header, style);
- if (n < 0)
- break;
- header.start[n + 1] = '#'; // turn into a comment
- header = bstr_cut(header, n + style.len);
- }
-}
-
-struct lavc_conv *lavc_conv_create(struct mp_log *log,
- const struct mp_codec_params *mp_codec)
+struct lavc_conv *lavc_conv_create(struct sd *sd)
{
struct lavc_conv *priv = talloc_zero(NULL, struct lavc_conv);
- priv->log = log;
+ priv->log = sd->log;
+ priv->opts = sd->opts;
priv->cur_list = talloc_array(priv, char*, 0);
- priv->codec = talloc_strdup(priv, mp_codec->codec);
+ priv->codec = talloc_strdup(priv, sd->codec->codec);
AVCodecContext *avctx = NULL;
AVDictionary *opts = NULL;
const char *fmt = get_lavc_format(priv->codec);
@@ -82,7 +70,7 @@ struct lavc_conv *lavc_conv_create(struct mp_log *log,
avctx = avcodec_alloc_context3(codec);
if (!avctx)
goto error;
- if (mp_set_avctx_codec_headers(avctx, mp_codec) < 0)
+ if (mp_set_avctx_codec_headers(avctx, sd->codec) < 0)
goto error;
priv->avpkt = av_packet_alloc();
@@ -90,6 +78,15 @@ struct lavc_conv *lavc_conv_create(struct mp_log *log,
if (!priv->avpkt || !priv->avpkt_vtt)
goto error;
+ switch (codec->id) {
+ case AV_CODEC_ID_DVB_TELETEXT:
+ av_dict_set_int(&opts, "txt_format", 2, 0);
+ break;
+ case AV_CODEC_ID_ARIB_CAPTION:
+ av_dict_set_int(&opts, "sub_type", SUBTITLE_ASS, 0);
+ break;
+ }
+
#if LIBAVCODEC_VERSION_MAJOR < 59
av_dict_set(&opts, "sub_text_format", "ass", 0);
#endif
@@ -106,7 +103,6 @@ struct lavc_conv *lavc_conv_create(struct mp_log *log,
priv->avctx = avctx;
priv->extradata = talloc_strndup(priv, avctx->subtitle_header,
avctx->subtitle_header_size);
- disable_styles(bstr0(priv->extradata));
return priv;
error:
@@ -250,6 +246,21 @@ char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet,
curr_pkt = priv->avpkt_vtt;
}
+ priv->styled = avctx->codec_id == AV_CODEC_ID_DVB_TELETEXT;
+
+ if (avctx->codec_id == AV_CODEC_ID_DVB_TELETEXT) {
+ if (!priv->opts->teletext_page) {
+ av_opt_set(avctx, "txt_page", "subtitle", AV_OPT_SEARCH_CHILDREN);
+ priv->styled = false;
+ } else if (priv->opts->teletext_page == -1) {
+ av_opt_set(avctx, "txt_page", "*", AV_OPT_SEARCH_CHILDREN);
+ } else {
+ char page[4];
+ snprintf(page, sizeof(page), "%d", priv->opts->teletext_page);
+ av_opt_set(avctx, "txt_page", page, AV_OPT_SEARCH_CHILDREN);
+ }
+ }
+
ret = avcodec_decode_subtitle2(avctx, &priv->cur, &got_sub, curr_pkt);
if (ret < 0) {
MP_ERR(priv, "Error decoding subtitle\n");
@@ -278,6 +289,11 @@ done:
return priv->cur_list;
}
+bool lavc_conv_is_styled(struct lavc_conv *priv)
+{
+ return priv->styled;
+}
+
void lavc_conv_reset(struct lavc_conv *priv)
{
avcodec_flush_buffers(priv->avctx);
diff --git a/sub/osd.c b/sub/osd.c
index d33aabdd53..58cc859a94 100644
--- a/sub/osd.c
+++ b/sub/osd.c
@@ -515,10 +515,16 @@ void osd_rescale_bitmaps(struct sub_bitmaps *imgs, int frame_w, int frame_h,
int cy = vidh / 2 - (int)(frame_h * yscale) / 2;
for (int i = 0; i < imgs->num_parts; i++) {
struct sub_bitmap *bi = &imgs->parts[i];
- bi->x = (int)(bi->x * xscale) + cx + res.ml;
- bi->y = (int)(bi->y * yscale) + cy + res.mt;
- bi->dw = (int)(bi->w * xscale + 0.5);
- bi->dh = (int)(bi->h * yscale + 0.5);
+ struct mp_rect rc = {
+ .x0 = lrint(bi->x * xscale),
+ .y0 = lrint(bi->y * yscale),
+ .x1 = lrint((bi->x + bi->w) * xscale),
+ .y1 = lrint((bi->y + bi->h) * yscale),
+ };
+ bi->x = rc.x0 + cx + res.ml;
+ bi->y = rc.y0 + cy + res.mt;
+ bi->dw = mp_rect_w(rc);
+ bi->dh = mp_rect_h(rc);
}
}
diff --git a/sub/osd.h b/sub/osd.h
index 2677847da5..bb3cbb378d 100644
--- a/sub/osd.h
+++ b/sub/osd.h
@@ -126,6 +126,7 @@ enum mp_osd_font_codepoints {
OSD_BRIGHTNESS = 0x0A,
OSD_HUE = 0x0B,
OSD_BALANCE = 0x0C,
+ OSD_REV = 0x0D,
OSD_PANSCAN = 0x50,
OSD_PB_START = 0x10,
diff --git a/sub/osd_font.otf b/sub/osd_font.otf
index 70b9b21f40..c5eff7c93d 100644
--- a/sub/osd_font.otf
+++ b/sub/osd_font.otf
Binary files differ
diff --git a/sub/sd.h b/sub/sd.h
index 459e8c07e9..0f5b8c7c72 100644
--- a/sub/sd.h
+++ b/sub/sd.h
@@ -51,11 +51,11 @@ struct sd_functions {
// lavc_conv.c
struct lavc_conv;
-struct lavc_conv *lavc_conv_create(struct mp_log *log,
- const struct mp_codec_params *mp_codec);
+struct lavc_conv *lavc_conv_create(struct sd *sd);
char *lavc_conv_get_extradata(struct lavc_conv *priv);
char **lavc_conv_decode(struct lavc_conv *priv, struct demux_packet *packet,
double *sub_pts, double *sub_duration);
+bool lavc_conv_is_styled(struct lavc_conv *priv);
void lavc_conv_reset(struct lavc_conv *priv);
void lavc_conv_uninit(struct lavc_conv *priv);
@@ -107,8 +107,10 @@ int sd_ass_fmt_offset(const char *event_format);
bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset);
// convert \0-terminated "Text" (ass) content to plaintext, possibly in-place.
-// result.start is out, result.len is MIN(out_siz, strlen(in)) or smaller.
-// if there's room: out[result.len] is set to \0. out == in is allowed.
-bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in);
+// result.start is *out, result.len is strlen(in) or smaller.
+// (*out)[result.len] is always set to \0. *out == in is allowed.
+// *out must be a talloc-allocated buffer or NULL, and will be reallocated if needed.
+// *out will not be reallocated if *out == in.
+bstr sd_ass_to_plaintext(char **out, const char *in);
#endif
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 6fa4d1bb52..baaf5c6905 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -51,7 +51,7 @@ struct sd_ass_priv {
bool clear_once;
struct mp_ass_packer *packer;
struct sub_bitmap_copy_cache *copy_cache;
- char last_text[500];
+ bstr last_text;
struct mp_image_params video_params;
struct mp_image_params last_params;
struct mp_osd_res osd;
@@ -271,7 +271,7 @@ static int init(struct sd *sd)
strcmp(sd->codec->codec, "null") != 0)
{
ctx->is_converted = true;
- ctx->converter = lavc_conv_create(sd->log, sd->codec);
+ ctx->converter = lavc_conv_create(sd);
if (!ctx->converter)
return -1;
@@ -420,7 +420,7 @@ static void decode(struct sd *sd, struct demux_packet *packet)
if (sd->opts->sub_stretch_durations ||
packet->duration < 0 || sub_duration == UINT32_MAX) {
if (!ctx->duration_unknown) {
- MP_WARN(sd, "Subtitle with unknown duration.\n");
+ MP_VERBOSE(sd, "Subtitle with unknown duration.\n");
ctx->duration_unknown = true;
}
sub_duration = UNKNOWN_DURATION;
@@ -510,7 +510,7 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim,
set_force_flags |= ASS_OVERRIDE_BIT_SELECTIVE_FONT_SCALE;
if (converted)
set_force_flags |= ASS_OVERRIDE_BIT_ALIGNMENT;
-#ifdef ASS_JUSTIFY_AUTO
+#if LIBASS_VERSION >= 0x01306000
if ((converted || shared_opts->ass_style_override[sd->order]) && opts->ass_justify)
set_force_flags |= ASS_OVERRIDE_BIT_JUSTIFY;
#endif
@@ -527,8 +527,16 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim,
ass_set_hinting(priv, set_hinting);
ass_set_line_spacing(priv, set_line_spacing);
#if LIBASS_VERSION >= 0x01600010
- if (converted)
+ if (converted) {
ass_track_set_feature(track, ASS_FEATURE_WRAP_UNICODE, 1);
+ if (!opts->sub_vsfilter_bidi_compat) {
+ for (int n = 0; n < track->n_styles; n++) {
+ track->styles[n].Encoding = -1;
+ }
+ ass_track_set_feature(track, ASS_FEATURE_BIDI_BRACKETS, 1);
+ ass_track_set_feature(track, ASS_FEATURE_WHOLE_TEXT_LAYOUT, 1);
+ }
+ }
#endif
if (converted) {
bool override_playres = true;
@@ -550,12 +558,13 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim,
if (override_playres) {
int vidw = dim->w - (dim->ml + dim->mr);
int vidh = dim->h - (dim->mt + dim->mb);
+ int old_playresx = track->PlayResX;
track->PlayResX = track->PlayResY * (double)vidw / MPMAX(vidh, 1);
- // ffmpeg and mpv use a default PlayResX of 384 when it is not known,
- // this comes from VSFilter.
- double fix_margins = track->PlayResX / (double)MP_ASS_FONT_PLAYRESX;
- track->styles->MarginL = round(track->styles->MarginL * fix_margins);
- track->styles->MarginR = round(track->styles->MarginR * fix_margins);
+ double fix_margins = track->PlayResX / (double)old_playresx;
+ for (int n = 0; n < track->n_styles; n++) {
+ track->styles[n].MarginL = round(track->styles[n].MarginL * fix_margins);
+ track->styles[n].MarginR = round(track->styles[n].MarginR * fix_margins);
+ }
}
}
}
@@ -642,7 +651,7 @@ static struct sub_bitmaps *get_bitmaps(struct sd *sd, struct mp_osd_res dim,
struct mp_subtitle_opts *opts = sd->opts;
struct mp_subtitle_shared_opts *shared_opts = sd->shared_opts;
bool no_ass = !opts->ass_enabled || shared_opts->ass_style_override[sd->order] == 5;
- bool converted = ctx->is_converted || no_ass;
+ bool converted = (ctx->is_converted && !lavc_conv_is_styled(ctx->converter)) || no_ass;
ASS_Track *track = no_ass ? ctx->shadow_track : ctx->ass_track;
ASS_Renderer *renderer = ctx->ass_renderer;
struct sub_bitmaps *res = &(struct sub_bitmaps){0};
@@ -700,30 +709,23 @@ done:
return res;
}
-struct buf {
- char *start;
- int size;
- int len;
-};
+#define MAX_BUF_SIZE 1024 * 1024
+#define MIN_EXPAND_SIZE 4096
-static void append(struct buf *b, char c)
+static void append(bstr *b, char c)
{
- if (b->len < b->size) {
- b->start[b->len] = c;
- b->len++;
- }
+ bstr_xappend(NULL, b, (bstr){&c, 1});
}
-static void ass_to_plaintext(struct buf *b, const char *in)
+static void ass_to_plaintext(bstr *b, const char *in)
{
- bool in_tag = false;
const char *open_tag_pos = NULL;
bool in_drawing = false;
while (*in) {
- if (in_tag) {
+ if (open_tag_pos) {
if (in[0] == '}') {
in += 1;
- in_tag = false;
+ open_tag_pos = NULL;
} else if (in[0] == '\\' && in[1] == 'p' && in[2] != 'o') {
in += 2;
// Skip text between \pN and \p0 tags. A \p without a number
@@ -747,7 +749,6 @@ static void ass_to_plaintext(struct buf *b, const char *in)
} else if (in[0] == '{') {
open_tag_pos = in;
in += 1;
- in_tag = true;
} else {
if (!in_drawing)
append(b, in[0]);
@@ -756,65 +757,86 @@ static void ass_to_plaintext(struct buf *b, const char *in)
}
}
// A '{' without a closing '}' is always visible.
- if (in_tag) {
- while (*open_tag_pos)
- append(b, *open_tag_pos++);
+ if (open_tag_pos) {
+ bstr_xappend(NULL, b, bstr0(open_tag_pos));
}
}
-// Empty string counts as whitespace. Reads s[len-1] even if there are \0s.
-static bool is_whitespace_only(char *s, int len)
+// Empty string counts as whitespace.
+static bool is_whitespace_only(bstr b)
{
- for (int n = 0; n < len; n++) {
- if (s[n] != ' ' && s[n] != '\t')
+ for (int n = 0; n < b.len; n++) {
+ if (b.start[n] != ' ' && b.start[n] != '\t')
return false;
}
return true;
}
-static char *get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
+static bstr get_text_buf(struct sd *sd, double pts, enum sd_text_type type)
{
struct sd_ass_priv *ctx = sd->priv;
ASS_Track *track = ctx->ass_track;
if (pts == MP_NOPTS_VALUE)
- return NULL;
+ return (bstr){0};
long long ipts = find_timestamp(sd, pts);
- struct buf b = {ctx->last_text, sizeof(ctx->last_text) - 1};
+ bstr *b = &ctx->last_text;
+
+ if (!b->start)
+ b->start = talloc_size(ctx, 4096);
+
+ b->len = 0;
for (int i = 0; i < track->n_events; ++i) {
ASS_Event *event = track->events + i;
if (ipts >= event->Start && ipts < event->Start + event->Duration) {
if (event->Text) {
- int start = b.len;
+ int start = b->len;
if (type == SD_TEXT_TYPE_PLAIN) {
- ass_to_plaintext(&b, event->Text);
+ ass_to_plaintext(b, event->Text);
+ } else if (type == SD_TEXT_TYPE_ASS_FULL) {
+ long long s = event->Start;
+ long long e = s + event->Duration;
+
+ ASS_Style *style = (event->Style < 0 || event->Style >= track->n_styles) ? NULL : &track->styles[event->Style];
+
+ int sh = (s / 60 / 60 / 1000);
+ int sm = (s / 60 / 1000) % 60;
+ int ss = (s / 1000) % 60;
+ int sc = (s / 10) % 100;
+ int eh = (e / 60 / 60 / 1000);
+ int em = (e / 60 / 1000) % 60;
+ int es = (e / 1000) % 60;
+ int ec = (e / 10) % 100;
+
+ bstr_xappend_asprintf(NULL, b, "Dialogue: %d,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,%s,%s,%04d,%04d,%04d,%s,%s",
+ event->Layer,
+ sh, sm, ss, sc,
+ eh, em, es, ec,
+ (style && style->Name) ? style->Name : "", event->Name,
+ event->MarginL, event->MarginR, event->MarginV,
+ event->Effect, event->Text);
} else {
- char *t = event->Text;
- while (*t)
- append(&b, *t++);
+ bstr_xappend(NULL, b, bstr0(event->Text));
}
- if (is_whitespace_only(&b.start[start], b.len - start)) {
- b.len = start;
+ if (is_whitespace_only(bstr_cut(*b, start))) {
+ b->len = start;
} else {
- append(&b, '\n');
+ append(b, '\n');
}
}
}
}
- b.start[b.len] = '\0';
+ bstr_eatend(b, (bstr)bstr0_lit("\n"));
- if (b.len > 0 && b.start[b.len - 1] == '\n')
- b.start[b.len - 1] = '\0';
-
- return ctx->last_text;
+ return *b;
}
static char *get_text(struct sd *sd, double pts, enum sd_text_type type)
{
- return talloc_strdup(NULL, get_text_buf(sd, pts, type));
+ return bstrto0(NULL, get_text_buf(sd, pts, type));
}
static struct sd_times get_times(struct sd *sd, double pts)
@@ -853,20 +875,26 @@ static void fill_plaintext(struct sd *sd, double pts)
ass_flush_events(track);
- char *text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
- if (!text)
+ bstr text = get_text_buf(sd, pts, SD_TEXT_TYPE_PLAIN);
+ if (!text.len)
return;
bstr dst = {0};
- while (*text) {
- if (*text == '{')
+ while (text.len) {
+ if (*text.start == '{') {
+ bstr_xappend(NULL, &dst, bstr0("\\{"));
+ text = bstr_cut(text, 1);
+ } else if (*text.start == '\\') {
bstr_xappend(NULL, &dst, bstr0("\\"));
- bstr_xappend(NULL, &dst, (bstr){text, 1});
- // Break ASS escapes with U+2060 WORD JOINER
- if (*text == '\\')
+ // Break ASS escapes with U+2060 WORD JOINER
mp_append_utf8_bstr(NULL, &dst, 0x2060);
- text++;
+ text = bstr_cut(text, 1);
+ }
+
+ int i = bstrcspn(text, "{\\");
+ bstr_xappend(NULL, &dst, (bstr){text.start, i});
+ text = bstr_cut(text, i);
}
if (!dst.start)
@@ -1094,11 +1122,10 @@ bstr sd_ass_pkt_text(struct sd_filter *ft, struct demux_packet *pkt, int offset)
return txt;
}
-bstr sd_ass_to_plaintext(char *out, size_t out_siz, const char *in)
+bstr sd_ass_to_plaintext(char **out, const char *in)
{
- struct buf b = {out, out_siz, 0};
+ bstr b = {*out};
ass_to_plaintext(&b, in);
- if (b.len < out_siz)
- out[b.len] = 0;
- return (bstr){out, b.len};
+ *out = b.start;
+ return b;
}
diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c
index cf49f2d8f1..6c1bdf550e 100644
--- a/sub/sd_lavc.c
+++ b/sub/sd_lavc.c
@@ -83,6 +83,7 @@ static int init(struct sd *sd)
case AV_CODEC_ID_HDMV_PGS_SUBTITLE:
case AV_CODEC_ID_XSUB:
case AV_CODEC_ID_DVD_SUBTITLE:
+ case AV_CODEC_ID_ARIB_CAPTION:
break;
default:
return -1;
@@ -92,13 +93,31 @@ static int init(struct sd *sd)
AVCodecContext *ctx = NULL;
const AVCodec *sub_codec = avcodec_find_decoder(cid);
if (!sub_codec)
- goto error;
+ goto error_probe;
ctx = avcodec_alloc_context3(sub_codec);
if (!ctx)
- goto error;
+ goto error_probe;
mp_set_avopts(sd->log, ctx, sd->opts->sub_avopts);
+ switch (cid) {
+ case AV_CODEC_ID_DVB_TELETEXT: {
+ int64_t format;
+ int ret = av_opt_get_int(ctx, "txt_format", AV_OPT_SEARCH_CHILDREN, &format);
+ // format == 0 is bitmap
+ if (!ret && format)
+ goto error_probe;
+ break;
+ }
+ case AV_CODEC_ID_ARIB_CAPTION: {
+ int64_t format;
+ int ret = av_opt_get_int(ctx, "sub_type", AV_OPT_SEARCH_CHILDREN, &format);
+ if (!ret && format != SUBTITLE_BITMAP)
+ goto error_probe;
+ break;
+ }
+ }
+
priv->avpkt = av_packet_alloc();
if (!priv->avpkt)
goto error;
@@ -115,8 +134,9 @@ static int init(struct sd *sd)
priv->packer = talloc_zero(priv, struct bitmap_packer);
return 0;
- error:
+error:
MP_FATAL(sd, "Could not open libavcodec subtitle decoder\n");
+error_probe:
avcodec_free_context(&ctx);
mp_free_av_packet(&priv->avpkt);
talloc_free(priv);