diff options
Diffstat (limited to 'player')
-rw-r--r-- | player/command.c | 155 | ||||
-rw-r--r-- | player/core.h | 2 | ||||
-rw-r--r-- | player/loadfile.c | 8 | ||||
-rw-r--r-- | player/lua.c | 2 | ||||
-rw-r--r-- | player/lua/osc.lua | 3 | ||||
-rw-r--r-- | player/lua/stats.lua | 203 | ||||
-rw-r--r-- | player/misc.c | 3 | ||||
-rw-r--r-- | player/playloop.c | 20 | ||||
-rw-r--r-- | player/sub.c | 16 | ||||
-rw-r--r-- | player/video.c | 1 |
10 files changed, 295 insertions, 118 deletions
diff --git a/player/command.c b/player/command.c index bcac0828e0..0673ecb032 100644 --- a/player/command.c +++ b/player/command.c @@ -114,6 +114,7 @@ struct command_ctx { char **script_props; mpv_node udata; + mpv_node mdata; double cached_window_scale; }; @@ -126,6 +127,10 @@ static const struct m_option udata_type = { .type = CONF_TYPE_NODE }; +static const struct m_option mdata_type = { + .type = CONF_TYPE_NODE +}; + struct overlay { struct mp_image *source; int x, y; @@ -154,12 +159,15 @@ struct load_action { bool play; }; -// U+279C HEAVY ROUND-TIPPED RIGHTWARDS ARROW +// U+25CB WHITE CIRCLE +// U+25CF BLACK CIRCLE // U+00A0 NO-BREAK SPACE -#define ARROW_SP "\342\236\234\302\240" +#define WHITECIRCLE "\xe2\x97\x8b" +#define BLACKCIRCLE "\xe2\x97\x8f" +#define NBSP "\xc2\xa0" -const char list_current[] = OSD_ASS_0 ARROW_SP OSD_ASS_1; -const char list_normal[] = OSD_ASS_0 "{\\alpha&HFF}" ARROW_SP "{\\r}" OSD_ASS_1; +const char list_current[] = BLACKCIRCLE NBSP; +const char list_normal[] = WHITECIRCLE NBSP; static int edit_filters(struct MPContext *mpctx, struct mp_log *log, enum stream_type mediatype, @@ -1821,28 +1829,6 @@ static int mp_property_audio_delay(void *ctx, struct m_property *prop, return mp_property_generic_option(mpctx, prop, action, arg); } -/// Audio codec tag (RO) -static int mp_property_audio_codec_name(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct track *track = mpctx->current_track[0][STREAM_AUDIO]; - const char *c = track && track->stream ? track->stream->codec->codec : NULL; - return m_property_strdup_ro(action, arg, c); -} - -/// Audio codec name (RO) -static int mp_property_audio_codec(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct track *track = mpctx->current_track[0][STREAM_AUDIO]; - char desc[256] = ""; - if (track && track->dec) - mp_decoder_wrapper_get_desc(track->dec, desc, sizeof(desc)); - return m_property_strdup_ro(action, arg, desc[0] ? desc : NULL); -} - static int property_audiofmt(struct mp_aframe *fmt, int action, void *arg) { if (!fmt || !mp_aframe_config_is_valid(fmt)) @@ -1991,10 +1977,6 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) struct mp_codec_params p = track->stream ? *track->stream->codec : (struct mp_codec_params){0}; - char decoder_desc[256] = {0}; - if (track->dec) - mp_decoder_wrapper_get_desc(track->dec, decoder_desc, sizeof(decoder_desc)); - bool has_rg = track->stream && track->stream->codec->replaygain_data; struct replaygain_data rg = has_rg ? *track->stream->codec->replaygain_data : (struct replaygain_data){0}; @@ -2043,10 +2025,16 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) .unavailable = !track->hls_bitrate}, {"program-id", SUB_PROP_INT(track->program_id), .unavailable = track->program_id < 0}, - {"decoder-desc", SUB_PROP_STR(decoder_desc), - .unavailable = !decoder_desc[0]}, + {"decoder", SUB_PROP_STR(p.decoder), + .unavailable = !p.decoder}, + {"decoder-desc", SUB_PROP_STR(p.decoder_desc), + .unavailable = !p.decoder_desc}, {"codec", SUB_PROP_STR(p.codec), .unavailable = !p.codec}, + {"codec-desc", SUB_PROP_STR(p.codec_desc), + .unavailable = !p.codec_desc}, + {"codec-profile", SUB_PROP_STR(p.codec_profile), + .unavailable = !p.codec_profile}, {"demux-w", SUB_PROP_INT(p.disp_w), .unavailable = !p.disp_w}, {"demux-h", SUB_PROP_INT(p.disp_h), .unavailable = !p.disp_h}, {"demux-crop-x",SUB_PROP_INT(p.crop.x0), .unavailable = !has_crop}, @@ -2256,28 +2244,6 @@ static int mp_property_frame_count(void *ctx, struct m_property *prop, return m_property_int_ro(action, arg, frames); } -/// Video codec tag (RO) -static int mp_property_video_format(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct track *track = mpctx->current_track[0][STREAM_VIDEO]; - const char *c = track && track->stream ? track->stream->codec->codec : NULL; - return m_property_strdup_ro(action, arg, c); -} - -/// Video codec name (RO) -static int mp_property_video_codec(void *ctx, struct m_property *prop, - int action, void *arg) -{ - MPContext *mpctx = ctx; - struct track *track = mpctx->current_track[0][STREAM_VIDEO]; - char desc[256] = ""; - if (track && track->dec) - mp_decoder_wrapper_get_desc(track->dec, desc, sizeof(desc)); - return m_property_strdup_ro(action, arg, desc[0] ? desc : NULL); -} - static const char *get_aspect_ratio_name(double ratio) { // Depending on cropping/mastering exact ratio may differ. @@ -3055,6 +3021,20 @@ static int mp_property_sub_text(void *ctx, struct m_property *prop, int sub_index = def[0]; int type = def[1]; + if (action == M_PROPERTY_KEY_ACTION) { + struct m_property_action_arg *ka = arg; + + if (!strcmp(ka->key, "ass")) + type = SD_TEXT_TYPE_ASS; + else if (!strcmp(ka->key, "ass-full")) + type = SD_TEXT_TYPE_ASS_FULL; + else + return M_PROPERTY_UNKNOWN; + + action = ka->action; + arg = ka->arg; + } + struct track *track = mpctx->current_track[sub_index][STREAM_SUB]; struct dec_sub *sub = track ? track->d_sub : NULL; double pts = mpctx->playback_pts; @@ -3096,7 +3076,7 @@ static int mp_property_sub_start(void *ctx, struct m_property *prop, double start = get_times(ctx, prop, action, arg).start; if (start == MP_NOPTS_VALUE) return M_PROPERTY_UNAVAILABLE; - return m_property_double_ro(action, arg, start); + return property_time(action, arg, start); } @@ -3106,7 +3086,7 @@ static int mp_property_sub_end(void *ctx, struct m_property *prop, double end = get_times(ctx, prop, action, arg).end; if (end == MP_NOPTS_VALUE) return M_PROPERTY_UNAVAILABLE; - return m_property_double_ro(action, arg, end); + return property_time(action, arg, end); } static int mp_property_playlist_current_pos(void *ctx, struct m_property *prop, @@ -3730,6 +3710,35 @@ static int mp_property_bindings(void *ctx, struct m_property *prop, return M_PROPERTY_NOT_IMPLEMENTED; } +static int mp_property_mdata(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + mpv_node *node = &mpctx->command_ctx->mdata; + + switch (action) { + case M_PROPERTY_GET_TYPE: + *(struct m_option *)arg = (struct m_option){.type = CONF_TYPE_NODE}; + return M_PROPERTY_OK; + case M_PROPERTY_GET: + case M_PROPERTY_GET_NODE: + m_option_copy(&mdata_type, arg, node); + return M_PROPERTY_OK; + case M_PROPERTY_SET: + case M_PROPERTY_SET_NODE: { + m_option_copy(&mdata_type, node, arg); + talloc_steal(mpctx->command_ctx, node_get_alloc(node)); + mp_notify_property(mpctx, prop->name); + + struct vo *vo = mpctx->video_out; + if (vo) + vo_control(vo, VOCTRL_UPDATE_MENU, arg); + return M_PROPERTY_OK; + } + } + return M_PROPERTY_NOT_IMPLEMENTED; +} + static int do_list_udata(int item, int action, void *arg, void *ctx); struct udata_ctx { @@ -3990,8 +3999,8 @@ static const struct m_property mp_properties_base[] = { {"ao-volume", mp_property_ao_volume}, {"ao-mute", mp_property_ao_mute}, {"audio-delay", mp_property_audio_delay}, - {"audio-codec-name", mp_property_audio_codec_name}, - {"audio-codec", mp_property_audio_codec}, + M_PROPERTY_ALIAS("audio-codec-name", "current-tracks/audio/codec"), + M_PROPERTY_ALIAS("audio-codec", "current-tracks/audio/codec-desc"), {"audio-params", mp_property_audio_params}, {"audio-out-params", mp_property_audio_out_params}, {"aid", property_switch_track, .priv = (void *)(const int[]){0, STREAM_AUDIO}}, @@ -4004,9 +4013,9 @@ static const struct m_property mp_properties_base[] = { {"video-out-params", mp_property_vo_imgparams}, {"video-dec-params", mp_property_dec_imgparams}, {"video-params", mp_property_vd_imgparams}, - {"video-format", mp_property_video_format}, {"video-frame-info", mp_property_video_frame_info}, - {"video-codec", mp_property_video_codec}, + M_PROPERTY_ALIAS("video-format", "current-tracks/video/codec"), + M_PROPERTY_ALIAS("video-codec", "current-tracks/video/codec-desc"), M_PROPERTY_ALIAS("dwidth", "video-out-params/dw"), M_PROPERTY_ALIAS("dheight", "video-out-params/dh"), M_PROPERTY_ALIAS("width", "video-params/w"), @@ -4053,8 +4062,7 @@ static const struct m_property mp_properties_base[] = { .priv = (void *)&(const int[]){0, SD_TEXT_TYPE_PLAIN}}, {"secondary-sub-text", mp_property_sub_text, .priv = (void *)&(const int[]){1, SD_TEXT_TYPE_PLAIN}}, - {"sub-text-ass", mp_property_sub_text, - .priv = (void *)&(const int[]){0, SD_TEXT_TYPE_ASS}}, + M_PROPERTY_DEPRECATED_ALIAS("sub-text-ass", "sub-text/ass"), {"sub-start", mp_property_sub_start, .priv = (void *)&(const int){0}}, {"secondary-sub-start", mp_property_sub_start, @@ -4109,6 +4117,8 @@ static const struct m_property mp_properties_base[] = { {"command-list", mp_property_commands}, {"input-bindings", mp_property_bindings}, + {"menu-data", mp_property_mdata}, + {"user-data", mp_property_udata}, {"term-size", mp_property_term_size}, @@ -4150,10 +4160,10 @@ static const char *const *const mp_event_property_change[] = { "video-format", "video-codec", "video-bitrate", "dwidth", "dheight", "width", "height", "container-fps", "aspect", "aspect-name", "vo-configured", "current-vo", "video-dec-params", "osd-dimensions", "hwdec", "hwdec-current", "hwdec-interop", - "window-id"), + "window-id", "track-list", "current-tracks"), E(MPV_EVENT_AUDIO_RECONFIG, "audio-format", "audio-codec", "audio-bitrate", "samplerate", "channels", "audio", "volume", "volume-gain", "mute", - "current-ao", "audio-codec-name", "audio-params", + "current-ao", "audio-codec-name", "audio-params", "track-list", "current-tracks", "audio-out-params", "volume-max", "volume-gain-min", "volume-gain-max", "mixer-active"), E(MPV_EVENT_SEEK, "seeking", "core-idle", "eof-reached"), E(MPV_EVENT_PLAYBACK_RESTART, "seeking", "core-idle", "eof-reached"), @@ -6567,6 +6577,16 @@ static void cmd_begin_vo_dragging(void *p) vo_control(vo, VOCTRL_BEGIN_DRAGGING, NULL); } +static void cmd_context_menu(void *p) +{ + struct mp_cmd_ctx *cmd = p; + struct MPContext *mpctx = cmd->mpctx; + struct vo *vo = mpctx->video_out; + + if (vo) + vo_control(vo, VOCTRL_SHOW_MENU, NULL); +} + /* This array defines all known commands. * The first field the command name used in libmpv and input.conf. * The second field is the handler function (see mp_cmd_def.handler and @@ -7039,6 +7059,8 @@ const struct mp_cmd_def mp_cmds[] = { { "begin-vo-dragging", cmd_begin_vo_dragging }, + { "context-menu", cmd_context_menu }, + {0} }; @@ -7123,6 +7145,9 @@ void command_init(struct MPContext *mpctx) ctx->properties[count++] = prop; } + node_init(&ctx->mdata, MPV_FORMAT_NODE_ARRAY, NULL); + talloc_steal(ctx, ctx->mdata.u.list); + node_init(&ctx->udata, MPV_FORMAT_NODE_MAP, NULL); talloc_steal(ctx, ctx->udata.u.list); talloc_free(prop_names); @@ -7294,7 +7319,7 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags, } if (opt_ptr == &opts->vo->video_driver_list || - opt_ptr == &opts->ra_ctx_opts->context_name || + opt_ptr == &opts->ra_ctx_opts->context_list || opt_ptr == &opts->ra_ctx_opts->context_type) { struct track *track = mpctx->current_track[0][STREAM_VIDEO]; uninit_video_out(mpctx); diff --git a/player/core.h b/player/core.h index 5e97b6d868..c44868cecd 100644 --- a/player/core.h +++ b/player/core.h @@ -132,6 +132,8 @@ struct track { char *external_filename; bool auto_loaded; + bool demuxer_ready; // if more packets should be read (subtitles only) + struct demuxer *demuxer; // Invariant: !stream || stream->demuxer == demuxer struct sh_stream *stream; diff --git a/player/loadfile.c b/player/loadfile.c index b8ccf6723e..a8dfda8c1c 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -278,6 +278,8 @@ static void print_stream(struct MPContext *mpctx, struct track *t) APPEND(b, " '%s'", t->title); const char *codec = s ? s->codec->codec : NULL; APPEND(b, " (%s", codec ? codec : "<unknown>"); + if (s && s->codec->codec_profile) + APPEND(b, " [%s]", s->codec->codec_profile); if (t->type == STREAM_VIDEO) { if (s && s->codec->disp_w) APPEND(b, " %dx%d", s->codec->disp_w, s->codec->disp_h); @@ -505,15 +507,14 @@ static bool compare_track(struct track *t1, struct track *t2, char **langs, bool return t1->program_id == preferred_program; } int l1 = match_lang(langs, t1->lang), l2 = match_lang(langs, t2->lang); - t1->forced_select = sub && forced && t1->forced_track; if (!os_langs && l1 != l2) return l1 > l2; if (forced) return t1->forced_track; - if (sub && !t2->forced_select && t2->forced_track) - return !t1->forced_track; if (t1->default_track != t2->default_track && !t2->forced_select) return t1->default_track; + if (sub && !t2->forced_select && t2->forced_track) + return !t1->forced_track; if (os_langs && l1 != l2) return l1 > l2; if (t1->attached_picture != t2->attached_picture) @@ -656,6 +657,7 @@ struct track *select_default_track(struct MPContext *mpctx, int order, (pick && compare_track(track, pick, langs, os_langs, forced, mpctx->opts, preferred_program)))) { pick = track; + pick->forced_select = forced; } } else if (!pick || compare_track(track, pick, langs, os_langs, false, mpctx->opts, preferred_program)) { pick = track; diff --git a/player/lua.c b/player/lua.c index b2548387f6..63547694e2 100644 --- a/player/lua.c +++ b/player/lua.c @@ -512,7 +512,7 @@ static int script_log(lua_State *L) const char *s = lua_tostring(L, -1); if (s == NULL) return luaL_error(L, "Invalid argument"); - mp_msg(ctx->log, msgl, "%s%s", s, i > 0 ? " " : ""); + mp_msg(ctx->log, msgl, (i == 2 ? "%s" : " %s"), s); lua_pop(L, 1); // args... tostring } mp_msg(ctx->log, msgl, "\n"); diff --git a/player/lua/osc.lua b/player/lua/osc.lua index 3ba1890a92..467f58bea6 100644 --- a/player/lua/osc.lua +++ b/player/lua/osc.lua @@ -57,6 +57,7 @@ local user_opts = { livemarkers = true, -- update seekbar chapter markers on duration change chapters_osd = true, -- whether to show chapters OSD on next/prev playlist_osd = true, -- whether to show playlist OSD on next/prev + playlist_media_title = true, -- whether to use media titles as playlist entry names chapter_fmt = "Chapter: %s", -- chapter print format for seekbar-hover. "no" to disable unicodeminus = false, -- whether to use the Unicode minus sign character } @@ -913,7 +914,7 @@ function get_playlist() for i, v in ipairs(limlist) do local title = v.title local _, filename = utils.split_path(v.filename) - if title == nil then + if not user_opts.playlist_media_title or title == nil then title = filename end message = string.format('%s %s %s\n', message, diff --git a/player/lua/stats.lua b/player/lua/stats.lua index 2feded2808..0085c22638 100644 --- a/player/lua/stats.lua +++ b/player/lua/stats.lua @@ -9,6 +9,7 @@ local mp = require 'mp' local options = require 'mp.options' local utils = require 'mp.utils' +local input = require 'mp.input' -- Options local o = { @@ -21,6 +22,7 @@ local o = { -- For pages which support scrolling key_scroll_up = "UP", key_scroll_down = "DOWN", + key_search = "/", scroll_lines = 1, duration = 4, @@ -45,18 +47,20 @@ local o = { plot_bg_border_color = "0000FF", plot_bg_color = "262626", plot_color = "FFFFFF", + plot_bg_border_width = 0.5, -- Text style - font = "sans-serif", + font = "", font_mono = "monospace", -- monospaced digits are sufficient font_size = 8, - font_color = "FFFFFF", + font_color = "", border_size = 0.8, - border_color = "262626", + border_color = "", shadow_x_offset = 0.0, shadow_y_offset = 0.0, - shadow_color = "000000", + shadow_color = "", alpha = "11", + vidscale = true, -- Custom header for ASS tags to style the text output. -- Specifying this will ignore the text style values above and just @@ -98,6 +102,12 @@ local format = string.format local max = math.max local min = math.min +-- Scaled metrics +local font_size = o.font_size +local border_size = o.border_size +local shadow_x_offset = o.shadow_x_offset +local shadow_y_offset = o.shadow_y_offset +local plot_bg_border_width = o.plot_bg_border_width -- Function used to record performance data local recorder = nil -- Timer used for redrawing (toggling) and clearing the screen (oneshot) @@ -108,6 +118,7 @@ local cache_recorder_timer = nil local curr_page = o.key_page_1 local pages = {} local scroll_bound = false +local searched_text local tm_viz_prev = nil -- Save these sequences locally as we'll need them a lot local ass_start = mp.get_property_osd("osd-ass-cc/0") @@ -158,13 +169,26 @@ local function text_style() if o.custom_header and o.custom_header ~= "" then return o.custom_header else - local has_shadow = mp.get_property('osd-back-color'):sub(2, 3) == '00' - return format("{\\r\\an7\\fs%d\\fn%s\\bord%f\\3c&H%s&" .. - "\\1c&H%s&\\1a&H%s&\\3a&H%s&" .. - (has_shadow and "\\4a&H%s&\\xshad%f\\yshad%f\\4c&H%s&}" or "}"), - o.font_size, o.font, o.border_size, - o.border_color, o.font_color, o.alpha, o.alpha, o.alpha, - o.shadow_x_offset, o.shadow_y_offset, o.shadow_color) + local style = "{\\r\\an7\\fs" .. font_size .. "\\bord" .. border_size + + if o.font ~= "" then + style = style .. "\\fn" .. o.font + end + + if o.font_color ~= "" then + style = style .. "\\1c&H" .. o.font_color .. "&\\1a&H" .. o.alpha .. "&" + end + + if o.border_color ~= "" then + style = style .. "\\3c&H" .. o.border_color .. "&\\3a&H" .. o.alpha .. "&" + end + + if o.shadow_color ~= "" then + style = style .. "\\4c&H" .. o.shadow_color .. "&\\4a&H" .. o.alpha .. "&" + end + + return style .. "\\xshad" .. shadow_x_offset .. + "\\yshad" .. shadow_y_offset .. "}" end end @@ -194,8 +218,8 @@ local function generate_graph(values, i, len, v_max, v_avg, scale, x_tics) end local x_max = (len - 1) * x_tics - local y_offset = o.border_size - local y_max = o.font_size * 0.66 + local y_offset = border_size + local y_max = font_size * 0.66 local x = 0 if v_max > 0 then @@ -219,9 +243,9 @@ local function generate_graph(values, i, len, v_max, v_avg, scale, x_tics) s[#s+1] = format("%f %f %f %f", x, y_max, 0, y_max) - local bg_box = format("{\\bord0.5}{\\3c&H%s&}{\\1c&H%s&}m 0 %f l %f %f %f 0 0 0", - o.plot_bg_border_color, o.plot_bg_color, y_max, x_max, y_max, x_max) - return format("%s{\\r}{\\rDefault}{\\pbo%f}{\\shad0}{\\alpha&H00}{\\p1}%s{\\p0}{\\bord0}{\\1c&H%s}{\\p1}%s{\\p0}%s", + local bg_box = format("{\\bord%f}{\\3c&H%s&}{\\1c&H%s&}m 0 %f l %f %f %f 0 0 0", + plot_bg_border_width, o.plot_bg_border_color, o.plot_bg_color, y_max, x_max, y_max, x_max) + return format("%s{\\rDefault}{\\pbo%f}{\\shad0}{\\alpha&H00}{\\p1}%s{\\p0}{\\bord0}{\\1c&H%s}{\\p1}%s{\\p0}%s", o.prefix_sep, y_offset, bg_box, o.plot_color, table.concat(s), text_style()) end @@ -276,10 +300,14 @@ local function sorted_keys(t, comp_fn) return keys end -local function scroll_hint() - local hint = format("(hint: scroll with %s/%s)", o.key_scroll_up, o.key_scroll_down) +local function scroll_hint(search) + local hint = format("(hint: scroll with %s/%s", o.key_scroll_up, o.key_scroll_down) + if search then + hint = hint .. " and search with " .. o.key_search + end + hint = hint .. ")" if not o.use_ass then return " " .. hint end - return format(" {\\fs%s}%s{\\fs%s}", o.font_size * 0.66, hint, o.font_size) + return format(" {\\fs%s}%s{\\fs%s}", font_size * 0.66, hint, font_size) end local function append_perfdata(header, s, dedicated_page, print_passes) @@ -326,8 +354,8 @@ local function append_perfdata(header, s, dedicated_page, print_passes) local h = dedicated_page and header or s h[#h+1] = format("%s%s%s%s{\\fs%s}%s{\\fs%s}%s", dedicated_page and "" or o.nl, dedicated_page and "" or o.indent, - b("Frame Timings:"), o.prefix_sep, o.font_size * 0.66, - "(last/average/peak μs)", o.font_size, + b("Frame Timings:"), o.prefix_sep, font_size * 0.66, + "(last/average/peak μs)", font_size, dedicated_page and scroll_hint() or "") for _,frame in ipairs(sorted_keys(vo_p)) do -- ensure fixed display order @@ -431,6 +459,11 @@ local function get_kbinfo_lines() (bind.is_weak == active[bind.key].is_weak and bind.priority > active[bind.key].priority) ) and not bind.cmd:find("script-binding stats/__forced_", 1, true) + and bind.section ~= "input_forced_console" + and ( + searched_text == nil or + (bind.key .. bind.cmd):lower():find(searched_text, 1, true) + ) then active[bind.key] = bind end @@ -481,8 +514,8 @@ local function get_kbinfo_lines() local kpost = term and " " or format(" {\\fn%s}", o.font) local spre = term and kspaces .. " " or format("{\\q2\\fn%s}%s {\\fn%s}{\\fs%d\\u1}", - o.font_mono, kspaces, o.font, 1.3*o.font_size) - local spost = term and "" or format("{\\u0\\fs%d}", o.font_size) + o.font_mono, kspaces, o.font, 1.3*font_size) + local spost = term and "" or format("{\\u0\\fs%d}", font_size) -- create the display lines local info_lines = {} @@ -862,18 +895,23 @@ local function add_video_out(s) scale = mp.get_property_native("current-window-scale") end - local r = mp.get_property_native("video-target-params") - if not r then - local osd_dims = mp.get_property_native("osd-dimensions") - local scaled_width = osd_dims["w"] - osd_dims["ml"] - osd_dims["mr"] - local scaled_height = osd_dims["h"] - osd_dims["mt"] - osd_dims["mb"] - append_resolution(s, {w=scaled_width, h=scaled_height, s=scale}, - "Resolution:") - return - end + local od = mp.get_property_native("osd-dimensions") + local rt = mp.get_property_native("video-target-params") + r = rt or {} -- Add window scale r["s"] = scale + r["crop-x"] = od["ml"] + r["crop-y"] = od["mt"] + r["crop-w"] = od["w"] - od["ml"] - od["mr"] + r["crop-h"] = od["h"] - od["mt"] - od["mb"] + + if not rt then + r["w"] = r["crop-w"] + r["h"] = r["crop-h"] + append_resolution(s, r, "Resolution:", "w", "h", true) + return + end append_img_params(s, r) append_hdr(s, r, true) @@ -891,12 +929,15 @@ local function add_video(s) return end - local osd_dims = mp.get_property_native("osd-dimensions") - local scaled_width = osd_dims["w"] - osd_dims["ml"] - osd_dims["mr"] - local scaled_height = osd_dims["h"] - osd_dims["mt"] - osd_dims["mb"] - append(s, "", {prefix=o.nl .. o.nl .. "Video:", nl="", indent=""}) - if append_property(s, "video-codec", {prefix_sep="", nl="", indent=""}) then + local track = mp.get_property_native("current-tracks/video") + if track and append(s, track["codec-desc"], {prefix_sep="", nl="", indent=""}) then + append(s, track["codec-profile"], {prefix="[", nl="", indent=" ", prefix_sep="", + no_prefix_markup=true, suffix="]"}) + if track["codec"] ~= track["decoder"] then + append(s, track["decoder"], {prefix="[", nl="", indent=" ", prefix_sep="", + no_prefix_markup=true, suffix="]"}) + end append_property(s, "hwdec-current", {prefix="HW:", nl="", indent=o.prefix_sep .. o.prefix_sep, no_prefix_markup=false, suffix=""}, {no=true, [""]=true}) @@ -945,11 +986,20 @@ local function add_audio(s) local merge = function(r, ro, prop) local a = r[prop] or ro[prop] local b = ro[prop] or r[prop] - return (a == b or a == nil) and a or (a .. " → " .. b) + return (a == b or a == nil) and a or (a .. " ➜ " .. b) end append(s, "", {prefix=o.nl .. o.nl .. "Audio:", nl="", indent=""}) - append_property(s, "audio-codec", {prefix_sep="", nl="", indent=""}) + local track = mp.get_property_native("current-tracks/audio") + if track then + append(s, track["codec-desc"], {prefix_sep="", nl="", indent=""}) + if track["codec"] ~= track["decoder"] then + append(s, track["decoder"], {prefix="[", nl="", indent=" ", prefix_sep="", + no_prefix_markup=true, suffix="]"}) + end + append(s, track["codec-profile"], {prefix="[", nl="", indent=" ", prefix_sep="", + no_prefix_markup=true, suffix="]"}) + end append_property(s, "current-ao", {prefix="AO:", nl="", indent=o.prefix_sep .. o.prefix_sep}) local dev = append_property(s, "audio-device", {prefix="Device:"}) @@ -1096,7 +1146,7 @@ local function vo_stats() add_header(header) append_perfdata(header, content, true, true) header = {table.concat(header)} - return finalize_page(header, content, false) + return finalize_page(header, content, true) end local kbinfo_lines = nil @@ -1105,7 +1155,7 @@ local function keybinding_info(after_scroll, bindlist) local page = pages[o.key_page_4] eval_ass_formatting() add_header(header) - append(header, "", {prefix=format("%s:%s", page.desc, scroll_hint()), nl="", indent=""}) + append(header, "", {prefix=format("%s:%s", page.desc, scroll_hint(true)), nl="", indent=""}) header = {table.concat(header)} if not kbinfo_lines or not after_scroll then @@ -1302,6 +1352,24 @@ local function print_page(page, after_scroll) end end +local function update_scale(name, value) + -- Calculate scaled metrics. + local scale = 1 + if not o.vidscale then + if value <= 1 then + value = 1 + end + scale = 720 / value + end + font_size = o.font_size * scale + border_size = o.border_size * scale + shadow_x_offset = o.shadow_x_offset * scale + shadow_y_offset = o.shadow_y_offset * scale + plot_bg_border_width = o.plot_bg_border_width * scale + if display_timer:is_enabled() then + print_page(curr_page) + end +end local function clear_screen() if o.persistent_overlay then mp.set_osd_ass(0, 0, "") else mp.osd_message("", 0) end @@ -1334,12 +1402,58 @@ local function unbind_scroll() scroll_bound = false end end + +local function filter_bindings() + input.get({ + prompt = "Filter bindings:", + opened = function () + -- This is necessary to close the console if the oneshot + -- display_timer expires without typing anything. + searched_text = "" + end, + edited = function (text) + reset_scroll_offsets() + searched_text = text:lower() + print_page(curr_page) + if display_timer.oneshot then + display_timer:kill() + display_timer:resume() + end + end, + submit = input.terminate, + closed = function () + searched_text = nil + if display_timer:is_enabled() then + print_page(curr_page) + if display_timer.oneshot then + display_timer:kill() + display_timer:resume() + end + end + end, + }) +end + +local function bind_search() + mp.add_forced_key_binding(o.key_search, "__forced_"..o.key_search, filter_bindings) +end + +local function unbind_search() + mp.remove_key_binding("__forced_"..o.key_search) +end + local function update_scroll_bindings(k) if pages[k].scroll then bind_scroll() else unbind_scroll() end + + if k == o.key_page_4 then + bind_search() + else + unbind_search() + end end -- Add keybindings for every page @@ -1366,6 +1480,7 @@ local function remove_page_bindings() mp.remove_key_binding("__forced_"..k) end unbind_scroll() + unbind_search() end @@ -1428,6 +1543,10 @@ display_timer = mp.add_periodic_timer(o.duration, function() if display_timer.oneshot then display_timer:kill() ; clear_screen() ; remove_page_bindings() + -- Close the console only if it was opened for searching bindings. + if searched_text then + input.terminate() + end else print_page(curr_page) end @@ -1477,3 +1596,5 @@ if o.bindlist ~= "no" then mp.command("quit") end) end + +mp.observe_property('osd-height', 'native', update_scale) diff --git a/player/misc.c b/player/misc.c index 693fa5a7e7..1b265e11fa 100644 --- a/player/misc.c +++ b/player/misc.c @@ -252,7 +252,8 @@ void error_on_track(struct MPContext *mpctx, struct track *track) if (track->type == STREAM_VIDEO) MP_INFO(mpctx, "Video: no video\n"); if (mpctx->opts->stop_playback_on_init_failure || - !(mpctx->vo_chain || mpctx->ao_chain)) + (!mpctx->current_track[0][STREAM_AUDIO] && + !mpctx->current_track[0][STREAM_VIDEO])) { if (!mpctx->stop_play) mpctx->stop_play = PT_ERROR; diff --git a/player/playloop.c b/player/playloop.c index bf903e54f7..12239d69ab 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -803,6 +803,22 @@ int get_cache_buffering_percentage(struct MPContext *mpctx) return mpctx->demuxer ? mpctx->cache_buffer : -1; } +static void handle_update_subtitles(struct MPContext *mpctx) +{ + if (mpctx->video_status == STATUS_EOF) { + update_subtitles(mpctx, mpctx->playback_pts); + return; + } + + for (int n = 0; n < mpctx->num_tracks; n++) { + struct track *track = mpctx->tracks[n]; + if (track->type == STREAM_SUB && !track->demuxer_ready) { + update_subtitles(mpctx, mpctx->playback_pts); + break; + } + } +} + static void handle_cursor_autohide(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; @@ -1233,8 +1249,8 @@ void run_playloop(struct MPContext *mpctx) handle_dummy_ticks(mpctx); update_osd_msg(mpctx); - if (mpctx->video_status == STATUS_EOF) - update_subtitles(mpctx, mpctx->playback_pts); + + handle_update_subtitles(mpctx); handle_each_frame_screenshot(mpctx); diff --git a/player/sub.c b/player/sub.c index 998b88d620..65e5732e23 100644 --- a/player/sub.c +++ b/player/sub.c @@ -224,10 +224,18 @@ void reinit_sub(struct MPContext *mpctx, struct track *track) osd_set_sub(mpctx->osd, order, track->d_sub); // When paused we have to wait for packets to be available. - // So just retry until we get a packet in this case. - if (mpctx->playback_initialized) - while (!update_subtitles(mpctx, mpctx->playback_pts) && - mpctx->paused && !mpctx->paused_for_cache); + // Retry on a timeout until we get a packet. If still not successful, + // then queue it for later in the playloop (but this will have a delay). + if (mpctx->playback_initialized) { + track->demuxer_ready = false; + int64_t end = mp_time_ns() + MP_TIME_MS_TO_NS(50); + while (!track->demuxer_ready && mp_time_ns() < end) + track->demuxer_ready = update_subtitles(mpctx, mpctx->playback_pts) || + !mpctx->paused; + if (!track->demuxer_ready) + mp_wakeup_core(mpctx); + + } } void reinit_sub_all(struct MPContext *mpctx) diff --git a/player/video.c b/player/video.c index 777460dcea..f0372b69a5 100644 --- a/player/video.c +++ b/player/video.c @@ -120,6 +120,7 @@ void reset_video_state(struct MPContext *mpctx) mpctx->drop_message_shown = 0; mpctx->display_sync_drift_dir = 0; mpctx->display_sync_error = 0; + mpctx->display_sync_active = 0; mpctx->video_status = mpctx->vo_chain ? STATUS_SYNCING : STATUS_EOF; } |