diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index c4e9e18f3e01c..830aa704f1105 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -2697,6 +2697,13 @@ Subtitles Default: yes. +``--sub-osc-margins`` + Whether to adjust the subtitle position so that subtitles do not overlap + with the OSC. Only takes effect when the OSC reports its margins via + ``user-data/osc/margins``. + + Default: yes. + ``--sub-ass-use-video-data=`` Controls which information about the video stream is passed to libass. Any option but ``all`` is incompatible with standard ASS as defined by VSFilter, @@ -4890,6 +4897,13 @@ OSD Set the text layout engine used by libass for the OSD. Default: complex. See also ``--sub-shaper`` +``--osd-osc-margins`` + Whether to adjust the OSD text position so that it does not overlap with + the OSC. Only takes effect when the OSC reports its margins via + ``user-data/osc/margins``. + + Default: yes. + Screenshot ---------- diff --git a/DOCS/man/osc.rst b/DOCS/man/osc.rst index 5981416761916..e75b281b5a904 100644 --- a/DOCS/man/osc.rst +++ b/DOCS/man/osc.rst @@ -408,27 +408,6 @@ Configurable Options applied when the OSC appears and removed when it hides. Without this option, margins are only applied when ``visibility`` is set to ``always``. -``sub_margins`` - Default: yes - - Whether to adjust ``--sub-margin-y`` so that subtitles do not overlap - with the OSC. The offset is derived from the bottom OSC margin and added - on top of the current ``--sub-margin-y`` value. Requires - ``dynamic_margins`` or ``visibility=always`` to take effect. - - With ``boxvideo`` enabled and ``--sub-use-margins=no``, subtitles are - already confined to the video area and this option has no additional - effect. - -``osd_margins`` - Default: yes - - Whether to adjust ``--osd-margin-y`` so that OSD text does not overlap - with the OSC. The offset is derived from the top OSC margin (including - window controls when present) and added on top of the current - ``--osd-margin-y`` value. Requires ``dynamic_margins`` or - ``visibility=always`` to take effect. - ``windowcontrols`` Default: auto (Show window controls if there is no window border) diff --git a/options/options.c b/options/options.c index c5771bd466cdd..56a3c871ea11c 100644 --- a/options/options.c +++ b/options/options.c @@ -318,6 +318,7 @@ const struct m_sub_options mp_subtitle_sub_opts = { {"sub-line-spacing", OPT_FLOAT(sub_line_spacing), M_RANGE(-1000, 1000)}, {"sub-ass-line-spacing", OPT_REPLACED("sub-line-spacing")}, {"sub-use-margins", OPT_BOOL(sub_use_margins)}, + {"sub-osc-margins", OPT_BOOL(sub_osc_margins)}, {"sub-ass-force-margins", OPT_BOOL(ass_use_margins)}, {"sub-ass-vsfilter-color-compat", OPT_CHOICE(ass_vsfilter_color_compat, {"no", 0}, {"basic", 1}, {"full", 2}, {"force-601", 3})}, @@ -360,6 +361,7 @@ const struct m_sub_options mp_subtitle_sub_opts = { .sub_fix_timing_keep = 400, .sub_scale_by_window = true, .sub_use_margins = true, + .sub_osc_margins = true, .sub_scale_with_window = true, .ass_prune_delay = -1.0, .teletext_page = 0, @@ -427,6 +429,7 @@ const struct m_sub_options mp_osd_render_sub_opts = { {"osd-glyph-limit", OPT_INT(osd_glyph_limit)}, {"osd-bitmap-max-size", OPT_INT(osd_bitmap_max_size)}, {"osd-shaper", OPT_CHOICE(osd_shaper, {"simple", 0}, {"complex", 1})}, + {"osd-osc-margins", OPT_BOOL(osd_osc_margins)}, {0} }, .size = sizeof(OPT_BASE_STRUCT), @@ -437,6 +440,7 @@ const struct m_sub_options mp_osd_render_sub_opts = { .osd_selected_outline_color = {0, 0, 0, 255}, .osd_ass_prune_delay = -1.0, .osd_shaper = 1, + .osd_osc_margins = true, }, .change_flags = UPDATE_OSD, }; diff --git a/options/options.h b/options/options.h index a8f82a98103e0..f7f123d7f9007 100644 --- a/options/options.h +++ b/options/options.h @@ -117,6 +117,7 @@ struct mp_subtitle_opts { float sub_line_spacing; bool ass_use_margins; bool sub_use_margins; + bool sub_osc_margins; int ass_vsfilter_color_compat; bool sub_vsfilter_bidi_compat; int ass_use_video_data; @@ -156,6 +157,7 @@ struct mp_osd_render_opts { int osd_glyph_limit; int osd_bitmap_max_size; int osd_shaper; + bool osd_osc_margins; }; struct mp_bluray_opts { diff --git a/player/command.c b/player/command.c index cfa493dc10cd1..17f65fd30e34a 100644 --- a/player/command.c +++ b/player/command.c @@ -4249,6 +4249,26 @@ static int mp_property_udata(void *ctx, struct m_property *prop, int ret = do_op_udata(&nctx, action, arg); + if (ret >= 0 && bstr_startswith0(bstr0(path), "user-data/osc/margins")) { + mpv_node *osc = node_map_get(&mpctx->command_ctx->udata, "osc"); + mpv_node *m = osc ? node_map_get(osc, "margins") : NULL; + double t = 0, b = 0; + if (m && m->format == MPV_FORMAT_NODE_MAP) { + mpv_node *n; + n = node_map_get(m, "t"); + t = (n && n->format == MPV_FORMAT_DOUBLE) ? n->u.double_ : 0; + n = node_map_get(m, "b"); + b = (n && n->format == MPV_FORMAT_DOUBLE) ? n->u.double_ : 0; + } + osd_set_script_margins(mpctx->osd, t, b); + double margins[] = {t, b}; + for (int n = 0; n < num_ptracks[STREAM_SUB]; n++) { + struct track *track = mpctx->current_track[n][STREAM_SUB]; + if (track && track->d_sub) + sub_control(track->d_sub, SD_CTRL_SET_SCRIPT_MARGINS, margins); + } + } + talloc_free(path); return ret; diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 36db44e790402..ffbf85248fa71 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -49,8 +49,6 @@ local user_opts = { boxmaxchars = 80, -- title crop threshold for box layout boxvideo = false, -- apply osc_param.video_margins to video dynamic_margins = false, -- update margins dynamically with OSC visibility - sub_margins = true, -- adjust sub-margin-y to not overlap with OSC - osd_margins = true, -- adjust osd-margin-y to not overlap with OSC windowcontrols = "auto", -- whether to show window controls windowcontrols_alignment = "right", -- which side to show window controls on windowcontrols_title = "${media-title}", -- same as title but for windowcontrols @@ -543,18 +541,6 @@ local function cache_enabled() return state.cache_state and #state.cache_state["seekable-ranges"] > 0 end -local function set_margin_offset(prop, offset) - if offset > 0 then - if not state[prop] then - state[prop] = mp.get_property_number(prop) - end - mp.set_property_number(prop, state[prop] + offset) - elseif state[prop] then - mp.set_property_number(prop, state[prop]) - state[prop] = nil - end -end - local function reset_margins() if state.using_video_margins then for _, mopt in ipairs(margins_opts) do @@ -562,8 +548,6 @@ local function reset_margins() end state.using_video_margins = false end - set_margin_offset("sub-margin-y", 0) - set_margin_offset("osd-margin-y", 0) end local function update_margins() @@ -602,24 +586,6 @@ local function update_margins() reset_margins() end - local function get_margin(ent) - local margin = 0 - if user_opts[ent .. "_margins"] then - local align = mp.get_property(ent .. "-align-y") - if align == "top" and top_vis then - margin = margins.t - elseif align == "bottom" and bottom_vis then - margin = margins.b - end - end - if ent == "sub" and user_opts.boxvideo and mp.get_property_bool("sub-use-margins") then - margin = 0 - end - return margin * osc_param.playresy - end - set_margin_offset("sub-margin-y", get_margin("sub")) - set_margin_offset("osd-margin-y", get_margin("osd")) - mp.set_property_native("user-data/osc/margins", margins) end diff --git a/sub/dec_sub.h b/sub/dec_sub.h index a6d6b585b82c2..571356a5f72ac 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -21,6 +21,7 @@ enum sd_ctrl { SD_CTRL_SET_VIDEO_DEF_FPS, SD_CTRL_RESET_SOFT, SD_CTRL_UPDATE_OPTS, + SD_CTRL_SET_SCRIPT_MARGINS, }; enum sd_text_type { diff --git a/sub/osd.c b/sub/osd.c index 278889739692e..185b25ce4cf3d 100644 --- a/sub/osd.c +++ b/sub/osd.c @@ -311,6 +311,12 @@ void osd_resize(struct osd_state *osd, struct mp_osd_res res) mp_mutex_unlock(&osd->lock); } +void osd_set_script_margins(struct osd_state *osd, double t, double b) +{ + atomic_store(&osd->margin_t, t); + atomic_store(&osd->margin_b, b); +} + static struct sub_bitmaps *render_object(struct osd_state *osd, struct osd_object *obj, struct mp_osd_res osdres, double video_pts, @@ -322,8 +328,14 @@ static struct sub_bitmaps *render_object(struct osd_state *osd, struct sub_bitmaps *res = NULL; + osdres.margin_top = atomic_load(&osd->margin_t); + osdres.margin_bottom = atomic_load(&osd->margin_b); + check_obj_resize(osd, osdres, obj); + obj->vo_res.margin_top = osdres.margin_top; + obj->vo_res.margin_bottom = osdres.margin_bottom; + if (obj->type == OSDTYPE_SUB) { if (obj->sub && sub_is_primary_visible(obj->sub)) res = sub_get_bitmaps(obj->sub, obj->vo_res, format, video_pts); diff --git a/sub/osd.h b/sub/osd.h index 076187573ad80..fad229bab124e 100644 --- a/sub/osd.h +++ b/sub/osd.h @@ -108,6 +108,7 @@ struct mp_osd_res { int w, h; // screen dimensions, including black borders int mt, mb, ml, mr; // borders (top, bottom, left, right) double display_par; + double margin_top, margin_bottom; }; bool osd_res_equals(struct mp_osd_res a, struct mp_osd_res b); @@ -234,6 +235,7 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res, struct mp_image_pool *pool, struct mp_image *dest); void osd_resize(struct osd_state *osd, struct mp_osd_res res); +void osd_set_script_margins(struct osd_state *osd, double t, double b); struct mp_image_params; struct mp_osd_res osd_res_from_image_params(const struct mp_image_params *p); diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 7b0850954ccdb..ead06fd4c4436 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -279,6 +279,15 @@ static ASS_Style *prepare_osd_ass(struct osd_state *osd, struct osd_object *obj) ASS_Style *style = get_style(&obj->ass, "OSD"); mp_ass_set_style(style, playresy, &font); + + if (opts->osd_osc_margins) { + double margin = (font.align_y == -1) ? obj->vo_res.margin_top + : (font.align_y == 1) ? obj->vo_res.margin_bottom + : 0; + if (margin > 0) + style->MarginV += margin * playresy; + } + return style; } diff --git a/sub/osd_state.h b/sub/osd_state.h index cd4ca15a04e3d..d79ea394e3be4 100644 --- a/sub/osd_state.h +++ b/sub/osd_state.h @@ -73,6 +73,8 @@ struct osd_state { bool render_subs_in_filter; _Atomic double force_video_pts; + _Atomic double margin_t, margin_b; + bool want_redraw; bool want_redraw_notification; diff --git a/sub/sd_ass.c b/sub/sd_ass.c index fea432269469d..5afd80561f1d2 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -58,6 +58,7 @@ struct sd_ass_priv { struct mp_image_params video_params; struct mp_image_params last_params; struct mp_osd_res osd; + double script_margin_t, script_margin_b; struct seen_packet *seen_packets; int num_seen_packets; int *packets_animated; @@ -598,6 +599,10 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim, if (converted && track->default_style < track->n_styles) { mp_ass_set_style(track->styles + track->default_style, track->PlayResY, opts->sub_style); + if (opts->sub_osc_margins) { + track->styles[track->default_style].MarginV += + ctx->script_margin_b * track->PlayResY; + } } ass_set_font_scale(priv, set_font_scale); ass_set_hinting(priv, set_hinting); @@ -1041,6 +1046,13 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg) case SD_CTRL_SET_VIDEO_PARAMS: ctx->video_params = *(struct mp_image_params *)arg; return CONTROL_OK; + case SD_CTRL_SET_SCRIPT_MARGINS: { + double *margins = arg; + ctx->script_margin_t = margins[0]; + ctx->script_margin_b = margins[1]; + ctx->ass_configured = false; + return CONTROL_OK; + } case SD_CTRL_UPDATE_OPTS: { uint64_t flags = *(uint64_t *)arg; if (flags & UPDATE_SUB_FILT) {