diff options
author | wm4 <wm4@nowhere> | 2020-03-06 18:20:11 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2020-03-06 18:20:11 +0100 |
commit | 7a76b577d85ddc8f9e255b1a1c195ee88b76a7d8 (patch) | |
tree | cf51a99eae3a5356680480a72c6fb81dbb7d8d91 /sub | |
parent | c6822b853d7475e8bf3b2c9f6823b7d74cf86950 (diff) | |
download | mpv-7a76b577d85ddc8f9e255b1a1c195ee88b76a7d8.tar.bz2 mpv-7a76b577d85ddc8f9e255b1a1c195ee88b76a7d8.tar.xz |
command: extend osd-overlay command with bounds reporting
This is more or less a minimal hack to make _some_ text measurement
functionality available to scripts. Since libass does not support such a
thing, this simply uses the bounding box of the rendered text.
This is far from ideal. Problems include:
- using a bitmap bounding box
- additional memory waste and/or flushing caches
- dependency on window size
- odd small deviations with different window sizes (run osd-test.lua and
resize the window after each timer update; the bounding boxes aren't
adjusted in an overly useful way)
- inability to query the size _after_ actual rendering
But I guess it's a start. Since I'm aware that it's crap, add a threat
to the manpage that this may be changed/removed again. For now, I'm
interested whether anyone will have use for it in its current form, as
it's an often requested feature.
Diffstat (limited to 'sub')
-rw-r--r-- | sub/ass_mp.c | 25 | ||||
-rw-r--r-- | sub/ass_mp.h | 2 | ||||
-rw-r--r-- | sub/osd.h | 3 | ||||
-rw-r--r-- | sub/osd_libass.c | 57 | ||||
-rw-r--r-- | sub/osd_state.h | 2 |
5 files changed, 82 insertions, 7 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c index d5d9e3e7d6..d214375b61 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -23,6 +23,7 @@ #include <stdarg.h> #include <stdbool.h> #include <assert.h> +#include <math.h> #include <ass/ass.h> #include <ass/ass_types.h> @@ -385,3 +386,27 @@ void mp_ass_packer_pack(struct mp_ass_packer *p, ASS_Image **image_lists, p->cached_subs.change_id = 0; p->cached_subs_valid = true; } + +// Set *out_rc to [x0, y0, x1, y1] of the graphical bounding box in script +// coordinates. +// Set it to [inf, inf, -inf, -inf] if empty. +void mp_ass_get_bb(ASS_Image *image_list, ASS_Track *track, + struct mp_osd_res *res, double *out_rc) +{ + double rc[4] = {INFINITY, INFINITY, -INFINITY, -INFINITY}; + + for (ASS_Image *img = image_list; img; img = img->next) { + if (img->w == 0 || img->h == 0) + continue; + rc[0] = MPMIN(rc[0], img->dst_x); + rc[1] = MPMIN(rc[1], img->dst_y); + rc[2] = MPMAX(rc[2], img->dst_x + img->w); + rc[3] = MPMAX(rc[3], img->dst_y + img->h); + } + + double scale = track->PlayResY / (double)MPMAX(res->h, 1); + if (scale > 0) { + for (int i = 0; i < 4; i++) + out_rc[i] = rc[i] * scale; + } +} diff --git a/sub/ass_mp.h b/sub/ass_mp.h index 4ebb7f39a6..f4488bf8c7 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -55,5 +55,7 @@ struct mp_ass_packer *mp_ass_packer_alloc(void *ta_parent); void mp_ass_packer_pack(struct mp_ass_packer *p, ASS_Image **image_lists, int num_image_lists, bool changed, int preferred_osd_format, struct sub_bitmaps *out); +void mp_ass_get_bb(ASS_Image *image_list, ASS_Track *track, + struct mp_osd_res *res, double *out_rc); #endif /* MPLAYER_ASS_MP_H */ @@ -209,6 +209,9 @@ struct osd_external_ass { char *data; int res_x, res_y; int z; + bool hidden; + + double *out_rc; // hack to pass boundary rect, [x0, y0, x1, y1] }; // defined in osd_libass.c and osd_dummy.c diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 01c0337eb4..bf527e17f3 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -40,6 +40,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) { } @@ -101,6 +104,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; @@ -531,10 +536,12 @@ 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); - obj->changed = true; - osd->want_redraw_notification = true; goto done; } @@ -547,17 +554,42 @@ 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 (!entry->ov.hidden) { + 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); } @@ -593,7 +625,13 @@ static void append_ass(struct ass_state *ass, struct mp_osd_res *res, 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, @@ -609,8 +647,13 @@ 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); + } } mp_ass_packer_pack(obj->ass_packer, obj->ass_imgs, obj->num_externals + 1, diff --git a/sub/osd_state.h b/sub/osd_state.h index 8207cf0dda..b563502fd6 100644 --- a/sub/osd_state.h +++ b/sub/osd_state.h @@ -23,6 +23,8 @@ struct ass_state { struct ass_renderer *render; struct ass_library *library; int res_x, res_y; + bool changed; + struct mp_osd_res vo_res; // last known value }; struct osd_object { |