diff options
Diffstat (limited to 'sub')
-rw-r--r-- | sub/ass_mp.c | 5 | ||||
-rw-r--r-- | sub/dec_sub.c | 25 | ||||
-rw-r--r-- | sub/dec_sub.h | 7 | ||||
-rw-r--r-- | sub/draw_bmp.c | 6 | ||||
-rw-r--r-- | sub/osd_font.otf | bin | 0 -> 2276 bytes | |||
-rw-r--r-- | sub/osd_font.pfb | bin | 8322 -> 0 bytes | |||
-rw-r--r-- | sub/osd_libass.c | 246 | ||||
-rw-r--r-- | sub/sd.h | 1 | ||||
-rw-r--r-- | sub/sd_ass.c | 17 | ||||
-rw-r--r-- | sub/sd_lavc.c | 35 | ||||
-rw-r--r-- | sub/sub.c | 1 | ||||
-rw-r--r-- | sub/sub.h | 10 | ||||
-rw-r--r-- | sub/subassconvert.c | 197 | ||||
-rw-r--r-- | sub/subreader.c | 13 | ||||
-rw-r--r-- | sub/subreader.h | 1 |
15 files changed, 439 insertions, 125 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 2312eaeff5..497e307953 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -69,6 +69,9 @@ void mp_ass_set_style(ASS_Style *style, struct osd_style_opts *opts) style->MarginV = opts->margin_y * scale; style->ScaleX = 1.; style->ScaleY = 1.; +#if LIBASS_VERSION >= 0x01020000 + style->Blur = opts->blur; +#endif } ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts) @@ -267,7 +270,9 @@ void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts) default_font = NULL; } + mp_msg(MSGT_ASS, MSGL_V, "[ass] Setting up fonts...\n"); ass_set_fonts(priv, default_font, opts->font, 1, config, 1); + mp_msg(MSGT_ASS, MSGL_V, "[ass] Done.\n"); talloc_free(default_font); talloc_free(config); diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 4e703e7dc0..d3cedea80d 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -30,17 +30,36 @@ extern const struct sd_functions sd_ass; extern const struct sd_functions sd_lavc; +bool is_text_sub(const char *t) +{ + return t && (is_ass_sub(t) || + strcmp(t, "text") == 0 || + strcmp(t, "subrip") == 0 || + strcmp(t, "mov_text") == 0); +} + +bool is_ass_sub(const char *t) +{ + return t && (strcmp(t, "ass") == 0 || + strcmp(t, "ssa") == 0); +} + +bool is_dvd_sub(const char *t) +{ + return t && strcmp(t, "dvd_subtitle") == 0; +} + void sub_init(struct sh_sub *sh, struct osd_state *osd) { struct MPOpts *opts = sh->opts; assert(!osd->sh_sub); + if (sd_lavc.probe(sh)) + sh->sd_driver = &sd_lavc; #ifdef CONFIG_ASS - if (opts->ass_enabled && is_text_sub(sh->type)) + if (opts->ass_enabled && sd_ass.probe(sh)) sh->sd_driver = &sd_ass; #endif - if (strchr("bpxv", sh->type)) - sh->sd_driver = &sd_lavc; if (sh->sd_driver) { if (sh->sd_driver->init(sh, osd) < 0) return; diff --git a/sub/dec_sub.h b/sub/dec_sub.h index f66f05c021..593eac1e03 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -10,10 +10,9 @@ struct sh_sub; struct ass_track; struct MPOpts; -static inline bool is_text_sub(int type) -{ - return type == 't' || type == 'm' || type == 'a'; -} +bool is_text_sub(const char *t); +bool is_ass_sub(const char *t); +bool is_dvd_sub(const char *t); void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration); diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 09068dba89..4057500f01 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -287,8 +287,10 @@ static void draw_ass(struct mp_draw_sub_cache *cache, struct mp_rect bb, cspar.int_bits_out = 8; float yuv2rgb[3][4], rgb2yuv[3][4]; - mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb); - mp_invert_yuv2rgb(rgb2yuv, yuv2rgb); + if (temp->flags & MP_IMGFLAG_YUV) { + mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb); + mp_invert_yuv2rgb(rgb2yuv, yuv2rgb); + } for (int i = 0; i < sbs->num_parts; ++i) { struct sub_bitmap *sb = &sbs->parts[i]; diff --git a/sub/osd_font.otf b/sub/osd_font.otf Binary files differnew file mode 100644 index 0000000000..d8ebec0ad8 --- /dev/null +++ b/sub/osd_font.otf diff --git a/sub/osd_font.pfb b/sub/osd_font.pfb Binary files differdeleted file mode 100644 index a4a65a143b..0000000000 --- a/sub/osd_font.pfb +++ /dev/null diff --git a/sub/osd_libass.c b/sub/osd_libass.c index bbd925f135..495bce2b73 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -54,6 +54,12 @@ void osd_init_backend(struct osd_state *osd) void osd_destroy_backend(struct osd_state *osd) { + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osd_object *obj = osd->objs[n]; + if (obj->osd_track) + ass_free_track(obj->osd_track); + obj->osd_track = NULL; + } if (osd->osd_render) ass_renderer_done(osd->osd_render); osd->osd_render = NULL; @@ -61,14 +67,19 @@ void osd_destroy_backend(struct osd_state *osd) osd->osd_ass_library = NULL; } -static ASS_Track *create_osd_ass_track(struct osd_state *osd) +static void create_osd_ass_track(struct osd_state *osd, struct osd_object *obj) { - ASS_Track *track = ass_new_track(osd->osd_ass_library); + ASS_Track *track = obj->osd_track; + if (!track) + track = ass_new_track(osd->osd_ass_library); + + double aspect = 1.0 * obj->vo_res.w / FFMAX(obj->vo_res.h, 1) / + obj->vo_res.display_par; track->track_type = TRACK_TYPE_ASS; track->Timer = 100.; track->PlayResY = MP_ASS_FONT_PLAYRESY; - track->PlayResX = track->PlayResY * 1.33333; + track->PlayResX = track->PlayResY * aspect; track->WrapStyle = 1; // end-of-line wrapping instead of smart wrapping if (track->n_styles == 0) { @@ -83,18 +94,19 @@ static ASS_Track *create_osd_ass_track(struct osd_state *osd) style->Encoding = -1; } - return track; + obj->osd_track = track; } -static ASS_Event *get_osd_ass_event(ASS_Track *track) +static ASS_Event *add_osd_ass_event(ASS_Track *track, const char *text) { - ass_flush_events(track); - ass_alloc_event(track); - ASS_Event *event = track->events + 0; + int n = ass_alloc_event(track); + ASS_Event *event = track->events + n; event->Start = 0; event->Duration = 100; event->Style = track->default_style; assert(event->Text == NULL); + if (text) + event->Text = strdup(text); return event; } @@ -135,67 +147,135 @@ static char *mangle_ass(const char *in) static void update_osd(struct osd_state *osd, struct osd_object *obj) { - if (!osd->osd_text[0]) { - clear_obj(obj); + create_osd_ass_track(osd, obj); + clear_obj(obj); + if (!osd->osd_text[0]) return; - } - if (!obj->osd_track) - obj->osd_track = create_osd_ass_track(osd); - ASS_Event *event = get_osd_ass_event(obj->osd_track); char *text = mangle_ass(osd->osd_text); - event->Text = strdup(text); + add_osd_ass_event(obj->osd_track, text); talloc_free(text); } -static int get_align(float val, int res, int *out_margin) +// align: -1 .. +1 +// frame: size of the containing area +// obj: size of the object that should be positioned inside the area +// margin: min. distance from object to frame (as long as -1 <= align <= +1) +static float get_align(float align, float frame, float obj, float margin) { - *out_margin = FFMAX(0, (1.0 - fabs(val)) * res / 2); - if (fabs(val) < 0.1) - return 1; // centered - return val > 0 ? 2 : 0; // bottom / top (or right / left) + frame -= margin * 2; + return margin + frame / 2 - obj / 2 + (frame - obj) / 2 * align; } -static const int ass_align_x[3] = {1, 2, 3}; -static const int ass_align_y[3] = {4, 8, 0}; +struct ass_draw { + int scale; + char *text; +}; + +static void ass_draw_start(struct ass_draw *d) +{ + d->scale = FFMAX(d->scale, 1); + d->text = talloc_asprintf_append(d->text, "{\\p%d}", d->scale); +} -#define OSDBAR_ELEMS 46 +static void ass_draw_stop(struct ass_draw *d) +{ + d->text = talloc_strdup_append(d->text, "{\\p0}"); +} -static void update_progbar(struct osd_state *osd, struct osd_object *obj) +static void ass_draw_c(struct ass_draw *d, float x, float y) +{ + int ix = round(x * (1 << (d->scale - 1))); + int iy = round(y * (1 << (d->scale - 1))); + d->text = talloc_asprintf_append(d->text, " %d %d", ix, iy); +} + +static void ass_draw_append(struct ass_draw *d, const char *t) +{ + d->text = talloc_strdup_append(d->text, t); +} + +static void ass_draw_move_to(struct ass_draw *d, float x, float y) +{ + ass_draw_append(d, " m"); + ass_draw_c(d, x, y); +} + +static void ass_draw_line_to(struct ass_draw *d, float x, float y) +{ + ass_draw_append(d, " l"); + ass_draw_c(d, x, y); +} + +static void ass_draw_rect_ccw(struct ass_draw *d, float x0, float y0, + float x1, float y1) +{ + ass_draw_move_to(d, x0, y0); + ass_draw_line_to(d, x0, y1); + ass_draw_line_to(d, x1, y1); + ass_draw_line_to(d, x1, y0); +} + +static void ass_draw_rect_cw(struct ass_draw *d, float x0, float y0, + float x1, float y1) +{ + ass_draw_move_to(d, x0, y0); + ass_draw_line_to(d, x1, y0); + ass_draw_line_to(d, x1, y1); + ass_draw_line_to(d, x0, y1); +} + +static void ass_draw_reset(struct ass_draw *d) +{ + talloc_free(d->text); + d->text = NULL; +} + +static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj, + float *o_x, float *o_y, float *o_w, float *o_h, + float *o_border) { struct MPOpts *opts = osd->opts; - if (osd->progbar_type < 0) { - clear_obj(obj); - return; + bool new_track = !obj->osd_track; + create_osd_ass_track(osd, obj); + ASS_Track *track = obj->osd_track; + ASS_Style *style = track->styles + track->default_style; + + *o_w = track->PlayResX * (opts->osd_bar_w / 100.0); + *o_h = track->PlayResY * (opts->osd_bar_h / 100.0); + + if (new_track) { + float base_size = 0.03125; + style->Outline *= *o_h / track->PlayResY / base_size; + // So that the chapter marks have space between them + style->Outline = FFMIN(style->Outline, *o_h / 5.2); + // So that the border is not 0 + style->Outline = FFMAX(style->Outline, *o_h / 32.0); + // Rendering with shadow is broken (because there's more than one shape) + style->Shadow = 0; } - if (!obj->osd_track) - obj->osd_track = create_osd_ass_track(osd); + *o_border = style->Outline; - ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; + *o_x = get_align(opts->osd_bar_align_x, track->PlayResX, *o_w, *o_border); + *o_y = get_align(opts->osd_bar_align_y, track->PlayResY, *o_h, *o_border); +} + +static void update_progbar(struct osd_state *osd, struct osd_object *obj) +{ + float px, py, width, height, border; + get_osd_bar_box(osd, obj, &px, &py, &width, &height, &border); - int ax = get_align(opts->osd_bar_align_x, obj->osd_track->PlayResX, - &style->MarginR); - int ay = get_align(opts->osd_bar_align_y, obj->osd_track->PlayResY, - &style->MarginV); - style->Alignment = ass_align_x[ax] + ass_align_y[ay]; - style->MarginL = style->MarginR; + clear_obj(obj); - // We need a fixed font size with respect to the OSD width. - // Assume the OSD bar takes 2/3 of the OSD width at PlayResY=288 and - // FontSize=22 with an OSD aspect ratio of 16:9. Rescale as needed. - // xxx can fail when unknown fonts are involved - double asp = (double)obj->vo_res.w / obj->vo_res.h; - double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0); - style->ScaleX = style->ScaleY = scale; - style->FontSize = 22.0; - style->Outline = style->FontSize / 16 * scale; + if (osd->progbar_type < 0) + return; - int active = (osd->progbar_value * OSDBAR_ELEMS + 255) / 256; - active = FFMIN(OSDBAR_ELEMS, FFMAX(active, 0)); + float sx = px - border * 2 - height / 4; // includes additional spacing + float sy = py + height / 2; - char *text = talloc_strdup(NULL, "{\\q2}"); + char *text = talloc_asprintf(NULL, "{\\an6\\pos(%f,%f)}", sx, sy); if (osd->progbar_type == 0 || osd->progbar_type >= 256) { // no sym @@ -207,30 +287,67 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) text = talloc_strdup_append_buffer(text, "{\\r}"); } - //xxx space in normal font, because OSD font doesn't have a space - text = talloc_strdup_append_buffer(text, "\\h"); - text = talloc_strdup_append_buffer(text, ASS_USE_OSD_FONT); + add_osd_ass_event(obj->osd_track, text); + talloc_free(text); - text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_START); - for (int n = 0; n < active; n++) - text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_0); - for (int n = 0; n < OSDBAR_ELEMS - active; n++) - text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_1); - text = mp_append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_END); + struct ass_draw *d = &(struct ass_draw) { .scale = 4 }; + // filled area + d->text = talloc_asprintf_append(d->text, "{\\bord0\\pos(%f,%f)}", px, py); + ass_draw_start(d); + float pos = osd->progbar_value * width - border / 2; + ass_draw_rect_cw(d, 0, 0, pos, height); + ass_draw_stop(d); + add_osd_ass_event(obj->osd_track, d->text); + ass_draw_reset(d); + + // position marker + d->text = talloc_asprintf_append(d->text, "{\\bord%f\\pos(%f,%f)}", + border / 2, px, py); + ass_draw_start(d); + ass_draw_move_to(d, pos + border / 2, 0); + ass_draw_line_to(d, pos + border / 2, height); + ass_draw_stop(d); + add_osd_ass_event(obj->osd_track, d->text); + ass_draw_reset(d); + + d->text = talloc_asprintf_append(d->text, "{\\pos(%f,%f)}", px, py); + ass_draw_start(d); + + // the box + ass_draw_rect_cw(d, -border, -border, width + border, height + border); + + // the "hole" + ass_draw_rect_ccw(d, 0, 0, width, height); + + // chapter marks + for (int n = 0; n < osd->progbar_num_stops; n++) { + float s = osd->progbar_stops[n] * width; + float dent = border * 1.3; + + if (s > dent && s < width - dent) { + ass_draw_move_to(d, s + dent, 0); + ass_draw_line_to(d, s, dent); + ass_draw_line_to(d, s - dent, 0); + + ass_draw_move_to(d, s - dent, height); + ass_draw_line_to(d, s, height - dent); + ass_draw_line_to(d, s + dent, height); + } + } - ASS_Event *event = get_osd_ass_event(obj->osd_track); - event->Text = strdup(text); - talloc_free(text); + ass_draw_stop(d); + add_osd_ass_event(obj->osd_track, d->text); + ass_draw_reset(d); } static void update_sub(struct osd_state *osd, struct osd_object *obj) { struct MPOpts *opts = osd->opts; - if (!(vo_sub && opts->sub_visibility)) { - clear_obj(obj); + clear_obj(obj); + + if (!(vo_sub && opts->sub_visibility)) return; - } if (!obj->osd_track) obj->osd_track = mp_ass_default_track(osd->osd_ass_library, osd->opts); @@ -250,9 +367,8 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj) for (int n = 0; n < vo_sub->lines; n++) text = talloc_asprintf_append_buffer(text, "%s\n", vo_sub->text[n]); - ASS_Event *event = get_osd_ass_event(obj->osd_track); char *escaped_text = mangle_ass(text); - event->Text = strdup(escaped_text); + add_osd_ass_event(obj->osd_track, escaped_text); talloc_free(escaped_text); talloc_free(text); } @@ -4,6 +4,7 @@ #include "dec_sub.h" struct sd_functions { + bool (*probe)(struct sh_sub *sh); int (*init)(struct sh_sub *sh, struct osd_state *osd); void (*decode)(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration); diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 00f2f8d796..8d17835809 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -41,6 +41,11 @@ struct sd_ass_priv { bool flush_on_seek; }; +static bool probe(struct sh_sub *sh) +{ + return is_text_sub(sh->gsh->codec); +} + static void free_last_event(ASS_Track *track) { assert(track->n_events > 0); @@ -51,13 +56,14 @@ static void free_last_event(ASS_Track *track) static int init(struct sh_sub *sh, struct osd_state *osd) { struct sd_ass_priv *ctx; + bool ass = is_ass_sub(sh->gsh->codec); if (sh->initialized) { ctx = sh->context; } else { ctx = talloc_zero(NULL, struct sd_ass_priv); sh->context = ctx; - if (sh->type == 'a') { + if (ass) { ctx->ass_track = ass_new_track(osd->ass_library); if (sh->extradata) ass_process_codec_private(ctx->ass_track, sh->extradata, @@ -66,7 +72,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd) ctx->ass_track = mp_ass_default_track(osd->ass_library, sh->opts); } - ctx->vsfilter_aspect = sh->type == 'a'; + ctx->vsfilter_aspect = ass; return 0; } @@ -77,7 +83,7 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, struct sd_ass_priv *ctx = sh->context; ASS_Track *track = ctx->ass_track; - if (sh->type == 'a') { // ssa/ass subs + if (is_ass_sub(sh->gsh->codec)) { if (bstr_startswith0((bstr){data, data_len}, "Dialogue: ")) { // broken ffmpeg ASS packet format ctx->flush_on_seek = true; @@ -177,6 +183,7 @@ static void uninit(struct sh_sub *sh) } const struct sd_functions sd_ass = { + .probe = probe, .init = init, .decode = decode, .get_bitmaps = get_bitmaps, @@ -199,7 +206,9 @@ struct sh_sub *sd_ass_create_from_track(struct ass_track *track, talloc_set_destructor(sh, sd_ass_track_destructor); *sh = (struct sh_sub) { .opts = opts, - .type = 'a', + .gsh = talloc_struct(sh, struct sh_stream, { + .codec = "ass", + }), .sd_driver = &sd_ass, .context = talloc_struct(sh, struct sd_ass_priv, { .ass_track = track, diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index f1f93b480e..1665e36749 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -22,6 +22,7 @@ #include "talloc.h" #include "core/mp_msg.h" +#include "core/av_common.h" #include "demux/stheader.h" #include "sd.h" #include "dec_sub.h" @@ -40,9 +41,24 @@ struct sd_lavc_priv { double endpts; }; -static void guess_resolution(char type, int *w, int *h) +static bool probe(struct sh_sub *sh) { - if (type == 'v') { + enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec); + // Supported codecs must be known to decode to paletted bitmaps + switch (cid) { + case AV_CODEC_ID_DVB_SUBTITLE: + case AV_CODEC_ID_HDMV_PGS_SUBTITLE: + case AV_CODEC_ID_XSUB: + case AV_CODEC_ID_DVD_SUBTITLE: + return true; + default: + return false; + } +} + +static void guess_resolution(enum AVCodecID type, int *w, int *h) +{ + if (type == AV_CODEC_ID_DVD_SUBTITLE) { /* XXX Although the video frame is some size, the SPU frame is always maximum size i.e. 720 wide and 576 or 480 high */ // For HD files in MKV the VobSub resolution can be higher though, @@ -65,17 +81,7 @@ static int init(struct sh_sub *sh, struct osd_state *osd) if (sh->initialized) return 0; struct sd_lavc_priv *priv = talloc_zero(NULL, struct sd_lavc_priv); - enum CodecID cid = CODEC_ID_NONE; - switch (sh->type) { - case 'b': - cid = CODEC_ID_DVB_SUBTITLE; break; - case 'p': - cid = CODEC_ID_HDMV_PGS_SUBTITLE; break; - case 'x': - cid = CODEC_ID_XSUB; break; - case 'v': - cid = CODEC_ID_DVD_SUBTITLE; break; - } + enum AVCodecID cid = mp_codec_to_av_codec_id(sh->gsh->codec); AVCodecContext *ctx = NULL; AVCodec *sub_codec = avcodec_find_decoder(cid); if (!sub_codec) @@ -194,7 +200,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, talloc_get_size(priv->inbitmaps)); int inw = priv->avctx->width; int inh = priv->avctx->height; - guess_resolution(sh->type, &inw, &inh); + guess_resolution(priv->avctx->codec_id, &inw, &inh); double xscale = (double) (d.w - d.ml - d.mr) / inw; double yscale = (double) (d.h - d.mt - d.mb) / inh; for (int i = 0; i < priv->count; i++) { @@ -235,6 +241,7 @@ static void uninit(struct sh_sub *sh) } const struct sd_functions sd_lavc = { + .probe = probe, .init = init, .decode = decode, .get_bitmaps = get_bitmaps, @@ -79,6 +79,7 @@ const struct m_sub_options osd_style_conf = { OPT_FLOATRANGE("spacing", spacing, 0, -10, 10), OPT_INTRANGE("margin-x", margin_x, 0, 0, 300), OPT_INTRANGE("margin-y", margin_y, 0, 0, 600), + OPT_FLOATRANGE("blur", blur, 0, 0, 20), {0} }, .size = sizeof(struct osd_style_opts), @@ -129,8 +129,13 @@ struct osd_state { bool want_redraw; - char *osd_text; // OSDTYPE_OSD - int progbar_type, progbar_value; // OSDTYPE_PROGBAR + // OSDTYPE_OSD + char *osd_text; + // OSDTYPE_PROGBAR + int progbar_type; // <0: disabled, 1-255: symbol, else: no symbol + float progbar_value; // range 0.0-1.0 + float *progbar_stops; // used for chapter indicators (0.0-1.0 each) + int progbar_num_stops; int switch_sub_id; @@ -187,6 +192,7 @@ struct osd_style_opts { float spacing; int margin_x; int margin_y; + float blur; }; extern const struct m_sub_options osd_style_conf; diff --git a/sub/subassconvert.c b/sub/subassconvert.c index 1d05096c15..c665750682 100644 --- a/sub/subassconvert.c +++ b/sub/subassconvert.c @@ -55,6 +55,11 @@ static void append_text(struct line *dst, char *fmt, ...) va_end(va); } +static void append_text_n(struct line *dst, char *start, size_t length) +{ + append_text(dst, "%.*s", (int)length, start); +} + static int indexof(const char *s, int c) { char *f = strchr(s, c); @@ -88,7 +93,7 @@ static const struct tag_conv { {"<b>", "{\\b1}"}, {"</b>", "{\\b0}"}, {"<u>", "{\\u1}"}, {"</u>", "{\\u0}"}, {"<s>", "{\\s1}"}, {"</s>", "{\\s0}"}, - {"{", "\\{"}, {"}", "\\}"}, + {"}", "\\}"}, {"\r\n", "\\N"}, {"\n", "\\N"}, {"\r", "\\N"}, }; @@ -96,29 +101,155 @@ static const struct { char *s; uint32_t v; } subrip_web_colors[] = { - /* Named CSS3 colors in BGR format; a subset of those + /* Named CSS3 colors in RGB format; a subset of those at http://www.w3.org/TR/css3-color/#svg-color */ - {"aqua", 0xffff00}, - {"black", 0x000000}, - {"blue", 0xff0000}, - {"cyan", 0xffff00}, - {"fuchsia", 0xff00ff}, - {"gray", 0x808080}, - {"green", 0x008000}, - {"grey", 0x808080}, - {"lime", 0x00ff00}, - {"magenta", 0xff00ff}, - {"maroon", 0x000080}, - {"navy", 0x800000}, - {"olive", 0x008080}, - {"orange", 0x00a5ff}, - {"pink", 0xcbc0ff}, - {"purple", 0x800080}, - {"red", 0x0000ff}, - {"silver", 0xc0c0c0}, - {"teal", 0x808000}, - {"white", 0xffffff}, - {"yellow", 0x00ffff}, + {"aliceblue", 0xF0F8FF}, + {"antiquewhite", 0xFAEBD7}, + {"aqua", 0x00FFFF}, + {"aquamarine", 0x7FFFD4}, + {"azure", 0xF0FFFF}, + {"beige", 0xF5F5DC}, + {"bisque", 0xFFE4C4}, + {"black", 0x000000}, + {"blanchedalmond", 0xFFEBCD}, + {"blue", 0x0000FF}, + {"blueviolet", 0x8A2BE2}, + {"brown", 0xA52A2A}, + {"burlywood", 0xDEB887}, + {"cadetblue", 0x5F9EA0}, + {"chartreuse", 0x7FFF00}, + {"chocolate", 0xD2691E}, + {"coral", 0xFF7F50}, + {"cornflowerblue", 0x6495ED}, + {"cornsilk", 0xFFF8DC}, + {"crimson", 0xDC143C}, + {"cyan", 0x00FFFF}, + {"darkblue", 0x00008B}, + {"darkcyan", 0x008B8B}, + {"darkgoldenrod", 0xB8860B}, + {"darkgray", 0xA9A9A9}, + {"darkgreen", 0x006400}, + {"darkgrey", 0xA9A9A9}, + {"darkkhaki", 0xBDB76B}, + {"darkmagenta", 0x8B008B}, + {"darkolivegreen", 0x556B2F}, + {"darkorange", 0xFF8C00}, + {"darkorchid", 0x9932CC}, + {"darkred", 0x8B0000}, + {"darksalmon", 0xE9967A}, + {"darkseagreen", 0x8FBC8F}, + {"darkslateblue", 0x483D8B}, + {"darkslategray", 0x2F4F4F}, + {"darkslategrey", 0x2F4F4F}, + {"darkturquoise", 0x00CED1}, + {"darkviolet", 0x9400D3}, + {"deeppink", 0xFF1493}, + {"deepskyblue", 0x00BFFF}, + {"dimgray", 0x696969}, + {"dimgrey", 0x696969}, + {"dodgerblue", 0x1E90FF}, + {"firebrick", 0xB22222}, + {"floralwhite", 0xFFFAF0}, + {"forestgreen", 0x228B22}, + {"fuchsia", 0xFF00FF}, + {"gainsboro", 0xDCDCDC}, + {"ghostwhite", 0xF8F8FF}, + {"gold", 0xFFD700}, + {"goldenrod", 0xDAA520}, + {"gray", 0x808080}, + {"green", 0x008000}, + {"greenyellow", 0xADFF2F}, + {"grey", 0x808080}, + {"honeydew", 0xF0FFF0}, + {"hotpink", 0xFF69B4}, + {"indianred", 0xCD5C5C}, + {"indigo", 0x4B0082}, + {"ivory", 0xFFFFF0}, + {"khaki", 0xF0E68C}, + {"lavender", 0xE6E6FA}, + {"lavenderblush", 0xFFF0F5}, + {"lawngreen", 0x7CFC00}, + {"lemonchiffon", 0xFFFACD}, + {"lightblue", 0xADD8E6}, + {"lightcoral", 0xF08080}, + {"lightcyan", 0xE0FFFF}, + {"lightgoldenrodyellow", 0xFAFAD2}, + {"lightgray", 0xD3D3D3}, + {"lightgreen", 0x90EE90}, + {"lightgrey", 0xD3D3D3}, + {"lightpink", 0xFFB6C1}, + {"lightsalmon", 0xFFA07A}, + {"lightseagreen", 0x20B2AA}, + {"lightskyblue", 0x87CEFA}, + {"lightslategray", 0x778899}, + {"lightslategrey", 0x778899}, + {"lightsteelblue", 0xB0C4DE}, + {"lightyellow", 0xFFFFE0}, + {"lime", 0x00FF00}, + {"limegreen", 0x32CD32}, + {"linen", 0xFAF0E6}, + {"magenta", 0xFF00FF}, + {"maroon", 0x800000}, + {"mediumaquamarine", 0x66CDAA}, + {"mediumblue", 0x0000CD}, + {"mediumorchid", 0xBA55D3}, + {"mediumpurple", 0x9370DB}, + {"mediumseagreen", 0x3CB371}, + {"mediumslateblue", 0x7B68EE}, + {"mediumspringgreen", 0x00FA9A}, + {"mediumturquoise", 0x48D1CC}, + {"mediumvioletred", 0xC71585}, + {"midnightblue", 0x191970}, + {"mintcream", 0xF5FFFA}, + {"mistyrose", 0xFFE4E1}, + {"moccasin", 0xFFE4B5}, + {"navajowhite", 0xFFDEAD}, + {"navy", 0x000080}, + {"oldlace", 0xFDF5E6}, + {"olive", 0x808000}, + {"olivedrab", 0x6B8E23}, + {"orange", 0xFFA500}, + {"orangered", 0xFF4500}, + {"orchid", 0xDA70D6}, + {"palegoldenrod", 0xEEE8AA}, + {"palegreen", 0x98FB98}, + {"paleturquoise", 0xAFEEEE}, + {"palevioletred", 0xDB7093}, + {"papayawhip", 0xFFEFD5}, + {"peachpuff", 0xFFDAB9}, + {"peru", 0xCD853F}, + {"pink", 0xFFC0CB}, + {"plum", 0xDDA0DD}, + {"powderblue", 0xB0E0E6}, + {"purple", 0x800080}, + {"red", 0xFF0000}, + {"rosybrown", 0xBC8F8F}, + {"royalblue", 0x4169E1}, + {"saddlebrown", 0x8B4513}, + {"salmon", 0xFA8072}, + {"sandybrown", 0xF4A460}, + {"seagreen", 0x2E8B57}, + {"seashell", 0xFFF5EE}, + {"sienna", 0xA0522D}, + {"silver", 0xC0C0C0}, + {"skyblue", 0x87CEEB}, + {"slateblue", 0x6A5ACD}, + {"slategray", 0x708090}, + {"slategrey", 0x708090}, + {"snow", 0xFFFAFA}, + {"springgreen", 0x00FF7F}, + {"steelblue", 0x4682B4}, + {"tan", 0xD2B48C}, + {"teal", 0x008080}, + {"thistle", 0xD8BFD8}, + {"tomato", 0xFF6347}, + {"turquoise", 0x40E0D0}, + {"violet", 0xEE82EE}, + {"wheat", 0xF5DEB3}, + {"white", 0xFFFFFF}, + {"whitesmoke", 0xF5F5F5}, + {"yellow", 0xFFFF00}, + {"yellowgreen", 0x9ACD32}, }; #define SUBRIP_MAX_STACKED_FONT_TAGS 16 @@ -238,7 +369,10 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size) for (int i = 0; i < FF_ARRAY_ELEMS(subrip_web_colors); i++) { char *color = subrip_web_colors[i].s; if (bstrcasecmp(val, bstr0(color)) == 0) { - tag->color = subrip_web_colors[i].v; + uint32_t color = subrip_web_colors[i].v; + tag->color = ((color & 0xff) << 16) + | (color & 0xff00) + | ((color & 0xff0000) >> 16); found = 1; } } @@ -264,7 +398,7 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size) } else { // We didn't find any matching color mp_tmsg(MSGT_SUBREADER, MSGL_WARN, - "SubRip: unknown font color in subtitle: %s\n", + "SubRip: unknown font color in subtitle: >%s<\n", orig); append_text(&new_line, "{\\c}"); } @@ -288,6 +422,19 @@ void subassconvert_subrip(const char *orig, char *dest, int dest_buffer_size) sp++; line++; } + } else if (*line == '{') { + char *end = strchr(line, '}'); + if (line[1] == '\\' && end) { + // Likely ASS tag, pass them through + // Note that ASS tags like {something\an8} are legal too (i.e. + // the first character after '{' doesn't have to be '\'), but + // consider these fringe cases not worth supporting. + append_text_n(&new_line, line, end - line + 1); + line = end + 1; + } else { + append_text(&new_line, "\\{"); + line++; + } } /* Tag conversion code didn't match */ |