diff options
Diffstat (limited to 'sub/sd_ass.c')
-rw-r--r-- | sub/sd_ass.c | 151 |
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; } |