diff options
Diffstat (limited to 'sub/osd_libass.c')
-rw-r--r-- | sub/osd_libass.c | 138 |
1 files changed, 106 insertions, 32 deletions
diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 01c0337eb4..f2de27bd64 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -21,8 +21,6 @@ #include <string.h> #include <assert.h> -#include "config.h" - #include "mpv_talloc.h" #include "misc/bstr.h" #include "common/common.h" @@ -31,7 +29,7 @@ #include "osd_state.h" static const char osd_font_pfb[] = -#include "sub/osd_font.h" +#include "sub/osd_font.otf.inc" ; #include "sub/ass_mp.h" @@ -40,6 +38,9 @@ static const char osd_font_pfb[] = #define ASS_USE_OSD_FONT "{\\fnmpv-osd-symbols}" +static void append_ass(struct ass_state *ass, struct mp_osd_res *res, + ASS_Image **img_list, bool *changed); + void osd_init_backend(struct osd_state *osd) { } @@ -50,7 +51,7 @@ static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass) return; ass->log = mp_log_new(NULL, osd->log, "libass"); - ass->library = mp_ass_init(osd->global, ass->log); + ass->library = mp_ass_init(osd->global, osd->opts->osd_style, ass->log); ass_add_font(ass->library, "mpv-osd-symbols", (void *)osd_font_pfb, sizeof(osd_font_pfb) - 1); @@ -60,7 +61,7 @@ static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass) mp_ass_configure_fonts(ass->render, osd->opts->osd_style, osd->global, ass->log); - ass_set_aspect_ratio(ass->render, 1.0, 1.0); + ass_set_pixel_aspect(ass->render, 1.0); } static void destroy_ass_renderer(struct ass_state *ass) @@ -101,6 +102,8 @@ static void update_playres(struct ass_state *ass, struct mp_osd_res *vo_res) int old_res_x = track->PlayResX; int old_res_y = track->PlayResY; + ass->vo_res = *vo_res; + double aspect = 1.0 * vo_res->w / MPMAX(vo_res->h, 1); if (vo_res->display_par > 0) aspect = aspect / vo_res->display_par; @@ -127,7 +130,10 @@ static void create_ass_track(struct osd_state *osd, struct osd_object *obj, track->Timer = 100.; track->WrapStyle = 1; // end-of-line wrapping instead of smart wrapping track->Kerning = true; - + track->ScaledBorderAndShadow = true; +#if LIBASS_VERSION >= 0x01600010 + ass_track_set_feature(track, ASS_FEATURE_WRAP_UNICODE, 1); +#endif update_playres(ass, &obj->vo_res); } @@ -187,7 +193,7 @@ void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) snprintf(buffer, buffer_size, "\xFF%c", osd_function); } -static void mangle_ass(bstr *dst, const char *in) +void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines) { const char *start = in; bool escape_ass = true; @@ -207,6 +213,14 @@ static void mangle_ass(bstr *dst, const char *in) } if (escape_ass && *in == '{') bstr_xappend(NULL, dst, bstr0("\\")); + // Replace newlines with \N for escape-ass. This is necessary to apply + // ASS tags past newlines and to preserve consecutive newlines with + // osd-overlay because update_external() adds a ASS event per line. + if (replace_newlines && *in == '\n') { + bstr_xappend(NULL, dst, bstr0("\\N")); + in += 1; + continue; + } // Libass will strip leading whitespace if (in[0] == ' ' && (in == start || in[-1] == '\n')) { bstr_xappend(NULL, dst, bstr0("\\h")); @@ -225,7 +239,7 @@ static ASS_Event *add_osd_ass_event_escaped(ASS_Track *track, const char *style, const char *text) { bstr buf = {0}; - mangle_ass(&buf, text); + osd_mangle_ass(&buf, text, false); ASS_Event *e = add_osd_ass_event(track, style, buf.start); talloc_free(buf.start); return e; @@ -262,12 +276,12 @@ static void update_osd_text(struct osd_state *osd, struct osd_object *obj) void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h) { - pthread_mutex_lock(&osd->lock); + mp_mutex_lock(&osd->lock); struct osd_object *obj = osd->objs[OSDTYPE_OSD]; ASS_Style *style = prepare_osd_ass(osd, obj); *out_screen_h = obj->ass.track->PlayResY - style->MarginV; *out_font_h = style->FontSize; - pthread_mutex_unlock(&osd->lock); + mp_mutex_unlock(&osd->lock); } // align: -1 .. +1 @@ -361,15 +375,18 @@ static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj, mp_ass_set_style(style, track->PlayResY, opts->osd_style); + if (osd->opts->osd_style->back_color.a) { + // override the default osd opaque-box into plain outline. Otherwise + // the opaque box is not aligned with the bar (even without shadow), + // and each bar ass event gets its own opaque box - breaking the bar. + style->BackColour = MP_ASS_COLOR(opts->osd_style->shadow_color); + style->BorderStyle = 1; // outline + } + *o_w = track->PlayResX * (opts->osd_bar_w / 100.0); *o_h = track->PlayResY * (opts->osd_bar_h / 100.0); - float base_size = 0.03125; - style->Outline *= *o_h / track->PlayResY / base_size; - // So that the chapter marks have space between them - style->Outline = MPMIN(style->Outline, *o_h / 5.2); - // So that the border is not 0 - style->Outline = MPMAX(style->Outline, *o_h / 32.0); + style->Outline = opts->osd_bar_border_size; // Rendering with shadow is broken (because there's more than one shape) style->Shadow = 0; @@ -410,6 +427,22 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) talloc_free(buf.start); struct ass_draw *d = &(struct ass_draw) { .scale = 4 }; + + if (osd->opts->osd_style->back_color.a) { + // the bar style always ignores the --osd-back-color config - it messes + // up the bar. draw an artificial box at the original back color. + struct m_color bc = osd->opts->osd_style->back_color; + d->text = talloc_asprintf_append(d->text, + "{\\pos(%f,%f)\\bord0\\1a&H%02X\\1c&H%02X%02X%02X&}", + px, py, 255 - bc.a, (int)bc.b, (int)bc.g, (int)bc.r); + + ass_draw_start(d); + ass_draw_rect_cw(d, -border, -border, width + border, height + border); + ass_draw_stop(d); + add_osd_ass_event(track, "progbar", d->text); + ass_draw_reset(d); + } + // filled area d->text = talloc_asprintf_append(d->text, "{\\bord0\\pos(%f,%f)}", px, py); ass_draw_start(d); @@ -441,7 +474,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) // chapter marks for (int n = 0; n < obj->progbar_state.num_stops; n++) { float s = obj->progbar_state.stops[n] * width; - float dent = border * 1.3; + float dent = MPMAX(border * 1.3, 1.6); if (s > dent && s < width - dent) { ass_draw_move_to(d, s + dent, 0); @@ -504,7 +537,7 @@ static int cmp_zorder(const void *pa, const void *pb) void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov) { - pthread_mutex_lock(&osd->lock); + mp_mutex_lock(&osd->lock); struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL]; bool zorder_changed = false; int index = -1; @@ -531,11 +564,18 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov) struct osd_external *entry = obj->externals[index]; if (!ov->format) { + if (!entry->ov.hidden) { + obj->changed = true; + osd->want_redraw_notification = true; + } destroy_external(entry); MP_TARRAY_REMOVE_AT(obj->externals, obj->num_externals, index); + goto done; + } + + if (!entry->ov.hidden || !ov->hidden) { obj->changed = true; osd->want_redraw_notification = true; - goto done; } entry->ov.format = ov->format; @@ -547,24 +587,44 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov) entry->ov.res_y = ov->res_y; zorder_changed |= entry->ov.z != ov->z; entry->ov.z = ov->z; + entry->ov.hidden = ov->hidden; update_external(osd, obj, entry); - obj->changed = true; - osd->want_redraw_notification = true; - if (zorder_changed) { qsort(obj->externals, obj->num_externals, sizeof(obj->externals[0]), cmp_zorder); } + if (ov->out_rc) { + struct mp_osd_res vo_res = entry->ass.vo_res; + // Defined fallback if VO has not drawn this yet + if (vo_res.w < 1 || vo_res.h < 1) { + vo_res = (struct mp_osd_res){ + .w = entry->ov.res_x, + .h = entry->ov.res_y, + .display_par = 1, + }; + // According to osd-overlay command description. + if (vo_res.w < 1) + vo_res.w = 1280; + if (vo_res.h < 1) + vo_res.h = 720; + } + + ASS_Image *img_list = NULL; + append_ass(&entry->ass, &vo_res, &img_list, NULL); + + mp_ass_get_bb(img_list, entry->ass.track, &vo_res, ov->out_rc); + } + done: - pthread_mutex_unlock(&osd->lock); + mp_mutex_unlock(&osd->lock); } void osd_set_external_remove_owner(struct osd_state *osd, void *owner) { - pthread_mutex_lock(&osd->lock); + mp_mutex_lock(&osd->lock); struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL]; for (int n = obj->num_externals - 1; n >= 0; n--) { struct osd_external *e = obj->externals[n]; @@ -575,7 +635,7 @@ void osd_set_external_remove_owner(struct osd_state *osd, void *owner) osd->want_redraw_notification = true; } } - pthread_mutex_unlock(&osd->lock); + mp_mutex_unlock(&osd->lock); } static void append_ass(struct ass_state *ass, struct mp_osd_res *res, @@ -589,15 +649,21 @@ static void append_ass(struct ass_state *ass, struct mp_osd_res *res, update_playres(ass, res); ass_set_frame_size(ass->render, res->w, res->h); - ass_set_aspect_ratio(ass->render, res->display_par, 1.0); + ass_set_pixel_aspect(ass->render, res->display_par); int ass_changed; *img_list = ass_render_frame(ass->render, ass->track, 0, &ass_changed); - *changed |= ass_changed; + + ass->changed |= ass_changed; + + if (changed) { + *changed |= ass->changed; + ass->changed = false; + } } -void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, - int format, struct sub_bitmaps *out_imgs) +struct sub_bitmaps *osd_object_get_bitmaps(struct osd_state *osd, + struct osd_object *obj, int format) { if (obj->type == OSDTYPE_OSD && obj->osd_changed) update_osd(osd, obj); @@ -609,12 +675,20 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, append_ass(&obj->ass, &obj->vo_res, &obj->ass_imgs[0], &obj->changed); for (int n = 0; n < obj->num_externals; n++) { - append_ass(&obj->externals[n]->ass, &obj->vo_res, - &obj->ass_imgs[n + 1], &obj->changed); + if (obj->externals[n]->ov.hidden) { + update_playres(&obj->externals[n]->ass, &obj->vo_res); + obj->ass_imgs[n + 1] = NULL; + } else { + append_ass(&obj->externals[n]->ass, &obj->vo_res, + &obj->ass_imgs[n + 1], &obj->changed); + } } + struct sub_bitmaps out_imgs = {0}; mp_ass_packer_pack(obj->ass_packer, obj->ass_imgs, obj->num_externals + 1, - obj->changed, format, out_imgs); + obj->changed, false, format, &out_imgs); obj->changed = false; + + return sub_bitmaps_copy(&obj->copy_cache, &out_imgs); } |