diff options
Diffstat (limited to 'player')
-rw-r--r-- | player/command.c | 74 | ||||
-rw-r--r-- | player/command.h | 3 | ||||
-rw-r--r-- | player/main.c | 3 |
3 files changed, 77 insertions, 3 deletions
diff --git a/player/command.c b/player/command.c index f4e2a0acd3..d791838ef8 100644 --- a/player/command.c +++ b/player/command.c @@ -126,6 +126,9 @@ static int edit_filters(struct MPContext *mpctx, struct mp_log *log, static int set_filters(struct MPContext *mpctx, enum stream_type mediatype, struct m_obj_settings *new_chain); +static int mp_property_do_silent(const char *name, int action, void *val, + struct MPContext *ctx); + static void hook_remove(struct MPContext *mpctx, int index) { struct command_ctx *cmd = mpctx->command_ctx; @@ -254,6 +257,64 @@ static char *format_delay(double time) return talloc_asprintf(NULL, "%d ms", (int)lrint(time * 1000)); } +// Option-property bridge. This is used so that setting options via various +// mechanisms (including command line parsing, config files, per-file options) +// updates state associated with them. For that, they have to go through the +// property layer. (Ideally, this would be the other way around, and there +// would be per-option change handlers instead.) +// Note that the property-option bridge sidesteps this, as we'd get infinite +// recursion. +int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flags) +{ + struct MPContext *mpctx = ctx; + + // These options are too inconsistent as they could be pulled through the + // property layer. Ideally we'd remove these inconsistencies in the future, + // though the actual problem is compatibility to user-expected behavior. + // What matters is whether _write_ access is different - property read + // access is not used here. + // We're also fine with cases where the property restricts the writable + // value range if playback is active, but not otherwise. + // OK, restrict during playback: vid, aid, sid, deinterlace, video-aspect, + // vf*, af*, chapter + // OK, is handled separately: playlist + // OK, does not conflict on low level: audio-file, sub-file, external-file + static const char *const no_property[] = { + "playlist-pos", // checks playlist bounds, "no" choice missing + "volume", // restricts to --volume-max + "demuxer", "idle", "length", "audio-samplerate", "audio-channels", + "audio-format", "fps", "cache", // different semantics + NULL + }; + + for (int n = 0; no_property[n]; n++) { + if (strcmp(co->name, no_property[n]) == 0) + goto direct_option; + } + + // Normalize "vf*" to "vf" + const char *name = co->name; + bstr bname = bstr0(name); + char tmp[50]; + if (bstr_eatend0(&bname, "*")) { + snprintf(tmp, sizeof(name), "%.*s", BSTR_P(bname)); + name = tmp; + } + + int r = mp_property_do_silent(name, M_PROPERTY_SET, data, mpctx); + if (r != M_PROPERTY_OK) + return M_OPT_INVALID; + + // The flag can't be passed through the property layer correctly. + if (flags & M_SETOPT_FROM_CMDLINE) + co->is_set_from_cmdline = true; + + return 0; + +direct_option: + return m_config_set_option_raw_direct(mpctx->mconfig, co, data, flags); +} + // Property-option bridge. (Maps the property to the option with the same name.) static int mp_property_generic_option_do(void *ctx, struct m_property *prop, int action, void *arg, bool force) @@ -277,7 +338,7 @@ static int mp_property_generic_option_do(void *ctx, struct m_property *prop, m_option_copy(opt->opt, arg, valptr); return M_PROPERTY_OK; case M_PROPERTY_SET: - if (m_config_set_option_raw(mpctx->mconfig, opt, arg, flags) < 0) + if (m_config_set_option_raw_direct(mpctx->mconfig, opt, arg, flags) < 0) return M_PROPERTY_ERROR; return M_PROPERTY_OK; } @@ -4069,13 +4130,20 @@ static bool is_property_set(int action, void *val) } } -int mp_property_do(const char *name, int action, void *val, - struct MPContext *ctx) +static int mp_property_do_silent(const char *name, int action, void *val, + struct MPContext *ctx) { struct command_ctx *cmd = ctx->command_ctx; int r = m_property_do(ctx->log, cmd->properties, name, action, val, ctx); if (r == M_PROPERTY_OK && is_property_set(action, val)) mp_notify_property(ctx, (char *)name); + return r; +} + +int mp_property_do(const char *name, int action, void *val, + struct MPContext *ctx) +{ + int r = mp_property_do_silent(name, action, val, ctx); if (mp_msg_test(ctx->log, MSGL_V) && is_property_set(action, val)) { struct m_option ot = {0}; void *data = val; diff --git a/player/command.h b/player/command.h index c082d8d0d7..33e5b74927 100644 --- a/player/command.h +++ b/player/command.h @@ -24,6 +24,7 @@ struct MPContext; struct mp_cmd; struct mp_log; struct mpv_node; +struct m_config_option; void command_init(struct MPContext *mpctx); void command_uninit(struct MPContext *mpctx); @@ -35,6 +36,8 @@ void property_print_help(struct MPContext *mpctx); int mp_property_do(const char* name, int action, void* val, struct MPContext *mpctx); +int mp_on_set_option(void *ctx, struct m_config_option *co, void *data, int flags); + void mp_notify(struct MPContext *mpctx, int event, void *arg); void mp_notify_property(struct MPContext *mpctx, const char *property); diff --git a/player/main.c b/player/main.c index d4c31a4726..12f0191fc6 100644 --- a/player/main.c +++ b/player/main.c @@ -356,6 +356,9 @@ struct MPContext *mp_create(void) mp_input_set_cancel(mpctx->input, mpctx->playback_abort); + mpctx->mconfig->option_set_callback = mp_on_set_option; + mpctx->mconfig->option_set_callback_cb = mpctx; + return mpctx; } |