summaryrefslogtreecommitdiffstats
path: root/player
diff options
context:
space:
mode:
Diffstat (limited to 'player')
-rw-r--r--player/command.c155
-rw-r--r--player/core.h2
-rw-r--r--player/loadfile.c8
-rw-r--r--player/lua.c2
-rw-r--r--player/lua/osc.lua3
-rw-r--r--player/lua/stats.lua203
-rw-r--r--player/misc.c3
-rw-r--r--player/playloop.c20
-rw-r--r--player/sub.c16
-rw-r--r--player/video.c1
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;
}