diff --git a/audio/out/ao.c b/audio/out/ao.c index 3bfa481bc5..cd2b9e8089 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -110,6 +110,7 @@ static bool get_desc(struct m_obj_desc *dst, int index) .priv_defaults = ao->priv_defaults, .options = ao->options, .global_opts = ao->global_opts, + .legacy_prefix = ao->legacy_prefix, .hidden = ao->encode, .p = ao, }; diff --git a/audio/out/internal.h b/audio/out/internal.h index f9dc073b4d..3115fbfeb7 100644 --- a/audio/out/internal.h +++ b/audio/out/internal.h @@ -182,6 +182,7 @@ struct ao_driver { const void *priv_defaults; const struct m_option *options; const struct m_sub_options *global_opts; + const char *legacy_prefix; }; // These functions can be called by AOs. diff --git a/options/m_config.c b/options/m_config.c index 18a9ad4de7..f8e8c705ae 100644 --- a/options/m_config.c +++ b/options/m_config.c @@ -258,15 +258,28 @@ struct m_config *m_config_from_obj_desc_noalloc(void *talloc_ctx, } static int m_config_set_obj_params(struct m_config *config, struct mp_log *log, - struct mpv_global *global, char **args) + struct mpv_global *global, + struct m_obj_desc *desc, char **args) { for (int n = 0; args && args[n * 2 + 0]; n++) { const char *opt = args[n * 2 + 0]; const char *val = args[n * 2 + 1]; struct m_config_option *co = m_config_get_co(config, bstr0(opt)); + if (!co) + continue; struct m_config *target = config; - if (co && co->opt->type == &m_option_type_subopt_legacy) { - const char *newopt = co->opt->priv; + bool is_legacy = co->opt->type == &m_option_type_subopt_legacy; + bool force_legacy = !!desc->legacy_prefix; + if (is_legacy || force_legacy) { + // Legacy: redirect deprecated sub-options to global ones. + char tmp[100]; + const char *newopt; + if (is_legacy) { + newopt = co->opt->priv; + } else { + snprintf(tmp, sizeof(tmp), "%s-%s", desc->legacy_prefix, opt); + newopt = tmp; + } assert(global); target = mp_get_root_config(global); mp_warn(log, "Using suboptions is deprecated. Use the global '--%s' " @@ -289,14 +302,29 @@ struct m_config *m_config_from_obj_desc_and_args(void *ta_parent, for (int n = 0; defaults && defaults[n].name; n++) { struct m_obj_settings *entry = &defaults[n]; if (name && strcmp(entry->name, name) == 0) { - if (m_config_set_obj_params(config, log, global, entry->attribs) < 0) + if (m_config_set_obj_params(config, log, global, desc, entry->attribs) < 0) goto error; } } - if (m_config_set_obj_params(config, log, global, args) < 0) + if (m_config_set_obj_params(config, log, global, desc, args) < 0) goto error; + if (desc->legacy_prefix) { + assert(global); + struct m_config *root = mp_get_root_config(global); + // In this mode, the AO/VO will still access the options via its priv + // struct (like with real sub-options). We have to copy them over. + for (int n = 0; n < config->num_opts; n++) { + struct m_config_option *co = &config->opts[n]; + char opt[100]; + snprintf(opt, sizeof(opt), "%s-%s", desc->legacy_prefix, co->name); + struct m_config_option *g = m_config_get_co(root, bstr0(opt)); + assert(g); + m_option_copy(co->opt, co->data, g->data); + } + } + return config; error: talloc_free(config); @@ -415,6 +443,20 @@ static void add_global_subopts(struct m_config *config, break; if (desc.global_opts) add_sub_options(config, NULL, desc.global_opts); + if (desc.legacy_prefix && desc.options) { + // Legacy: auto-add sub-options as global options (using the prefix). + struct m_config_option parent = { + .name = desc.legacy_prefix, + .group = 0, + }; + struct m_sub_options *conf = talloc(config, struct m_sub_options); + *conf = (struct m_sub_options){ + .opts = desc.options, + .defaults = desc.priv_defaults, + .size = desc.priv_size, + }; + add_sub_options(config, &parent, conf); + } } } diff --git a/options/m_option.h b/options/m_option.h index 48afc23df7..024b62521a 100644 --- a/options/m_option.h +++ b/options/m_option.h @@ -132,6 +132,10 @@ struct m_obj_desc { const char *replaced_name; // For convenience: these are added as global command-line options. const struct m_sub_options *global_opts; + // Evil hack to essentially force-move .options to global_opts. All options + // will be added as global options with the given prefix, and using + // sub-options will be treated as deprecated and redirected. + const char *legacy_prefix; }; // Extra definition needed for \ref m_option_type_obj_settings_list options. diff --git a/video/out/vo.c b/video/out/vo.c index 3e6a2c7070..afd4b4c792 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -173,6 +173,7 @@ static bool get_desc(struct m_obj_desc *dst, int index) .priv_defaults = vo->priv_defaults, .options = vo->options, .global_opts = vo->global_opts, + .legacy_prefix = vo->legacy_prefix, .hidden = vo->encode || !strcmp(vo->name, "opengl-cb"), .p = vo, }; diff --git a/video/out/vo.h b/video/out/vo.h index 6a6101692c..e3258a39ff 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -295,11 +295,17 @@ struct vo_driver { const void *priv_defaults; // List of options to parse into priv struct (requires priv_size to be set) + // Deprecated. Use global options or global_opts instead. const struct m_option *options; // Global options to register if the VO is compiled in. // mp_get_config_group() or other function can be used to access them. const struct m_sub_options *global_opts; + + // Evil hack: add .options as global options, using the provided prefix. + // For further evilness, the options will be copied to the priv struct + // like with normal .options behavior. + const char *legacy_prefix; }; struct vo {