summaryrefslogtreecommitdiffstats
path: root/sub/sd_ass.c
diff options
context:
space:
mode:
Diffstat (limited to 'sub/sd_ass.c')
-rw-r--r--sub/sd_ass.c151
1 files changed, 89 insertions, 62 deletions
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index 6fa4d1bb52..41c14623a1 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;
@@ -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;
}