summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--options/m_config.c125
-rw-r--r--options/m_config.h12
-rw-r--r--player/client.c80
-rw-r--r--player/command.c11
4 files changed, 138 insertions, 90 deletions
diff --git a/options/m_config.c b/options/m_config.c
index 632f27b64f..271b2bde8b 100644
--- a/options/m_config.c
+++ b/options/m_config.c
@@ -471,6 +471,80 @@ const char *m_config_get_positional_option(const struct m_config *config, int p)
return NULL;
}
+// return: <0: M_OPT_ error, 0: skip, 1: check, 2: set
+static int handle_set_opt_flags(struct m_config *config,
+ struct m_config_option *co, int flags)
+{
+ int optflags = co->opt->flags;
+ bool set = !(flags & M_SETOPT_CHECK_ONLY);
+
+ if ((flags & M_SETOPT_PRE_PARSE_ONLY) && !(optflags & M_OPT_PRE_PARSE))
+ return 0;
+
+ if ((flags & M_SETOPT_PRESERVE_CMDLINE) && co->is_set_from_cmdline)
+ set = false;
+
+ if ((flags & M_SETOPT_NO_FIXED) && (optflags & M_OPT_FIXED))
+ return M_OPT_INVALID;
+
+ if ((flags & M_SETOPT_NO_PRE_PARSE) && (optflags & M_OPT_PRE_PARSE))
+ return M_OPT_INVALID;
+
+ // Check if this option isn't forbidden in the current mode
+ if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (optflags & M_OPT_NOCFG)) {
+ MP_ERR(config, "The %s option can't be used in a config file.\n",
+ co->name);
+ return M_OPT_INVALID;
+ }
+ if (flags & M_SETOPT_BACKUP) {
+ if (optflags & M_OPT_GLOBAL) {
+ MP_ERR(config, "The %s option is global and can't be set per-file.\n",
+ co->name);
+ return M_OPT_INVALID;
+ }
+ if (set)
+ ensure_backup(config, co);
+ }
+
+ return set ? 2 : 1;
+}
+
+static void handle_set_from_cmdline(struct m_config *config,
+ struct m_config_option *co)
+{
+ co->is_set_from_cmdline = true;
+ // Mark aliases too
+ if (co->data) {
+ for (int n = 0; n < config->num_opts; n++) {
+ struct m_config_option *co2 = &config->opts[n];
+ if (co2->data == co->data)
+ co2->is_set_from_cmdline = true;
+ }
+ }
+}
+
+// The type data points to is as in: m_config_get_co(config, name)->opt
+int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
+ void *data, int flags)
+{
+ if (!co)
+ return M_OPT_UNKNOWN;
+
+ // This affects some special options like "include", "profile". Maybe these
+ // should work, or maybe not. For now they would require special code.
+ if (!co->data)
+ return M_OPT_UNKNOWN;
+
+ int r = handle_set_opt_flags(config, co, flags);
+ if (r <= 1)
+ return r;
+
+ m_option_copy(co->opt, co->data, data);
+ if (flags & M_SETOPT_FROM_CMDLINE)
+ handle_set_from_cmdline(config, co);
+ return 0;
+}
+
static int parse_subopts(struct m_config *config, char *name, char *prefix,
struct bstr param, int flags);
@@ -479,7 +553,6 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
{
assert(config != NULL);
assert(name.len != 0);
- bool set = !(flags & M_SETOPT_CHECK_ONLY);
struct m_config_option *co = m_config_get_co(config, name);
if (!co) {
@@ -498,33 +571,16 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
// This is the only mandatory function
assert(co->opt->type->parse);
- if ((flags & M_SETOPT_PRE_PARSE_ONLY) && !(co->opt->flags & M_OPT_PRE_PARSE))
- return 0;
-
- if ((flags & M_SETOPT_PRESERVE_CMDLINE) && co->is_set_from_cmdline)
- set = false;
+ int r = handle_set_opt_flags(config, co, flags);
+ if (r <= 0)
+ return r;
+ bool set = r == 2;
if (set) {
MP_VERBOSE(config, "Setting option '%.*s' = '%.*s' (flags = %d)\n",
BSTR_P(name), BSTR_P(param), flags);
}
- // Check if this option isn't forbidden in the current mode
- if ((flags & M_SETOPT_FROM_CONFIG_FILE) && (co->opt->flags & M_OPT_NOCFG)) {
- MP_ERR(config, "The %.*s option can't be used in a config file.\n",
- BSTR_P(name));
- return M_OPT_INVALID;
- }
- if (flags & M_SETOPT_BACKUP) {
- if (co->opt->flags & M_OPT_GLOBAL) {
- MP_ERR(config, "The %.*s option is global and can't be set per-file.\n",
- BSTR_P(name));
- return M_OPT_INVALID;
- }
- if (set)
- ensure_backup(config, co);
- }
-
if (config->includefunc && bstr_equals0(name, "include"))
return parse_include(config, param, set, flags);
if (config->use_profiles && bstr_equals0(name, "profile"))
@@ -542,20 +598,10 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
return parse_subopts(config, (char *)co->name, prefix, param, flags);
}
- int r = m_option_parse(config->log, co->opt, name, param,
- set ? co->data : NULL);
+ r = m_option_parse(config->log, co->opt, name, param, set ? co->data : NULL);
- if (r >= 0 && set && (flags & M_SETOPT_FROM_CMDLINE)) {
- co->is_set_from_cmdline = true;
- // Mark aliases too
- if (co->data) {
- for (int n = 0; n < config->num_opts; n++) {
- struct m_config_option *co2 = &config->opts[n];
- if (co2->data == co->data)
- co2->is_set_from_cmdline = true;
- }
- }
- }
+ if (r >= 0 && set && (flags & M_SETOPT_FROM_CMDLINE))
+ handle_set_from_cmdline(config, co);
return r;
}
@@ -621,17 +667,12 @@ int m_config_set_option(struct m_config *config, struct bstr name,
}
int m_config_set_option_node(struct m_config *config, bstr name,
- struct mpv_node *data)
+ struct mpv_node *data, int flags)
{
struct m_config_option *co = m_config_get_co(config, name);
if (!co)
return M_OPT_UNKNOWN;
- // This affects some special options like "include", "profile". Maybe these
- // should work, or maybe not. For now they would require special code.
- if (!co->data)
- return M_OPT_UNKNOWN;
-
int r;
// Do this on an "empty" type to make setting the option strictly overwrite
@@ -646,7 +687,7 @@ int m_config_set_option_node(struct m_config *config, bstr name,
}
if (r >= 0)
- m_option_copy(co->opt, co->data, &val);
+ r = m_config_set_option_raw(config, co, &val, flags);
m_option_free(co->opt, &val);
return r;
diff --git a/options/m_config.h b/options/m_config.h
index 57a271f1c4..5a6274b945 100644
--- a/options/m_config.h
+++ b/options/m_config.h
@@ -116,8 +116,13 @@ enum {
M_SETOPT_FROM_CMDLINE = 8, // Mark as set by command line
M_SETOPT_BACKUP = 16, // Call m_config_backup_opt() before
M_SETOPT_PRESERVE_CMDLINE = 32, // Don't set if already marked as FROM_CMDLINE
+ M_SETOPT_NO_FIXED = 64, // Reject M_OPT_FIXED options
+ M_SETOPT_NO_PRE_PARSE = 128, // Reject M_OPT_PREPARSE options
};
+// Flags for safe option setting during runtime.
+#define M_SETOPT_RUNTIME (M_SETOPT_NO_FIXED | M_SETOPT_NO_PRE_PARSE)
+
// Set the named option to the given string.
// flags: combination of M_SETOPT_* flags (0 for normal operation)
// Returns >= 0 on success, otherwise see OptionParserReturn.
@@ -139,10 +144,15 @@ static inline int m_config_set_option0(struct m_config *config,
return m_config_set_option(config, bstr0(name), bstr0(param));
}
+// Similar to m_config_set_option_ext(), but set as data in its native format.
+// The type data points to is as in co->opt
+int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
+ void *data, int flags);
+
// Similar to m_config_set_option_ext(), but set as data using mpv_node.
struct mpv_node;
int m_config_set_option_node(struct m_config *config, bstr name,
- struct mpv_node *data);
+ struct mpv_node *data, int flags);
int m_config_parse_suboptions(struct m_config *config, char *name,
diff --git a/player/client.c b/player/client.c
index 88ebabafaa..580eebaddb 100644
--- a/player/client.c
+++ b/player/client.c
@@ -237,6 +237,18 @@ void mpv_resume(mpv_handle *ctx)
mp_dispatch_resume(ctx->mpctx->dispatch);
}
+static void lock_core(mpv_handle *ctx)
+{
+ if (ctx->mpctx->initialized)
+ mp_dispatch_lock(ctx->mpctx->dispatch);
+}
+
+static void unlock_core(mpv_handle *ctx)
+{
+ if (ctx->mpctx->initialized)
+ mp_dispatch_unlock(ctx->mpctx->dispatch);
+}
+
void mpv_destroy(mpv_handle *ctx)
{
if (!ctx)
@@ -631,47 +643,33 @@ void mpv_free_node_contents(mpv_node *node)
int mpv_set_option(mpv_handle *ctx, const char *name, mpv_format format,
void *data)
{
- if (ctx->mpctx->initialized) {
- char prop[100];
- snprintf(prop, sizeof(prop), "options/%s", name);
- int err = mpv_set_property(ctx, prop, format, data);
- switch (err) {
- case MPV_ERROR_PROPERTY_UNAVAILABLE:
- case MPV_ERROR_PROPERTY_ERROR:
- return MPV_ERROR_OPTION_ERROR;
- case MPV_ERROR_PROPERTY_FORMAT:
- return MPV_ERROR_OPTION_FORMAT;
- case MPV_ERROR_PROPERTY_NOT_FOUND:
- return MPV_ERROR_OPTION_NOT_FOUND;
- default:
- return err;
- }
- } else {
- const struct m_option *type = get_mp_type(format);
- if (!type)
- return MPV_ERROR_OPTION_FORMAT;
- struct mpv_node tmp;
- if (format != MPV_FORMAT_NODE) {
- tmp.format = format;
- memcpy(&tmp.u, data, type->type->size);
- format = MPV_FORMAT_NODE;
- data = &tmp;
- }
- int err = m_config_set_option_node(ctx->mpctx->mconfig, bstr0(name),
- data);
- switch (err) {
- case M_OPT_MISSING_PARAM:
- case M_OPT_INVALID:
- return MPV_ERROR_OPTION_ERROR;
- case M_OPT_OUT_OF_RANGE:
- return MPV_ERROR_OPTION_FORMAT;
- case M_OPT_UNKNOWN:
- return MPV_ERROR_OPTION_NOT_FOUND;
- default:
- if (err >= 0)
- return 0;
- return MPV_ERROR_OPTION_ERROR;
- }
+ int flags = ctx->mpctx->initialized ? M_SETOPT_RUNTIME : 0;
+ const struct m_option *type = get_mp_type(format);
+ if (!type)
+ return MPV_ERROR_OPTION_FORMAT;
+ struct mpv_node tmp;
+ if (format != MPV_FORMAT_NODE) {
+ tmp.format = format;
+ memcpy(&tmp.u, data, type->type->size);
+ format = MPV_FORMAT_NODE;
+ data = &tmp;
+ }
+ lock_core(ctx);
+ int err = m_config_set_option_node(ctx->mpctx->mconfig, bstr0(name),
+ data, flags);
+ unlock_core(ctx);
+ switch (err) {
+ case M_OPT_MISSING_PARAM:
+ case M_OPT_INVALID:
+ return MPV_ERROR_OPTION_ERROR;
+ case M_OPT_OUT_OF_RANGE:
+ return MPV_ERROR_OPTION_FORMAT;
+ case M_OPT_UNKNOWN:
+ return MPV_ERROR_OPTION_NOT_FOUND;
+ default:
+ if (err >= 0)
+ return 0;
+ return MPV_ERROR_OPTION_ERROR;
}
}
diff --git a/player/command.c b/player/command.c
index fd0f589053..5e09079866 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2273,12 +2273,11 @@ static int access_options(struct m_property_action_arg *ka, MPContext *mpctx)
case M_PROPERTY_GET:
m_option_copy(opt->opt, ka->arg, opt->data);
return M_PROPERTY_OK;
- case M_PROPERTY_SET:
- if (!(opt->opt->flags & (M_OPT_PRE_PARSE | M_OPT_FIXED))) {
- m_option_copy(opt->opt, opt->data, ka->arg);
- return M_PROPERTY_OK;
- }
- return M_PROPERTY_ERROR;
+ case M_PROPERTY_SET: {
+ int r = m_config_set_option_raw(mpctx->mconfig, opt, ka->arg,
+ M_SETOPT_RUNTIME);
+ return r < 0 ? M_PROPERTY_ERROR : M_PROPERTY_OK;
+ }
case M_PROPERTY_GET_TYPE:
*(struct m_option *)ka->arg = *opt->opt;
return M_PROPERTY_OK;