From 533a6843811573a862de47b424fe5bf7ad71f85e Mon Sep 17 00:00:00 2001 From: Dudemanguy Date: Tue, 4 Mar 2025 12:23:06 -0600 Subject: [PATCH] player: only coalesce callbacks from parsed config files This relaxes what bbac628a1b01261766459c6556e36d2443a42534 introduced. Although it is rare, there may be scripts out there that depend on the old timing. We'd still like to process config files in a sane manner and not cause OOMs so keep the general coalescing mechanism in place but use it selectively. There is one special case with the --input-commands option. We want this coalesced as well so some special handling needs to be added for that. --- input/cmd.h | 1 + options/m_config_frontend.c | 3 +++ options/m_config_frontend.h | 1 + options/m_property.h | 2 ++ player/command.c | 24 +++++++++++++++++++++--- player/command.h | 2 +- player/playloop.c | 2 +- 7 files changed, 30 insertions(+), 5 deletions(-) diff --git a/input/cmd.h b/input/cmd.h index 4a0f9d3800..239404725a 100644 --- a/input/cmd.h +++ b/input/cmd.h @@ -114,6 +114,7 @@ typedef struct mp_cmd { bool repeated : 1; bool mouse_move : 1; bool canceled : 1; + bool coalesce : 1; int mouse_x, mouse_y; struct mp_cmd *queue_next; double scale; // for scaling numeric arguments diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c index 9fe30ac391..2b812e0232 100644 --- a/options/m_config_frontend.c +++ b/options/m_config_frontend.c @@ -737,6 +737,9 @@ int m_config_set_option_cli(struct m_config *config, struct bstr name, param = bstr0("no"); } + if (flags & M_SETOPT_FROM_CONFIG_FILE) + co->coalesce = true; + // This is the only mandatory function mp_assert(co->opt->type->parse); diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h index 8ee42c16e0..97d0d7527e 100644 --- a/options/m_config_frontend.h +++ b/options/m_config_frontend.h @@ -49,6 +49,7 @@ struct m_config_option { bool is_set_from_config : 1; // Set by a config file bool is_set_locally : 1; // Has a backup entry bool warning_was_printed : 1; + bool coalesce : 1; // Property changes should be coalesced int32_t opt_id; // For some m_config APIs const char *name; // Full name (ie option-subopt) const struct m_option *opt; // Option description diff --git a/options/m_property.h b/options/m_property.h index 8fbb83384d..c4838cd204 100644 --- a/options/m_property.h +++ b/options/m_property.h @@ -147,6 +147,8 @@ struct m_property { void *priv; // Special-case: mark options for which command.c uses the option-bridge bool is_option; + // Special-case: option-bridge properties should be coalesced + bool coalesce; }; struct m_property *m_property_list_find(const struct m_property *list, diff --git a/player/command.c b/player/command.c index 49e3456ef0..0a3ece4448 100644 --- a/player/command.c +++ b/player/command.c @@ -434,6 +434,7 @@ static int mp_property_generic_option(void *ctx, struct m_property *prop, m_option_copy(opt->opt, arg, opt->data); return M_PROPERTY_OK; case M_PROPERTY_SET: + opt->coalesce = prop->coalesce; if (m_config_set_option_raw(mpctx->mconfig, opt, arg, 0) < 0) return M_PROPERTY_ERROR; return M_PROPERTY_OK; @@ -5219,8 +5220,17 @@ static void show_property_status(struct mp_cmd_ctx *cmd, const char *name, int r static void change_property_cmd(struct mp_cmd_ctx *cmd, const char *name, int action, void *arg) { + struct m_property *prop = NULL; + if (cmd->cmd->coalesce) { + struct command_ctx *ctx = cmd->mpctx->command_ctx; + prop = m_property_list_find(ctx->properties, name); + if (prop) + prop->coalesce = true; + } int r = mp_property_do(name, action, arg, cmd->mpctx); show_property_status(cmd, name, r); + if (prop) + prop->coalesce = false; } static void cmd_cycle_values(void *p) @@ -7657,6 +7667,7 @@ void run_command_opts(struct MPContext *mpctx) for (int i = 0; opts->input_commands[i]; i++) { struct mp_cmd *cmd = mp_input_parse_cmd(mpctx->input, bstr0(opts->input_commands[i]), "the command line"); + cmd->coalesce = true; mp_input_queue_cmd(mpctx->input, cmd); } ctx->command_opts_processed = true; @@ -7715,6 +7726,13 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t f if (self_update) return; + // Run these immediately. + if (co && !co->coalesce) { + struct mp_option_callback callback = {.co = co, .flags = flags}; + mp_option_run_callback(mpctx, &callback); + return; + } + // Coalesce redundant updates and only keep the newest one. bool drop = false; for (int i = 0; i < mpctx->num_option_callbacks; i++) { @@ -7737,12 +7755,12 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t f } } -void mp_option_run_callback(struct MPContext *mpctx, int index) +void mp_option_run_callback(struct MPContext *mpctx, struct mp_option_callback *callback) { struct MPOpts *opts = mpctx->opts; - struct m_config_option *co = mpctx->option_callbacks[index].co; + struct m_config_option *co = callback->co; void *opt_ptr = co ? co->data : NULL; - uint64_t flags = mpctx->option_callbacks[index].flags; + uint64_t flags = callback->flags; if (flags & UPDATE_TERM) mp_update_logging(mpctx, false); diff --git a/player/command.h b/player/command.h index cebd56b392..9a24b2d7af 100644 --- a/player/command.h +++ b/player/command.h @@ -87,7 +87,7 @@ int mp_property_do(const char* name, int action, void* val, void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t flags, bool self_update); -void mp_option_run_callback(struct MPContext *mpctx, int index); +void mp_option_run_callback(struct MPContext *mpctx, struct mp_option_callback *callback); void mp_notify(struct MPContext *mpctx, int event, void *arg); void mp_notify_property(struct MPContext *mpctx, const char *property); diff --git a/player/playloop.c b/player/playloop.c index f61cf3a1ff..e4b59dfe69 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -125,7 +125,7 @@ static void mp_process_input(struct MPContext *mpctx) void handle_option_callbacks(struct MPContext *mpctx) { for (int i = 0; i < mpctx->num_option_callbacks; i++) - mp_option_run_callback(mpctx, i); + mp_option_run_callback(mpctx, &mpctx->option_callbacks[i]); mpctx->num_option_callbacks = 0; }