diff options
Diffstat (limited to 'sub/osd_libass.c')
-rw-r--r-- | sub/osd_libass.c | 209 |
1 files changed, 130 insertions, 79 deletions
diff --git a/sub/osd_libass.c b/sub/osd_libass.c index eed2822380..30d404d8c6 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -45,49 +45,66 @@ void osd_init_backend(struct osd_state *osd) { } -static void create_ass_renderer(struct osd_state *osd, struct osd_object *obj) +static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass) { - if (obj->osd_render) + if (ass->render) return; - struct mp_log *ass_log = mp_log_new(obj, osd->log, "libass"); - obj->osd_ass_library = mp_ass_init(osd->global, ass_log); - ass_add_font(obj->osd_ass_library, "mpv-osd-symbols", (void *)osd_font_pfb, + ass->log = mp_log_new(NULL, osd->log, "libass"); + ass->library = mp_ass_init(osd->global, ass->log); + ass_add_font(ass->library, "mpv-osd-symbols", (void *)osd_font_pfb, sizeof(osd_font_pfb) - 1); - obj->osd_render = ass_renderer_init(obj->osd_ass_library); - if (!obj->osd_render) + ass->render = ass_renderer_init(ass->library); + if (!ass->render) abort(); - mp_ass_configure_fonts(obj->osd_render, osd->opts->osd_style, - osd->global, ass_log); - ass_set_aspect_ratio(obj->osd_render, 1.0, 1.0); + mp_ass_configure_fonts(ass->render, osd->opts->osd_style, + osd->global, ass->log); + ass_set_aspect_ratio(ass->render, 1.0, 1.0); +} + +static void destroy_ass_renderer(struct ass_state *ass) +{ + if (ass->track) + ass_free_track(ass->track); + ass->track = NULL; + if (ass->render) + ass_renderer_done(ass->render); + ass->render = NULL; + if (ass->library) + ass_library_done(ass->library); + ass->library = NULL; + talloc_free(ass->log); + ass->log = NULL; +} + +static void destroy_external(struct osd_external *ext) +{ + talloc_free(ext->text); + destroy_ass_renderer(&ext->ass); } 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 (obj->osd_render) - ass_renderer_done(obj->osd_render); - obj->osd_render = NULL; - if (obj->osd_ass_library) - ass_library_done(obj->osd_ass_library); - obj->osd_ass_library = NULL; + destroy_ass_renderer(&obj->ass); + talloc_free(obj->parts_cache.parts); + for (int i = 0; i < obj->num_externals; i++) + destroy_external(&obj->externals[i]); + obj->num_externals = 0; } } static void create_ass_track(struct osd_state *osd, struct osd_object *obj, - int res_x, int res_y) + struct ass_state *ass, int res_x, int res_y) { - create_ass_renderer(osd, obj); + create_ass_renderer(osd, ass); - ASS_Track *track = obj->osd_track; + ASS_Track *track = ass->track; if (!track) - track = ass_new_track(obj->osd_ass_library); + track = ass_new_track(ass->library); int old_res_x = track->PlayResX; int old_res_y = track->PlayResY; @@ -105,9 +122,9 @@ static void create_ass_track(struct osd_state *osd, struct osd_object *obj, // Force libass to clear its internal cache - it doesn't check for // PlayRes changes itself. if (old_res_x != track->PlayResX || old_res_y != track->PlayResY) - ass_set_frame_size(obj->osd_render, 1, 1); + ass_set_frame_size(ass->render, 1, 1); - obj->osd_track = track; + ass->track = track; } static int find_style(ASS_Track *track, const char *name, int def) @@ -120,10 +137,9 @@ static int find_style(ASS_Track *track, const char *name, int def) } // Find a given style, or add it if it's missing. -static ASS_Style *get_style(struct osd_state *osd, struct osd_object *obj, - char *name) +static ASS_Style *get_style(struct ass_state *ass, char *name) { - ASS_Track *track = obj->osd_track; + ASS_Track *track = ass->track; if (!track) return NULL; @@ -154,10 +170,10 @@ static ASS_Event *add_osd_ass_event(ASS_Track *track, const char *style, return event; } -static void clear_obj(struct osd_object *obj) +static void clear_ass(struct ass_state *ass) { - if (obj->osd_track) - ass_flush_events(obj->osd_track); + if (ass->track) + ass_flush_events(ass->track); } void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) @@ -214,18 +230,18 @@ static void update_osd_text(struct osd_state *osd, struct osd_object *obj) if (!obj->text[0]) return; - create_ass_track(osd, obj, 0, 0); + create_ass_track(osd, obj, &obj->ass, 0, 0); struct osd_style_opts font = *opts->osd_style; font.font_size *= opts->osd_scale; - double playresy = obj->osd_track->PlayResY; + double playresy = obj->ass.track->PlayResY; // Compensate for libass and mp_ass_set_style scaling the font etc. if (!opts->osd_scale_by_window) playresy *= 720.0 / obj->vo_res.h; - mp_ass_set_style(get_style(osd, obj, "OSD"), playresy, &font); - add_osd_ass_event_escaped(obj->osd_track, "OSD", obj->text); + mp_ass_set_style(get_style(&obj->ass, "OSD"), playresy, &font); + add_osd_ass_event_escaped(obj->ass.track, "OSD", obj->text); } // align: -1 .. +1 @@ -308,10 +324,10 @@ static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj, { struct MPOpts *opts = osd->opts; - create_ass_track(osd, obj, 0, 0); - ASS_Track *track = obj->osd_track; + create_ass_track(osd, obj, &obj->ass, 0, 0); + ASS_Track *track = obj->ass.track; - ASS_Style *style = get_style(osd, obj, "progbar"); + ASS_Style *style = get_style(&obj->ass, "progbar"); if (!style) { *o_x = *o_y = *o_w = *o_h = *o_border = 0; return; @@ -347,6 +363,8 @@ 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); + ASS_Track *track = obj->ass.track; + float sx = px - border * 2 - height / 4; // includes additional spacing float sy = py + height / 2; @@ -362,7 +380,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) bstr_xappend(NULL, &buf, bstr0("{\\r}")); } - add_osd_ass_event(obj->osd_track, "progbar", buf.start); + add_osd_ass_event(track, "progbar", buf.start); talloc_free(buf.start); struct ass_draw *d = &(struct ass_draw) { .scale = 4 }; @@ -372,7 +390,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) float pos = obj->progbar_state.value * width - border / 2; ass_draw_rect_cw(d, 0, 0, pos, height); ass_draw_stop(d); - add_osd_ass_event(obj->osd_track, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); // position marker @@ -382,7 +400,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) 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, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); d->text = talloc_asprintf_append(d->text, "{\\pos(%f,%f)}", px, py); @@ -411,79 +429,112 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) } ass_draw_stop(d); - add_osd_ass_event(obj->osd_track, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); } static void update_osd(struct osd_state *osd, struct osd_object *obj) { - clear_obj(obj); + clear_ass(&obj->ass); update_osd_text(osd, obj); update_progbar(osd, obj); } -static void update_external(struct osd_state *osd, struct osd_object *obj) +static void update_external(struct osd_state *osd, struct osd_object *obj, + struct osd_external *ext) { - clear_obj(obj); - - bstr t = bstr0(obj->text); + bstr t = bstr0(ext->text); if (!t.len) return; - create_ass_track(osd, obj, obj->external_res_x, obj->external_res_y); + create_ass_track(osd, obj, &ext->ass, ext->res_x, ext->res_y); - int resy = obj->osd_track->PlayResY; - mp_ass_set_style(get_style(osd, obj, "OSD"), resy, osd->opts->osd_style); + clear_ass(&ext->ass); + + int resy = ext->ass.track->PlayResY; + mp_ass_set_style(get_style(&ext->ass, "OSD"), resy, osd->opts->osd_style); // Some scripts will reference this style name with \r tags. const struct osd_style_opts *def = osd_style_conf.defaults; - mp_ass_set_style(get_style(osd, obj, "Default"), resy, def); + mp_ass_set_style(get_style(&ext->ass, "Default"), resy, def); while (t.len) { bstr line; bstr_split_tok(t, "\n", &line, &t); if (line.len) { char *tmp = bstrdup0(NULL, line); - add_osd_ass_event(obj->osd_track, "OSD", tmp); + add_osd_ass_event(ext->ass.track, "OSD", tmp); talloc_free(tmp); } } } -static void update_object(struct osd_state *osd, struct osd_object *obj) +void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, + char *text) { - switch (obj->type) { - case OSDTYPE_OSD: - update_osd(osd, obj); - break; - case OSDTYPE_EXTERNAL: - update_external(osd, obj); - break; + pthread_mutex_lock(&osd->lock); + struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL]; + struct osd_external *entry = 0; + for (int n = 0; n < obj->num_externals; n++) { + if (obj->externals[n].id == id) { + entry = &obj->externals[n]; + break; + } + } + if (!entry && !text) + goto done; + + if (!entry) { + struct osd_external new = { .id = id }; + MP_TARRAY_APPEND(obj, obj->externals, obj->num_externals, new); + entry = &obj->externals[obj->num_externals - 1]; + } + + if (!text) { + int index = entry - &obj->externals[0]; + destroy_external(entry); + MP_TARRAY_REMOVE_AT(obj->externals, obj->num_externals, index); + goto done; } + + if (!entry->text || strcmp(entry->text, text) != 0 || + entry->res_x != res_x || entry->res_y != res_y) + { + talloc_free(entry->text); + entry->text = talloc_strdup(NULL, text); + entry->res_x = res_x; + entry->res_y = res_y; + update_external(osd, obj, entry); + obj->parts_cache.change_id = 1; + osd_changed_unlocked(osd, obj->type); + } + +done: + pthread_mutex_unlock(&osd->lock); } -void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, - struct sub_bitmaps *out_imgs) +static void append_ass(struct ass_state *ass, struct mp_osd_res *res, + struct sub_bitmaps *imgs) { - if (obj->force_redraw) - update_object(osd, obj); - - *out_imgs = (struct sub_bitmaps) {0}; - if (!obj->osd_track) + if (!ass->render || !ass->track) return; - ass_set_frame_size(obj->osd_render, obj->vo_res.w, obj->vo_res.h); - ass_set_aspect_ratio(obj->osd_render, obj->vo_res.display_par, 1.0); - mp_ass_render_frame(obj->osd_render, obj->osd_track, 0, - &obj->parts_cache, out_imgs); - talloc_steal(obj, obj->parts_cache); + ass_set_frame_size(ass->render, res->w, res->h); + ass_set_aspect_ratio(ass->render, res->display_par, 1.0); + mp_ass_render_frame(ass->render, ass->track, 0, imgs); } -void osd_object_get_resolution(struct osd_state *osd, int obj, - int *out_w, int *out_h) +void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, + struct sub_bitmaps *out_imgs) { - pthread_mutex_lock(&osd->lock); - struct osd_object *osd_obj = osd->objs[obj]; - *out_w = osd_obj->osd_track ? osd_obj->osd_track->PlayResX : 0; - *out_h = osd_obj->osd_track ? osd_obj->osd_track->PlayResY : 0; - pthread_mutex_unlock(&osd->lock); + if (obj->force_redraw && obj->type == OSDTYPE_OSD) + update_osd(osd, obj); + + append_ass(&obj->ass, &obj->vo_res, &obj->parts_cache); + for (int n = 0; n < obj->num_externals; n++) + append_ass(&obj->externals[n].ass, &obj->vo_res, &obj->parts_cache); + + *out_imgs = obj->parts_cache; + + obj->parts_cache.change_id = 0; + obj->parts_cache.num_parts = 0; } |