aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar wm4 <wm4@nowhere>2014-01-18 01:19:20 +0100
committerGravatar wm4 <wm4@nowhere>2014-01-18 01:27:43 +0100
commit7f4a09bb8534dfafd83099d773adf2e33c64e267 (patch)
tree5b75791151f92e164fbd9badee47590d1164683d
parent92a9f11a0b4fda60c8880014be5920dcf3e95253 (diff)
sub: uglify OSD code path with locking
Do two things: 1. add locking to struct osd_state 2. make struct osd_state opaque While 1. is somewhat simple, 2. is quite horrible. Lots of code accesses lots of osd_state (and osd_object) members. To make sure everything is accessed synchronously, I prefer making osd_state opaque, even if it means adding pretty dumb accessors. All of this is meant to allow running VO in their own threads. Eventually, VOs will request OSD on their own, which means osd_state will be accessed from foreign threads.
-rw-r--r--player/command.c58
-rw-r--r--player/core.h2
-rw-r--r--player/dvdnav.c39
-rw-r--r--player/loadfile.c3
-rw-r--r--player/lua.c31
-rw-r--r--player/osd.c36
-rw-r--r--player/playloop.c9
-rw-r--r--player/screenshot.c6
-rw-r--r--player/sub.c38
-rw-r--r--player/video.c4
-rw-r--r--sub/osd.c184
-rw-r--r--sub/osd.h119
-rw-r--r--sub/osd_dummy.c2
-rw-r--r--sub/osd_libass.c38
-rw-r--r--sub/osd_state.h68
-rw-r--r--video/out/gl_osd.c4
-rw-r--r--video/out/vo_direct3d.c2
-rw-r--r--video/out/vo_image.c2
-rw-r--r--video/out/vo_lavc.c3
-rw-r--r--video/out/vo_sdl.c2
-rw-r--r--video/out/vo_vaapi.c2
-rw-r--r--video/out/vo_vdpau.c2
-rw-r--r--video/out/vo_wayland.c2
-rw-r--r--video/out/vo_x11.c2
-rw-r--r--video/out/vo_xv.c2
25 files changed, 416 insertions, 244 deletions
diff --git a/player/command.c b/player/command.c
index 2334e844b4..bb0e9789cf 100644
--- a/player/command.c
+++ b/player/command.c
@@ -87,6 +87,7 @@ struct command_ctx {
#define OVERLAY_MAX_ID 64
void *overlay_map[OVERLAY_MAX_ID];
+ struct sub_bitmaps external2;
};
static int edit_filters(struct MPContext *mpctx, enum stream_type mediatype,
@@ -1573,20 +1574,22 @@ static int mp_property_window_scale(m_option_t *prop, int action, void *arg,
static int mp_property_osd_w(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- return m_property_int_ro(prop, action, arg, mpctx->osd->last_vo_res.w);
+ struct mp_osd_res vo_res = osd_get_vo_res(mpctx->osd, OSDTYPE_OSD);
+ return m_property_int_ro(prop, action, arg, vo_res.w);
}
static int mp_property_osd_h(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- return m_property_int_ro(prop, action, arg, mpctx->osd->last_vo_res.w);
+ struct mp_osd_res vo_res = osd_get_vo_res(mpctx->osd, OSDTYPE_OSD);
+ return m_property_int_ro(prop, action, arg, vo_res.w);
}
static int mp_property_osd_par(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- return m_property_double_ro(prop, action, arg,
- mpctx->osd->last_vo_res.display_par);
+ struct mp_osd_res vo_res = osd_get_vo_res(mpctx->osd, OSDTYPE_OSD);
+ return m_property_double_ro(prop, action, arg, vo_res.display_par);
}
/// Video fps (RO)
@@ -2348,7 +2351,7 @@ static int edit_filters_osd(struct MPContext *mpctx, enum stream_type mediatype,
static int ext2_sub_find(struct MPContext *mpctx, int id)
{
struct command_ctx *cmd = mpctx->command_ctx;
- struct sub_bitmaps *sub = &mpctx->osd->external2;
+ struct sub_bitmaps *sub = &cmd->external2;
void *p = NULL;
if (id >= 0 && id < OVERLAY_MAX_ID)
p = cmd->overlay_map[id];
@@ -2363,10 +2366,10 @@ static int ext2_sub_find(struct MPContext *mpctx, int id)
static int ext2_sub_alloc(struct MPContext *mpctx)
{
- struct osd_state *osd = mpctx->osd;
- struct sub_bitmaps *sub = &osd->external2;
+ struct command_ctx *cmd = mpctx->command_ctx;
+ struct sub_bitmaps *sub = &cmd->external2;
struct sub_bitmap b = {0};
- MP_TARRAY_APPEND(osd, sub->parts, sub->num_parts, b);
+ MP_TARRAY_APPEND(cmd, sub->parts, sub->num_parts, b);
return sub->num_parts - 1;
}
@@ -2375,14 +2378,16 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
int stride)
{
struct command_ctx *cmd = mpctx->command_ctx;
- struct osd_state *osd = mpctx->osd;
+ int r = -1;
+ // Temporarily unmap them to avoid race condition with concurrent access.
+ osd_set_external2(mpctx->osd, NULL);
if (strcmp(fmt, "bgra") != 0) {
MP_ERR(mpctx, "overlay_add: unsupported OSD format '%s'\n", fmt);
- return -1;
+ goto error;
}
if (id < 0 || id >= OVERLAY_MAX_ID) {
MP_ERR(mpctx, "overlay_add: invalid id %d\n", id);
- return -1;
+ goto error;
}
int fd = -1;
bool close_fd = true;
@@ -2400,48 +2405,52 @@ static int overlay_add(struct MPContext *mpctx, int id, int x, int y,
close(fd);
if (!p) {
MP_ERR(mpctx, "overlay_add: could not open or map '%s'\n", file);
- return -1;
+ goto error;
}
int index = ext2_sub_find(mpctx, id);
if (index < 0)
index = ext2_sub_alloc(mpctx);
if (index < 0) {
munmap(p, h * stride);
- return -1;
+ goto error;
}
cmd->overlay_map[id] = p;
- osd->external2.parts[index] = (struct sub_bitmap) {
+ cmd->external2.parts[index] = (struct sub_bitmap) {
.bitmap = p,
.stride = stride,
.x = x, .y = y,
.w = w, .h = h,
.dw = w, .dh = h,
};
- osd->external2.bitmap_id = osd->external2.bitmap_pos_id = 1;
- osd->external2.format = SUBBITMAP_RGBA;
- osd->want_redraw = true;
- return 0;
+ cmd->external2.bitmap_id = cmd->external2.bitmap_pos_id = 1;
+ cmd->external2.format = SUBBITMAP_RGBA;
+ r = 0;
+error:
+ osd_set_external2(mpctx->osd, &cmd->external2);
+ return r;
}
static void overlay_remove(struct MPContext *mpctx, int id)
{
struct command_ctx *cmd = mpctx->command_ctx;
- struct osd_state *osd = mpctx->osd;
+ osd_set_external2(mpctx->osd, NULL);
int index = ext2_sub_find(mpctx, id);
if (index >= 0) {
- struct sub_bitmaps *sub = &osd->external2;
+ struct sub_bitmaps *sub = &cmd->external2;
struct sub_bitmap *part = &sub->parts[index];
munmap(part->bitmap, part->h * part->stride);
MP_TARRAY_REMOVE_AT(sub->parts, sub->num_parts, index);
cmd->overlay_map[id] = NULL;
sub->bitmap_id = sub->bitmap_pos_id = 1;
}
+ osd_set_external2(mpctx->osd, &cmd->external2);
}
static void overlay_uninit(struct MPContext *mpctx)
{
for (int id = 0; id < OVERLAY_MAX_ID; id++)
overlay_remove(mpctx, id);
+ osd_set_external2(mpctx->osd, NULL);
}
#else
@@ -2739,12 +2748,13 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
case MP_CMD_SUB_STEP:
case MP_CMD_SUB_SEEK: {
- struct osd_object *obj = mpctx->osd->objs[OSDTYPE_SUB];
- if (obj->dec_sub) {
+ struct osd_sub_state state;
+ osd_get_sub(mpctx->osd, OSDTYPE_SUB, &state);
+ if (state.dec_sub) {
double a[2];
- a[0] = mpctx->video_pts - obj->video_offset - opts->sub_delay;
+ a[0] = mpctx->video_pts - state.video_offset - opts->sub_delay;
a[1] = cmd->args[0].v.i;
- if (sub_control(obj->dec_sub, SD_CTRL_SUB_STEP, a) > 0) {
+ if (sub_control(state.dec_sub, SD_CTRL_SUB_STEP, a) > 0) {
if (cmd->id == MP_CMD_SUB_STEP) {
opts->sub_delay -= a[0];
osd_changed_all(mpctx->osd);
diff --git a/player/core.h b/player/core.h
index edfdaec2e1..1018ea9df3 100644
--- a/player/core.h
+++ b/player/core.h
@@ -23,6 +23,7 @@
#include "common/common.h"
#include "options/options.h"
+#include "sub/osd.h"
// definitions used internally by the core player code
@@ -158,6 +159,7 @@ typedef struct MPContext {
int osd_function;
double osd_function_visible;
double osd_last_update;
+ struct osd_progbar_state osd_progbar;
struct playlist *playlist;
char *filename; // currently playing file
diff --git a/player/dvdnav.c b/player/dvdnav.c
index 7e28c1922b..fd370599c6 100644
--- a/player/dvdnav.c
+++ b/player/dvdnav.c
@@ -39,8 +39,11 @@ struct mp_nav_state {
bool nav_eof;
bool nav_menu;
bool nav_draining;
+
+ // Accessed by OSD (possibly separate thread)
int hi_visible;
int highlight[4]; // x0 y0 x1 y1
+ int vidsize[2];
int subsize[2];
struct sub_bitmap *hi_elem;
};
@@ -78,6 +81,7 @@ void mp_nav_reset(struct MPContext *mpctx)
return;
struct mp_nav_cmd inp = {MP_NAV_CMD_RESUME};
stream_control(mpctx->stream, STREAM_CTRL_NAV_CMD, &inp);
+ osd_set_nav_highlight(mpctx->osd, NULL);
nav->hi_visible = 0;
nav->nav_menu = false;
nav->nav_draining = false;
@@ -90,6 +94,7 @@ void mp_nav_reset(struct MPContext *mpctx)
void mp_nav_destroy(struct MPContext *mpctx)
{
+ osd_set_nav_highlight(mpctx->osd, NULL);
if (!mpctx->nav_state)
return;
mp_input_disable_section(mpctx->input, "dvdnav");
@@ -164,19 +169,32 @@ void mp_handle_nav(struct MPContext *mpctx)
mp_input_disable_section(mpctx->input, "dvdnav-menu");
}
break;
- case MP_NAV_EVENT_HIGHLIGHT:
+ case MP_NAV_EVENT_HIGHLIGHT: {
MP_VERBOSE(nav, "highlight: %d %d %d - %d %d\n",
ev->u.highlight.display,
ev->u.highlight.sx, ev->u.highlight.sy,
ev->u.highlight.ex, ev->u.highlight.ey);
+ osd_set_nav_highlight(mpctx->osd, NULL);
nav->highlight[0] = ev->u.highlight.sx;
nav->highlight[1] = ev->u.highlight.sy;
nav->highlight[2] = ev->u.highlight.ex;
nav->highlight[3] = ev->u.highlight.ey;
nav->hi_visible = ev->u.highlight.display;
- mpctx->osd->highlight_priv = mpctx;
- osd_changed(mpctx->osd, OSDTYPE_NAV_HIGHLIGHT);
+ int sizes[2] = {0};
+ if (mpctx->d_sub[0])
+ sub_control(mpctx->d_sub[0], SD_CTRL_GET_RESOLUTION, sizes);
+ if (sizes[0] < 1 || sizes[1] < 1) {
+ struct mp_image_params vid = {0};
+ if (mpctx->d_video)
+ vid = mpctx->d_video->decoder_output;
+ sizes[0] = vid.w;
+ sizes[1] = vid.h;
+ }
+ for (int n = 0; n < 2; n++)
+ nav->vidsize[n] = sizes[n];
+ osd_set_nav_highlight(mpctx->osd, mpctx);
break;
+ }
default: ; // ignore
}
talloc_free(ev);
@@ -209,10 +227,10 @@ void mp_handle_nav(struct MPContext *mpctx)
// Note: a proper solution would introduce something like
// SD_CTRL_APPLY_DVDNAV, which would crop the vobsub frame,
// and apply the current CLUT.
-void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res,
+void mp_nav_get_highlight(void *priv, struct mp_osd_res res,
struct sub_bitmaps *out_imgs)
{
- struct MPContext *mpctx = osd->highlight_priv;
+ struct MPContext *mpctx = priv;
struct mp_nav_state *nav = mpctx ? mpctx->nav_state : NULL;
if (!nav)
return;
@@ -221,16 +239,7 @@ void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res,
sub = talloc_zero(nav, struct sub_bitmap);
nav->hi_elem = sub;
- int sizes[2] = {0};
- if (mpctx->d_sub[0])
- sub_control(mpctx->d_sub[0], SD_CTRL_GET_RESOLUTION, sizes);
- if (sizes[0] < 1 || sizes[1] < 1) {
- struct mp_image_params vid = {0};
- if (mpctx->d_video)
- vid = mpctx->d_video->decoder_output;
- sizes[0] = vid.w;
- sizes[1] = vid.h;
- }
+ int sizes[2] = {nav->vidsize[0], nav->vidsize[1]};
if (sizes[0] < 1 || sizes[1] < 1)
return;
if (sizes[0] != nav->subsize[0] || sizes[1] != nav->subsize[1]) {
diff --git a/player/loadfile.c b/player/loadfile.c
index 6262042709..b81da983f8 100644
--- a/player/loadfile.c
+++ b/player/loadfile.c
@@ -67,7 +67,8 @@ static void uninit_sub(struct MPContext *mpctx, int order)
if (mpctx->d_sub[order])
sub_reset(mpctx->d_sub[order]);
mpctx->d_sub[order] = NULL; // Note: not free'd.
- mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB]->dec_sub = NULL;
+ int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
+ osd_set_sub(mpctx->osd, obj, NULL);
reset_subtitles(mpctx, order);
reselect_demux_streams(mpctx);
}
diff --git a/player/lua.c b/player/lua.c
index f77f9d1a7e..ca92aa009d 100644
--- a/player/lua.c
+++ b/player/lua.c
@@ -479,17 +479,7 @@ static int script_set_osd_ass(lua_State *L)
int res_x = luaL_checkinteger(L, 1);
int res_y = luaL_checkinteger(L, 2);
const char *text = luaL_checkstring(L, 3);
- if (!mpctx->osd->external ||
- strcmp(mpctx->osd->external, text) != 0 ||
- mpctx->osd->external_res_x != res_x ||
- mpctx->osd->external_res_y != res_y)
- {
- talloc_free(mpctx->osd->external);
- mpctx->osd->external = talloc_strdup(mpctx->osd, text);
- mpctx->osd->external_res_x = res_x;
- mpctx->osd->external_res_y = res_y;
- osd_changed(mpctx->osd, OSDTYPE_EXTERNAL);
- }
+ osd_set_external(mpctx->osd, res_x, res_y, (char *)text);
return 0;
}
@@ -497,8 +487,7 @@ static int script_get_osd_resolution(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
int w, h;
- osd_object_get_resolution(mpctx->osd, mpctx->osd->objs[OSDTYPE_EXTERNAL],
- &w, &h);
+ osd_object_get_resolution(mpctx->osd, OSDTYPE_EXTERNAL, &w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
@@ -507,11 +496,11 @@ static int script_get_osd_resolution(lua_State *L)
static int script_get_screen_size(lua_State *L)
{
struct MPContext *mpctx = get_mpctx(L);
- struct osd_object *obj = mpctx->osd->objs[OSDTYPE_EXTERNAL];
- double aspect = 1.0 * obj->vo_res.w / MPMAX(obj->vo_res.h, 1) /
- obj->vo_res.display_par;
- lua_pushnumber(L, obj->vo_res.w);
- lua_pushnumber(L, obj->vo_res.h);
+ struct mp_osd_res vo_res = osd_get_vo_res(mpctx->osd, OSDTYPE_EXTERNAL);
+ double aspect = 1.0 * vo_res.w / MPMAX(vo_res.h, 1) /
+ vo_res.display_par;
+ lua_pushnumber(L, vo_res.w);
+ lua_pushnumber(L, vo_res.h);
lua_pushnumber(L, aspect);
return 3;
}
@@ -522,8 +511,7 @@ static int script_get_mouse_pos(lua_State *L)
int px, py;
mp_input_get_mouse_pos(mpctx->input, &px, &py);
double sw, sh;
- osd_object_get_scale_factor(mpctx->osd, mpctx->osd->objs[OSDTYPE_EXTERNAL],
- &sw, &sh);
+ osd_object_get_scale_factor(mpctx->osd, OSDTYPE_EXTERNAL, &sw, &sh);
lua_pushnumber(L, px * sw);
lua_pushnumber(L, py * sh);
return 2;
@@ -652,8 +640,7 @@ static int script_input_set_section_mouse_area(lua_State *L)
struct MPContext *mpctx = get_mpctx(L);
double sw, sh;
- struct osd_object *obj = mpctx->osd->objs[OSDTYPE_EXTERNAL];
- osd_object_get_scale_factor(mpctx->osd, obj, &sw, &sh);
+ osd_object_get_scale_factor(mpctx->osd, OSDTYPE_EXTERNAL, &sw, &sh);
char *section = (char *)luaL_checkstring(L, 1);
int x0 = luaL_checkinteger(L, 2) / sw;
diff --git a/player/osd.c b/player/osd.c
index 8401f75b36..1f15e3ddc7 100644
--- a/player/osd.c
+++ b/player/osd.c
@@ -292,8 +292,8 @@ static mp_osd_msg_t *get_osd_msg(struct MPContext *mpctx)
if (mpctx->osd_visible && now >= mpctx->osd_visible) {
mpctx->osd_visible = 0;
- mpctx->osd->progbar_type = -1; // disable
- osd_changed(mpctx->osd, OSDTYPE_PROGBAR);
+ mpctx->osd_progbar.type = -1; // disable
+ osd_set_progbar(mpctx->osd, &mpctx->osd_progbar);
}
if (mpctx->osd_function_visible && now >= mpctx->osd_function_visible) {
mpctx->osd_function_visible = 0;
@@ -335,10 +335,10 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name,
if (mpctx->video_out && opts->term_osd != 1) {
mpctx->osd_visible = mp_time_sec() + opts->osd_duration / 1000.0;
- mpctx->osd->progbar_type = type;
- mpctx->osd->progbar_value = (val - min) / (max - min);
- mpctx->osd->progbar_num_stops = 0;
- osd_changed(mpctx->osd, OSDTYPE_PROGBAR);
+ mpctx->osd_progbar.type = type;
+ mpctx->osd_progbar.value = (val - min) / (max - min);
+ mpctx->osd_progbar.num_stops = 0;
+ osd_set_progbar(mpctx->osd, &mpctx->osd_progbar);
return;
}
@@ -351,20 +351,19 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name,
static void update_osd_bar(struct MPContext *mpctx, int type,
double min, double max, double val)
{
- if (mpctx->osd->progbar_type == type) {
+ if (mpctx->osd_progbar.type == type) {
float new_value = (val - min) / (max - min);
- if (new_value != mpctx->osd->progbar_value) {
- mpctx->osd->progbar_value = new_value;
- osd_changed(mpctx->osd, OSDTYPE_PROGBAR);
+ if (new_value != mpctx->osd_progbar.value) {
+ mpctx->osd_progbar.value = new_value;
+ osd_set_progbar(mpctx->osd, &mpctx->osd_progbar);
}
}
}
static void set_osd_bar_chapters(struct MPContext *mpctx, int type)
{
- struct osd_state *osd = mpctx->osd;
- osd->progbar_num_stops = 0;
- if (osd->progbar_type == type) {
+ mpctx->osd_progbar.num_stops = 0;
+ if (mpctx->osd_progbar.type == type) {
double len = get_time_length(mpctx);
if (len > 0) {
int num = get_chapter_count(mpctx);
@@ -372,12 +371,13 @@ static void set_osd_bar_chapters(struct MPContext *mpctx, int type)
double time = chapter_start_time(mpctx, n);
if (time >= 0) {
float pos = time / len;
- MP_TARRAY_APPEND(osd, osd->progbar_stops,
- osd->progbar_num_stops, pos);
+ MP_TARRAY_APPEND(mpctx, mpctx->osd_progbar.stops,
+ mpctx->osd_progbar.num_stops, pos);
}
}
}
}
+ osd_set_progbar(mpctx->osd, &mpctx->osd_progbar);
}
// osd_function is the symbol appearing in the video status, such as OSD_PLAY
@@ -394,7 +394,7 @@ void set_osd_function(struct MPContext *mpctx, int osd_function)
*/
void set_osd_subtitle(struct MPContext *mpctx, const char *text)
{
- osd_set_sub(mpctx->osd, mpctx->osd->objs[OSDTYPE_SUB], text);
+ osd_set_text(mpctx->osd, OSDTYPE_SUB, text);
term_osd_set_subs(mpctx, text);
}
@@ -495,7 +495,7 @@ void update_osd_msg(struct MPContext *mpctx)
// Look if we have a msg
mp_osd_msg_t *msg = get_osd_msg(mpctx);
if (msg && !msg->show_position) {
- osd_set_text(osd, msg->msg);
+ osd_set_text(osd, OSDTYPE_OSD, msg->msg);
term_osd_set_text(mpctx, msg->msg);
return;
}
@@ -510,7 +510,7 @@ void update_osd_msg(struct MPContext *mpctx)
if (osd_level >= 2)
sadd_osd_status(&text, mpctx, osd_level == 3);
- osd_set_text(osd, text);
+ osd_set_text(osd, OSDTYPE_OSD, text);
talloc_free(text);
// always clear (term-osd has separate status line)
diff --git a/player/playloop.c b/player/playloop.c
index 95e9a9c5a4..167a0722a2 100644
--- a/player/playloop.c
+++ b/player/playloop.c
@@ -136,7 +136,7 @@ static void draw_osd(struct MPContext *mpctx)
{
struct vo *vo = mpctx->video_out;
- mpctx->osd->vo_pts = mpctx->video_pts;
+ osd_set_vo_pts(mpctx->osd, mpctx->video_pts);
vo_draw_osd(vo, mpctx->osd);
}
@@ -646,10 +646,9 @@ static bool handle_osd_redraw(struct MPContext *mpctx)
{
if (!mpctx->video_out || !mpctx->video_out->config_ok)
return false;
- bool want_redraw = vo_get_want_redraw(mpctx->video_out);
- if (mpctx->video_out->driver->draw_osd)
- want_redraw |= mpctx->osd->want_redraw;
- mpctx->osd->want_redraw = false;
+ bool want_redraw = vo_get_want_redraw(mpctx->video_out) |
+ (osd_query_and_reset_want_redraw(mpctx->osd) &&
+ mpctx->video_out->driver->draw_osd);
if (want_redraw) {
if (redraw_osd(mpctx))
return true;
diff --git a/player/screenshot.c b/player/screenshot.c
index d5a6b1b3d0..9b8922c39a 100644
--- a/player/screenshot.c
+++ b/player/screenshot.c
@@ -307,7 +307,7 @@ static void add_subs(struct MPContext *mpctx, struct mp_image *image)
.display_par = sar / dar,
};
- osd_draw_on_image(mpctx->osd, res, mpctx->osd->vo_pts,
+ osd_draw_on_image(mpctx->osd, res, osd_get_vo_pts(mpctx->osd),
OSD_DRAW_SUB_ONLY, image);
}
@@ -330,7 +330,7 @@ static struct mp_image *screenshot_get(struct MPContext *mpctx, int mode)
{
struct mp_image *image = NULL;
if (mpctx->video_out && mpctx->video_out->config_ok) {
- if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter)
+ if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd))
mode = 0;
struct voctrl_screenshot_args args =
@@ -386,7 +386,7 @@ void screenshot_request(struct MPContext *mpctx, int mode, bool each_frame,
{
screenshot_ctx *ctx = mpctx->screenshot_ctx;
- if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter)
+ if (mode == MODE_SUBTITLES && osd_get_render_subs_in_filter(mpctx->osd))
mode = 0;
if (each_frame) {
diff --git a/player/sub.c b/player/sub.c
index 6d39ef2299..00b2260c67 100644
--- a/player/sub.c
+++ b/player/sub.c
@@ -68,12 +68,11 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track)
void reset_subtitles(struct MPContext *mpctx, int order)
{
- struct osd_object *osd_obj =
- mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB];
+ int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
if (mpctx->d_sub[order])
sub_reset(mpctx->d_sub[order]);
set_osd_subtitle(mpctx, NULL);
- osd_set_sub(mpctx->osd, osd_obj, NULL);
+ osd_set_text(mpctx->osd, obj, NULL);
}
static void update_subtitle(struct MPContext *mpctx, int order)
@@ -90,8 +89,7 @@ static void update_subtitle(struct MPContext *mpctx, int order)
struct track *track = mpctx->current_track[order][STREAM_SUB];
struct dec_sub *dec_sub = mpctx->d_sub[order];
assert(track && dec_sub);
- struct osd_object *osd_obj
- = mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB];
+ int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
if (mpctx->d_video) {
struct mp_image_params params = mpctx->d_video->vf_input;
@@ -99,9 +97,14 @@ static void update_subtitle(struct MPContext *mpctx, int order)
sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, &params);
}
- osd_obj->video_offset = track->under_timeline ? mpctx->video_offset : 0;
+ struct osd_sub_state state;
+ osd_get_sub(mpctx->osd, obj, &state);
- double refpts_s = mpctx->playback_pts - osd_obj->video_offset;
+ state.video_offset = track->under_timeline ? mpctx->video_offset : 0;
+
+ osd_set_sub(mpctx->osd, obj, &state);
+
+ double refpts_s = mpctx->playback_pts - state.video_offset;
double curpts_s = refpts_s - opts->sub_delay;
if (!track->preloaded && track->stream) {
@@ -136,14 +139,14 @@ static void update_subtitle(struct MPContext *mpctx, int order)
// Handle displaying subtitles on terminal; never done for secondary subs
if (order == 0) {
- if (!osd_obj->render_bitmap_subs || !mpctx->video_out) {
+ if (!state.render_bitmap_subs || !mpctx->video_out) {
sub_lock(dec_sub);
set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s));
sub_unlock(dec_sub);
}
} else if (order == 1) {
sub_lock(dec_sub);
- osd_set_sub(mpctx->osd, osd_obj, sub_get_text(dec_sub, curpts_s));
+ osd_set_text(mpctx->osd, obj, sub_get_text(dec_sub, curpts_s));
sub_unlock(dec_sub);
}
}
@@ -225,8 +228,7 @@ void reinit_subs(struct MPContext *mpctx, int order)
{
struct MPOpts *opts = mpctx->opts;
struct track *track = mpctx->current_track[order][STREAM_SUB];
- struct osd_object *osd_obj =
- mpctx->osd->objs[order ? OSDTYPE_SUB2 : OSDTYPE_SUB];
+ int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
int init_flag = order ? INITIALIZED_SUB2 : INITIALIZED_SUB;
assert(!(mpctx->initialized_flags & init_flag));
@@ -256,16 +258,18 @@ void reinit_subs(struct MPContext *mpctx, int order)
reinit_subdec(mpctx, track, dec_sub);
- osd_obj->dec_sub = dec_sub;
-
- // Decides whether to use OSD path or normal subtitle rendering path.
- osd_obj->render_bitmap_subs =
- opts->ass_enabled || !sub_has_get_text(dec_sub);
+ struct osd_sub_state state = {
+ .dec_sub = dec_sub,
+ // Decides whether to use OSD path or normal subtitle rendering path.
+ .render_bitmap_subs = opts->ass_enabled || !sub_has_get_text(dec_sub),
+ };
// Secondary subs are rendered with the "text" renderer to transform them
// to toptitles.
if (order == 1 && sub_has_get_text(dec_sub))
- osd_obj->render_bitmap_subs = false;
+ state.render_bitmap_subs = false;
reset_subtitles(mpctx, order);
+
+ osd_set_sub(mpctx->osd, obj, &state);
}
diff --git a/player/video.c b/player/video.c
index 17eaab619e..6f634270d2 100644
--- a/player/video.c
+++ b/player/video.c
@@ -126,8 +126,8 @@ static void recreate_video_filters(struct MPContext *mpctx)
// for vf_sub
vf_control_any(d_video->vfilter, VFCTRL_SET_OSD_OBJ, mpctx->osd);
- mpctx->osd->render_subs_in_filter
- = vf_control_any(d_video->vfilter, VFCTRL_INIT_OSD, NULL) == CONTROL_OK;
+ osd_set_render_subs_in_filter(mpctx->osd,
+ vf_control_any(d_video->vfilter, VFCTRL_INIT_OSD, NULL) == CONTROL_OK);
set_allowed_vo_formats(d_video->vfilter, mpctx->video_out);
}
diff --git a/sub/osd.c b/sub/osd.c
index 56d845b97f..69ba554890 100644
--- a/sub/osd.c
+++ b/sub/osd.c
@@ -34,6 +34,7 @@
#include "common/global.h"
#include "common/msg.h"
#include "osd.h"
+#include "osd_state.h"
#include "dec_sub.h"
#include "img_convert.h"
#include "draw_bmp.h"
@@ -87,15 +88,15 @@ struct osd_state *osd_create(struct mpv_global *global)
.opts = global->opts,
.global = global,
.log = mp_log_new(osd, global->log, "osd"),
- .osd_text = talloc_strdup(osd, ""),
- .progbar_type = -1,
};
+ pthread_mutex_init(&osd->lock, NULL);
for (int n = 0; n < MAX_OSD_PARTS; n++) {
struct osd_object *obj = talloc(osd, struct osd_object);
*obj = (struct osd_object) {
.type = n,
- .sub_text = talloc_strdup(obj, ""),
+ .text = talloc_strdup(obj, ""),
+ .progbar_state = {.type = -1},
};
for (int i = 0; i < OSD_CONV_CACHE_MAX; i++)
obj->cache[i] = talloc_steal(obj, osd_conv_cache_new());
@@ -114,30 +115,102 @@ void osd_free(struct osd_state *osd)
if (!osd)
return;
osd_destroy_backend(osd);
+ pthread_mutex_destroy(&osd->lock);
talloc_free(osd);
}
-static bool set_text(void *talloc_ctx, char **var, const char *text)
+static void osd_changed_unlocked(struct osd_state *osd, int obj)
{
+ osd->objs[obj]->force_redraw = true;
+ osd->want_redraw = true;
+}
+
+void osd_set_text(struct osd_state *osd, int obj, const char *text)
+{
+ pthread_mutex_lock(&osd->lock);
+ struct osd_object *osd_obj = osd->objs[obj];
if (!text)
text = "";
- if (strcmp(*var, text) == 0)
- return true;
- talloc_free(*var);
- *var = talloc_strdup(talloc_ctx, text);
- return false;
+ if (strcmp(osd_obj->text, text) != 0) {
+ talloc_free(osd_obj->text);
+ osd_obj->text = talloc_strdup(osd_obj, text);
+ osd_changed_unlocked(osd, obj);
+ }
+ pthread_mutex_unlock(&osd->lock);
+}
+
+void osd_set_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate)
+{
+ pthread_mutex_lock(&osd->lock);
+ osd->objs[obj]->sub_state = substate ? *substate : (struct osd_sub_state){0};
+ pthread_mutex_unlock(&osd->lock);
+}
+
+void osd_get_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate)
+{
+ pthread_mutex_lock(&osd->lock);
+ *substate = osd->objs[obj]->sub_state;
+ pthread_mutex_unlock(&osd->lock);
}
-void osd_set_text(struct osd_state *osd, const char *text)
+bool osd_get_render_subs_in_filter(struct osd_state *osd)
{
- if (!set_text(osd, &osd->osd_text, text))
- osd_changed(osd, OSDTYPE_OSD);
+ pthread_mutex_lock(&osd->lock);
+ bool r = osd->render_subs_in_filter;
+ pthread_mutex_unlock(&osd->lock);
+ return r;
+}
+
+void osd_set_render_subs_in_filter(struct osd_state *osd, bool s)
+{
+ pthread_mutex_lock(&osd->lock);
+ osd->render_subs_in_filter = s;
+ pthread_mutex_unlock(&osd->lock);
+}
+
+void osd_set_progbar(struct osd_state *osd, struct osd_progbar_state *s)
+{
+ pthread_mutex_lock(&osd->lock);
+ struct osd_object *osd_obj = osd->objs[OSDTYPE_PROGBAR];
+ osd_obj->progbar_state.type = s->type;
+ osd_obj->progbar_state.value = s->value;
+ osd_obj->progbar_state.num_stops = s->num_stops;
+ MP_TARRAY_GROW(osd_obj, osd_obj->progbar_state.stops, s->num_stops);
+ memcpy(osd_obj->progbar_state.stops, s->stops,
+ sizeof(osd_obj->progbar_state.stops[0]) * s->num_stops);
+ osd_changed_unlocked(osd, osd_obj->type);
+ pthread_mutex_unlock(&osd->lock);
+}
+
+void osd_set_external(struct osd_state *osd, int res_x, int res_y, char *text)
+{
+ pthread_mutex_lock(&osd->lock);
+ struct osd_object *osd_obj = osd->objs[OSDTYPE_EXTERNAL];
+ if (strcmp(osd_obj->text, text) != 0 ||
+ osd_obj->external_res_x != res_x ||
+ osd_obj->external_res_y != res_y)
+ {
+ talloc_free(osd_obj->text);
+ osd_obj->text = talloc_strdup(osd_obj, text);
+ osd_obj->external_res_x = res_x;
+ osd_obj->external_res_y = res_y;
+ osd_changed_unlocked(osd, osd_obj->type);
+ }
+ pthread_mutex_unlock(&osd->lock);
}
-void osd_set_sub(struct osd_state *osd, struct osd_object *obj, const char *text)
+void osd_set_external2(struct osd_state *osd, struct sub_bitmaps *imgs)
{
- if (!set_text(obj, &obj->sub_text, text))
- osd_changed(osd, obj->type);
+ pthread_mutex_lock(&osd->lock);
+ osd->objs[OSDTYPE_EXTERNAL2]->external2 = imgs;
+ pthread_mutex_unlock(&osd->lock);
+}
+
+void osd_set_nav_highlight(struct osd_state *osd, void *priv)
+{
+ pthread_mutex_lock(&osd->lock);
+ osd->objs[OSDTYPE_NAV_HIGHLIGHT]->highlight_priv = priv;
+ pthread_mutex_unlock(&osd->lock);
}
static void render_object(struct osd_state *osd, struct osd_object *obj,
@@ -159,21 +232,23 @@ static void render_object(struct osd_state *osd, struct osd_object *obj,
obj->vo_res = res;
if (obj->type == OSDTYPE_SUB || obj->type == OSDTYPE_SUB2) {
- if (obj->render_bitmap_subs && obj->dec_sub) {
+ struct osd_sub_state *sub = &obj->sub_state;
+ if (sub->render_bitmap_subs && sub->dec_sub) {
double sub_pts = video_pts;
if (sub_pts != MP_NOPTS_VALUE)
- sub_pts -= obj->video_offset + opts->sub_delay;
- sub_get_bitmaps(obj->dec_sub, obj->vo_res, sub_pts, out_imgs);
+ sub_pts -= sub->video_offset + opts->sub_delay;
+ sub_get_bitmaps(sub->dec_sub, obj->vo_res, sub_pts, out_imgs);
} else {
osd_object_get_bitmaps(osd, obj, out_imgs);
}
} else if (obj->type == OSDTYPE_EXTERNAL2) {
- if (osd->external2.format) {
- *out_imgs = osd->external2;
- osd->external2.bitmap_id = osd->external2.bitmap_pos_id = 0;
+ if (obj->external2 && obj->external2->format) {
+ *out_imgs = *obj->external2;
+ obj->external2->bitmap_id = obj->external2->bitmap_pos_id = 0;
}
} else if (obj->type == OSDTYPE_NAV_HIGHLIGHT) {
- mp_nav_get_highlight(osd, obj->vo_res, out_imgs);
+ if (obj->highlight_priv)
+ mp_nav_get_highlight(osd, obj->vo_res, out_imgs);
} else {
osd_object_get_bitmaps(osd, obj, out_imgs);
}
@@ -230,12 +305,11 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
const bool formats[SUBBITMAP_COUNT],
void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx)
{
+ pthread_mutex_lock(&osd->lock);
+
if (draw_flags & OSD_DRAW_SUB_FILTER)
draw_flags |= OSD_DRAW_SUB_ONLY;
- if (!(draw_flags & OSD_DRAW_SUB_ONLY))
- osd->last_vo_res = res;
-
for (int n = 0; n < MAX_OSD_PARTS; n++) {
struct osd_object *obj = osd->objs[n];
@@ -246,8 +320,8 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
if ((draw_flags & OSD_DRAW_SUB_ONLY) && !obj->is_sub)
continue;
- if (obj->dec_sub)
- sub_lock(obj->dec_sub);
+ if (obj->sub_state.dec_sub)
+ sub_lock(obj->sub_state.dec_sub);
struct sub_bitmaps imgs;
render_object(osd, obj, res, video_pts, formats, &imgs);
@@ -260,9 +334,11 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
}
}
- if (obj->dec_sub)
- sub_unlock(obj->dec_sub);
+ if (obj->sub_state.dec_sub)
+ sub_unlock(obj->sub_state.dec_sub);
}
+
+ pthread_mutex_unlock(&osd->lock);
}
struct draw_on_image_closure {
@@ -311,11 +387,9 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res,
void osd_changed(struct osd_state *osd, int new_value)
{
- for (int n = 0; n < MAX_OSD_PARTS; n++) {
- if (osd->objs[n]->type == new_value)
- osd->objs[n]->force_redraw = true;
- }
- osd->want_redraw = true;
+ pthread_mutex_lock(&osd->lock);
+ osd_changed_unlocked(osd, new_value);
+ pthread_mutex_unlock(&osd->lock);
}
void osd_changed_all(struct osd_state *osd)
@@ -324,15 +398,41 @@ void osd_changed_all(struct osd_state *osd)
osd_changed(osd, n);
}
+bool osd_query_and_reset_want_redraw(struct osd_state *osd)
+{
+ pthread_mutex_lock(&osd->lock);
+ bool r = osd->want_redraw;
+ osd->want_redraw = false;
+ pthread_mutex_unlock(&osd->lock);
+ return r;
+}
+
+double osd_get_vo_pts(struct osd_state *osd)
+{
+ pthread_mutex_lock(&osd->lock);
+ double r = osd->vo_pts;
+ pthread_mutex_unlock(&osd->lock);
+ return r;
+}
+
+void osd_set_vo_pts(struct osd_state *osd, double vo_pts)
+{
+ pthread_mutex_lock(&osd->lock);
+ osd->vo_pts = vo_pts;
+ pthread_mutex_unlock(&osd->lock);
+}
+
// Scale factor to translate OSD coordinates to what the obj uses internally.
// osd_coordinates * (sw, sh) = obj_coordinates
-void osd_object_get_scale_factor(struct osd_state *osd, struct osd_object *obj,
+void osd_object_get_scale_factor(struct osd_state *osd, int obj,
double *sw, double *sh)
{
int nw, nh;
osd_object_get_resolution(osd, obj, &nw, &nh);
- *sw = nw / (double)obj->vo_res.w;
- *sh = nh / (double)obj->vo_res.h;
+ pthread_mutex_lock(&osd->lock);
+ *sw = nw / (double)osd->objs[obj]->vo_res.w;
+ *sh = nh / (double)osd->objs[obj]->vo_res.h;
+ pthread_mutex_unlock(&osd->lock);
}
// Turn *x and *y, which are given in OSD coordinates, to video coordinates.
@@ -342,6 +442,7 @@ void osd_object_get_scale_factor(struct osd_state *osd, struct osd_object *obj,
void osd_coords_to_video(struct osd_state *osd, int frame_w, int frame_h,
int *x, int *y)
{
+ pthread_mutex_lock(&osd->lock);
struct mp_osd_res res = osd->objs[OSDTYPE_OSD]->vo_res;
int vidw = res.w - res.ml - res.mr;
int vidh = res.h - res.mt - res.mb;
@@ -350,6 +451,15 @@ void osd_coords_to_video(struct osd_state *osd, int frame_w, int frame_h,
// The OSD size + margins make up the scaled rectangle of the video.
*x = (*x - res.ml) / xscale;
*y = (*y - res.mt) / yscale;
+ pthread_mutex_unlock(&osd->lock);
+}
+
+struct mp_osd_res osd_get_vo_res(struct osd_state *osd, int obj)
+{
+ pthread_mutex_lock(&osd->lock);
+ struct mp_osd_res res = osd->objs[obj]->vo_res;
+ pthread_mutex_unlock(&osd->lock);
+ return res;
}
// Position the subbitmaps in imgs on the screen. Basically, this fits the
diff --git a/sub/osd.h b/sub/osd.h
index 17e8a02c08..239286c5e6 100644
--- a/sub/osd.h
+++ b/sub/osd.h
@@ -97,70 +97,6 @@ enum mp_osdtype {
MAX_OSD_PARTS
};
-#define OSD_CONV_CACHE_MAX 4
-
-struct osd_object {
- int type; // OSDTYPE_*
- bool is_sub;
-
- bool force_redraw;
-
- // OSDTYPE_SUB
- struct dec_sub *dec_sub;
- double video_offset;
- bool render_bitmap_subs;
- char *sub_text;
-
- // caches for OSD conversion (internal to render_object())
- struct osd_conv_cache *cache[OSD_CONV_CACHE_MAX];
- struct sub_bitmaps cached;
-
- // VO cache state
- int vo_bitmap_id;
- int vo_bitmap_pos_id;
- struct mp_osd_res vo_res;
-
- // Internally used by osd_libass.c
- struct sub_bitmap *parts_cache;
- struct ass_track *osd_track;
- struct ass_renderer *osd_render;
- struct ass_library *osd_ass_library;
-};
-
-struct osd_state {
- struct osd_object *objs[MAX_OSD_PARTS];
-
- double vo_pts;
-
- bool render_subs_in_filter;
-
- struct mp_osd_res last_vo_res;
-
- bool want_redraw;
-
- // 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;
- // OSDTYPE_EXTERNAL
- char *external;
- int external_res_x, external_res_y;
- // OSDTYPE_EXTERNAL2
- struct sub_bitmaps external2;
- // OSDTYPE_NAV_HIGHLIGHT
- void *highlight_priv;
-
- struct MPOpts *opts;
- struct mpv_global *global;
- struct mp_log *log;
-
- // Internal to sub.c
- struct mp_draw_sub_cache *draw_cache;
-};
-
// Start of OSD symbols in osd_font.pfb
#define OSD_CODEPOINTS 0xE000
@@ -204,13 +140,47 @@ struct osd_style_opts {
extern const struct m_sub_options osd_style_conf;
+struct osd_state;
+struct osd_object;
+struct mpv_global;
+
struct osd_state *osd_create(struct mpv_global *global);
-void osd_set_text(struct osd_state *osd, const char *text);
-void osd_set_sub(struct osd_state *osd, struct osd_object *obj, const char *text);
void osd_changed(struct osd_state *osd, int new_value);
void osd_changed_all(struct osd_state *osd);
void osd_free(struct osd_state *osd);
+bool osd_query_and_reset_want_redraw(struct osd_state *osd);
+
+double osd_get_vo_pts(struct osd_state *osd);
+void osd_set_vo_pts(struct osd_state *osd, double vo_pts);
+
+void osd_set_text(struct osd_state *osd, int obj, const char *text);
+
+struct osd_sub_state {
+ struct dec_sub *dec_sub;
+ double video_offset;
+ bool render_bitmap_subs;
+};
+void osd_set_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate);
+void osd_get_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate);
+
+bool osd_get_render_subs_in_filter(struct osd_state *osd);
+void osd_set_render_subs_in_filter(struct osd_state *osd, bool s);
+
+struct osd_progbar_state {
+ int type; // <0: disabled, 1-255: symbol, else: no symbol
+ float value; // range 0.0-1.0
+ float *stops; // used for chapter indicators (0.0-1.0 each)
+ int num_stops;
+};
+void osd_set_progbar(struct osd_state *osd, struct osd_progbar_state *s);
+
+void osd_set_external(struct osd_state *osd, int res_x, int res_y, char *text);
+
+void osd_set_external2(struct osd_state *osd, struct sub_bitmaps *imgs);
+
+void osd_set_nav_highlight(struct osd_state *osd, void *priv);
+
enum mp_osd_draw_flags {
OSD_DRAW_SUB_FILTER = (1 << 0),
OSD_DRAW_SUB_ONLY = (1 << 1),
@@ -230,27 +200,34 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res,
double video_pts, int draw_flags,
struct mp_image_pool *pool, struct mp_image *dest);
-void osd_object_get_scale_factor(struct osd_state *osd, struct osd_object *obj,
+void osd_object_get_scale_factor(struct osd_state *osd, int obj,
double *sw, double *sh);
void osd_coords_to_video(struct osd_state *osd, int frame_w, int frame_h,
int *x, int *y);
+struct mp_osd_res osd_get_vo_res(struct osd_state *osd, int obj);
+
void osd_rescale_bitmaps(struct sub_bitmaps *imgs, int frame_w, int frame_h,
struct mp_osd_res res, double compensate_par);
// defined in osd_libass.c and osd_dummy.c
+// internal use only
void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
struct sub_bitmaps *out_imgs);
-void osd_object_get_resolution(struct osd_state *osd, struct osd_object *obj,
- int *out_w, int *out_h);
-void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);
void osd_init_backend(struct osd_state *osd);
void osd_destroy_backend(struct osd_state *osd);
+// doesn't need locking
+void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);
+
+// defined in backend, but locks if required
+void osd_object_get_resolution(struct osd_state *osd, int obj,
+ int *out_w, int *out_h);
+
// defined in player
-void mp_nav_get_highlight(struct osd_state *osd, struct mp_osd_res res,
+void mp_nav_get_highlight(void *priv, struct mp_osd_res res,
struct sub_bitmaps *out_imgs);
#endif /* MPLAYER_SUB_H */
diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c
index cc2ba37377..6fc78ab368 100644
--- a/sub/osd_dummy.c
+++ b/sub/osd_dummy.c
@@ -24,7 +24,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
*out_imgs = (struct sub_bitmaps) {0};
}
-void osd_object_get_resolution(struct osd_state *osd, struct osd_object *obj,
+void osd_object_get_resolution(struct osd_state *osd, int obj,
int *out_w, int *out_h)
{
*out_w = 0;
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index fb50dce9cd..90807fa60a 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -29,6 +29,7 @@
#include "common/common.h"
#include "common/msg.h"
#include "osd.h"
+#include "osd_state.h"
static const char osd_font_pfb[] =
#include "sub/osd_font.h"
@@ -193,7 +194,7 @@ static void update_osd(struct osd_state *osd, struct osd_object *obj)
create_ass_track(osd, obj, 0, 0);
clear_obj(obj);
- if (!osd->osd_text[0])
+ if (!obj->text[0])
return;
struct osd_style_opts font = *opts->osd_style;
@@ -207,7 +208,7 @@ static void update_osd(struct osd_state *osd, struct osd_object *obj)
ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style;
mp_ass_set_style(style, playresy, &font);
- add_osd_ass_event_escaped(obj->osd_track, osd->osd_text);
+ add_osd_ass_event_escaped(obj->osd_track, obj->text);
}
// align: -1 .. +1
@@ -322,7 +323,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
clear_obj(obj);
- if (osd->progbar_type < 0)
+ if (obj->progbar_state.type < 0)
return;
float sx = px - border * 2 - height / 4; // includes additional spacing
@@ -330,13 +331,13 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
bstr buf = bstr0(talloc_asprintf(NULL, "{\\an6\\pos(%f,%f)}", sx, sy));
- if (osd->progbar_type == 0 || osd->progbar_type >= 256) {
+ if (obj->progbar_state.type == 0 || obj->progbar_state.type >= 256) {
// no sym
- } else if (osd->progbar_type >= 32) {
- mp_append_utf8_bstr(NULL, &buf, osd->progbar_type);
+ } else if (obj->progbar_state.type >= 32) {
+ mp_append_utf8_bstr(NULL, &buf, obj->progbar_state.type);
} else {
bstr_xappend(NULL, &buf, bstr0(ASS_USE_OSD_FONT));
- mp_append_utf8_bstr(NULL, &buf, OSD_CODEPOINTS + osd->progbar_type);
+ mp_append_utf8_bstr(NULL, &buf, OSD_CODEPOINTS + obj->progbar_state.type);
bstr_xappend(NULL, &buf, bstr0("{\\r}"));
}
@@ -347,7 +348,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
// 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;
+ 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, d->text);
@@ -373,8 +374,8 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
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;
+ for (int n = 0; n < obj->progbar_state.num_stops; n++) {
+ float s = obj->progbar_state.stops[n] * width;
float dent = border * 1.3;
if (s > dent && s < width - dent) {
@@ -395,10 +396,10 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
static void update_external(struct osd_state *osd, struct osd_object *obj)
{
- create_ass_track(osd, obj, osd->external_res_x, osd->external_res_y);
+ create_ass_track(osd, obj, obj->external_res_x, obj->external_res_y);
clear_obj(obj);
- bstr t = bstr0(osd->external);
+ bstr t = bstr0(obj->text);
while (t.len) {
bstr line;
bstr_split_tok(t, "\n", &line, &t);
@@ -416,7 +417,7 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj)
clear_obj(obj);
- if (!obj->sub_text || !obj->sub_text[0] || obj->render_bitmap_subs)
+ if (!obj->text || !obj->text[0] || obj->sub_state.render_bitmap_subs)
return;
create_ass_renderer(osd, obj);
@@ -435,7 +436,7 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj)
ass_set_line_position(obj->osd_render, 100 - opts->sub_pos);
#endif
- add_osd_ass_event_escaped(obj->osd_track, obj->sub_text);
+ add_osd_ass_event_escaped(obj->osd_track, obj->text);
}
static void update_object(struct osd_state *osd, struct osd_object *obj)
@@ -474,9 +475,12 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
talloc_steal(obj, obj->parts_cache);
}
-void osd_object_get_resolution(struct osd_state *osd, struct osd_object *obj,
+void osd_object_get_resolution(struct osd_state *osd, int obj,
int *out_w, int *out_h)
{
- *out_w = obj->osd_track ? obj->osd_track->PlayResX : 0;
- *out_h = obj->osd_track ? obj->osd_track->PlayResY : 0;
+ 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);
}
diff --git a/sub/osd_state.h b/sub/osd_state.h
new file mode 100644
index 0000000000..55e484e3e0
--- /dev/null
+++ b/sub/osd_state.h
@@ -0,0 +1,68 @@
+#ifndef MP_OSD_STATE_H_
+#define MP_OSD_STATE_H_
+
+#include <pthread.h>
+
+#include "osd.h"
+
+#define OSD_CONV_CACHE_MAX 4
+
+struct osd_object {
+ int type; // OSDTYPE_*
+ bool is_sub;
+
+ bool force_redraw;
+
+ // OSDTYPE_SUB/OSDTYPE_SUB2/OSDTYPE_OSD/OSDTYPE_EXTERNAL
+ char *text;
+
+ // OSDTYPE_PROGBAR
+ struct osd_progbar_state progbar_state;
+
+ // OSDTYPE_SUB/OSDTYPE_SUB2
+ struct osd_sub_state sub_state;
+
+ // OSDTYPE_EXTERNAL
+ int external_res_x, external_res_y;
+
+ // OSDTYPE_EXTERNAL2
+ struct sub_bitmaps *external2;
+
+ // OSDTYPE_NAV_HIGHLIGHT
+ void *highlight_priv;
+
+ // caches for OSD conversion (internal to render_object())
+ struct osd_conv_cache *cache[OSD_CONV_CACHE_MAX];
+ struct sub_bitmaps cached;
+
+ // VO cache state
+ int vo_bitmap_id;
+ int vo_bitmap_pos_id;
+ struct mp_osd_res vo_res;
+
+ // Internally used by osd_libass.c
+ struct sub_bitmap *parts_cache;
+ struct ass_track *osd_track;
+ struct ass_renderer *osd_render;
+ struct ass_library *osd_ass_library;
+};
+
+struct osd_state {
+ pthread_mutex_t lock;
+
+ struct osd_object *objs[MAX_OSD_PARTS];
+
+ double vo_pts;
+
+ bool render_subs_in_filter;
+
+ bool want_redraw;
+
+ struct MPOpts *opts;
+ struct mpv_global *global;
+ struct mp_log *log;
+
+ struct mp_draw_sub_cache *draw_cache;
+};
+
+#endif
diff --git a/video/out/gl_osd.c b/video/out/gl_osd.c
index 99b64176ae..393619e554 100644
--- a/video/out/gl_osd.c
+++ b/video/out/gl_osd.c
@@ -282,7 +282,7 @@ void mpgl_osd_draw_cb(struct mpgl_osd *ctx,
{
struct draw_cb_closure c = {ctx, cb, cb_ctx};
reset(ctx);
- osd_draw(osd, res, osd->vo_pts, 0, ctx->formats, draw_cb, &c);
+ osd_draw(osd, res, osd_get_vo_pts(osd), 0, ctx->formats, draw_cb, &c);
}
void mpgl_osd_redraw_cb(struct mpgl_osd *ctx,
@@ -376,5 +376,5 @@ static void draw_legacy_cb(void *pctx, struct sub_bitmaps *imgs)
void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct osd_state *osd,
struct mp_osd_res res)
{
- osd_draw(osd, res, osd->vo_pts, 0, ctx->formats, draw_legacy_cb, ctx);
+ osd_draw(osd, res, osd_get_vo_pts(osd), 0, ctx->formats, draw_legacy_cb, ctx);
}
diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c
index 6e189bc660..10539d4f18 100644
--- a/video/out/vo_direct3d.c
+++ b/video/out/vo_direct3d.c
@@ -1700,7 +1700,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
if (!priv->d3d_device)
return;
- osd_draw(osd, priv->osd_res, osd->vo_pts, 0, osd_fmt_supported,
+ osd_draw(osd, priv->osd_res, osd_get_vo_pts(osd), 0, osd_fmt_supported,
draw_osd_cb, priv);
}
diff --git a/video/out/vo_image.c b/video/out/vo_image.c
index c99eae49b4..f7f3a35822 100644
--- a/video/out/vo_image.c
+++ b/video/out/vo_image.c
@@ -97,7 +97,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.display_par = sar / dar,
};
- osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, p->current);
+ osd_draw_on_image(osd, dim, osd_get_vo_pts(osd), OSD_DRAW_SUB_ONLY, p->current);
}
static void flip_page(struct vo *vo)
diff --git a/video/out/vo_lavc.c b/video/out/vo_lavc.c
index c0b317da94..8a784db37b 100644
--- a/video/out/vo_lavc.c
+++ b/video/out/vo_lavc.c
@@ -500,7 +500,8 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
mp_image_set_colorspace_details(vc->lastimg, &vc->colorspace);
- osd_draw_on_image(osd, dim, osd->vo_pts, OSD_DRAW_SUB_ONLY, vc->lastimg);
+ osd_draw_on_image(osd, dim, osd_get_vo_pts(osd), OSD_DRAW_SUB_ONLY,
+ vc->lastimg);
}
}
diff --git a/video/out/vo_sdl.c b/video/out/vo_sdl.c
index 893279a8f4..3f743a17a4 100644
--- a/video/out/vo_sdl.c
+++ b/video/out/vo_sdl.c
@@ -727,7 +727,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
[SUBBITMAP_RGBA] = true,
};
- osd_draw(osd, vc->osd_res, osd->vo_pts, 0, osdformats, draw_osd_cb, vo);
+ osd_draw(osd, vc->osd_res, osd_get_vo_pts(osd), 0, osdformats, draw_osd_cb, vo);
}
static int preinit(struct vo *vo)
diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c
index cd2768a3ea..4876c454d9 100644
--- a/video/out/vo_vaapi.c
+++ b/video/out/vo_vaapi.c
@@ -435,7 +435,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
for (int n = 0; n < MAX_OSD_PARTS; n++)
p->osd_parts[n].active = false;
- osd_draw(osd, *res, osd->vo_pts, 0, osd_formats, draw_osd_cb, p);
+ osd_draw(osd, *res, osd_get_vo_pts(osd), 0, osd_formats, draw_osd_cb, p);
}
static int get_displayattribtype(const char *name)
diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c
index 5a0d11206a..c93c3eb0a6 100644
--- a/video/out/vo_vdpau.c
+++ b/video/out/vo_vdpau.c
@@ -997,7 +997,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
[SUBBITMAP_RGBA] = true,
};
- osd_draw(osd, vc->osd_rect, osd->vo_pts, 0, formats, draw_osd_cb, vo);
+ osd_draw(osd, vc->osd_rect, osd_get_vo_pts(osd), 0, formats, draw_osd_cb, vo);
}
static int update_presentation_queue_status(struct vo *vo)
diff --git a/video/out/vo_wayland.c b/video/out/vo_wayland.c
index 1d9025b245..3ab9246553 100644
--- a/video/out/vo_wayland.c
+++ b/video/out/vo_wayland.c
@@ -560,7 +560,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
{
struct priv *p = vo->priv;
struct mp_image img = buffer_get_mp_image(p, p->back_buffer);
- osd_draw_on_image(osd, p->osd, osd->vo_pts, 0, &img);
+ osd_draw_on_image(osd, p->osd, osd_get_vo_pts(osd), 0, &img);
}
static void flip_page(struct vo *vo)
diff --git a/video/out/vo_x11.c b/video/out/vo_x11.c
index 8240f55b25..0da8715f5d 100644
--- a/video/out/vo_x11.c
+++ b/video/out/vo_x11.c
@@ -427,7 +427,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
struct mp_image img = get_x_buffer(p, p->current_buf);
- osd_draw_on_image(osd, p->osd, osd->vo_pts, 0, &img);
+ osd_draw_on_image(osd, p->osd, osd_get_vo_pts(osd), 0, &img);
}
static mp_image_t *get_screenshot(struct vo *vo)
diff --git a/video/out/vo_xv.c b/video/out/vo_xv.c
index 046dc21d85..53a46cbe5a 100644
--- a/video/out/vo_xv.c
+++ b/video/out/vo_xv.c
@@ -622,7 +622,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd)
.display_par = 1.0 / vo->aspdat.par,
};
- osd_draw_on_image(osd, res, osd->vo_pts, 0, &img);
+ osd_draw_on_image(osd, res, osd_get_vo_pts(osd), 0, &img);
}
static void wait_for_completion(struct vo *vo, int max_outstanding)