diff --git a/mpvcore/m_config.c b/mpvcore/m_config.c index be583f8f42..3fd4056b56 100644 --- a/mpvcore/m_config.c +++ b/mpvcore/m_config.c @@ -34,6 +34,8 @@ #include "mpvcore/m_option.h" #include "mpvcore/mp_msg.h" +static const union m_option_value default_value; + // Profiles allow to predefine some sets of options that can then // be applied later on with the internal -profile option. #define MAX_PROFILE_DEPTH 20 @@ -157,10 +159,10 @@ static int list_options(struct m_config *config) return M_OPT_EXIT; } -// The memcpys are supposed to work around the struct aliasing violation, +// The memcpys are supposed to work around the strict aliasing violation, // that would result if we just dereferenced a void** (where the void** is // actually casted from struct some_type* ). -static void *substruct_read_ptr(void *ptr) +static void *substruct_read_ptr(const void *ptr) { void *res; memcpy(&res, ptr, sizeof(void*)); @@ -187,8 +189,7 @@ static void config_destroy(void *p) struct m_config *m_config_new(void *talloc_parent, size_t size, const void *defaults, - const struct m_option *options, - const char *suboptinit) + const struct m_option *options) { struct m_config *config = talloc(talloc_parent, struct m_config); talloc_set_destructor(config, config_destroy); @@ -196,7 +197,6 @@ struct m_config *m_config_new(void *talloc_parent, size_t size, .optstruct_size = size, .optstruct_defaults = defaults, .options = options, - .suboptinit = suboptinit, }; if (size) { // size==0 means a dummy object is created config->optstruct = talloc_zero_size(config, size); @@ -205,13 +205,6 @@ struct m_config *m_config_new(void *talloc_parent, size_t size, if (options) add_options(config, "", config->optstruct, defaults, options); } - if (suboptinit) { - bstr s = bstr0(suboptinit); - int r = m_obj_parse_sub_config(bstr0("internal"), bstr0("-"), &s, - config, 0, NULL); - if (r < 0 || s.len > 0) - mp_msg(MSGT_CFGPARSER, MSGL_ERR, "Internal error: preset broken\n"); - } return config; } @@ -219,7 +212,7 @@ struct m_config *m_config_from_obj_desc(void *talloc_parent, struct m_obj_desc *desc) { return m_config_new(talloc_parent, desc->priv_size, desc->priv_defaults, - desc->options, desc->init_options); + desc->options); } int m_config_set_obj_params(struct m_config *conf, char **args) @@ -384,7 +377,21 @@ static void m_config_add_option(struct m_config *config, .name = (char *)arg->name, }; - co.data = arg->is_new_option ? (char *)optstruct + arg->offset : arg->p; + if (arg->is_new_option) { + if (optstruct) + co.data = (char *)optstruct + arg->offset; + if (optstruct_def) + co.default_data = (char *)optstruct_def + arg->offset; + } else { + co.data = arg->p; + co.default_data = arg->p; + } + + if (arg->defval) + co.default_data = arg->defval; + + if (co.data && !co.default_data) + co.default_data = &default_value; // Fill in the full name if (parent_name[0]) @@ -397,12 +404,13 @@ static void m_config_add_option(struct m_config *config, if (arg->type->flags & M_OPT_TYPE_USE_SUBSTRUCT) { const struct m_sub_options *subopts = arg->priv; - void *new_optstruct = substruct_read_ptr(co.data); - if (!new_optstruct) { - new_optstruct = m_config_alloc_struct(config, subopts); - substruct_write_ptr(co.data, new_optstruct); - } - const void *new_optstruct_def = subopts->defaults; + + void *new_optstruct = m_config_alloc_struct(config, subopts); + substruct_write_ptr(co.data, new_optstruct); + + const void *new_optstruct_def = substruct_read_ptr(co.default_data); + if (!new_optstruct_def) + new_optstruct_def = subopts->defaults; add_options(config, new_parent_name, new_optstruct, new_optstruct_def, subopts->opts); @@ -412,26 +420,19 @@ static void m_config_add_option(struct m_config *config, } } else { // Initialize options - if (co.data) { - if (arg->defval) { - // Target data in optstruct is supposed to be cleared (consider - // m_option freeing previously set dynamic data). - m_option_copy(arg, co.data, arg->defval); - } else if (arg->type->flags & M_OPT_TYPE_DYNAMIC) { - // Initialize dynamically managed fields from static data (like - // string options): copy the option into temporary memory, - // clear the original option (to stop m_option from freeing the - // static data), copy it back. - // This would leak memory when done on aliased options. + if (co.data && co.default_data) { + if (arg->type->flags & M_OPT_TYPE_DYNAMIC) { + // Would leak memory by overwriting *co.data repeatedly. for (int i = 0; i < config->num_opts; i++) { if (co.data == config->opts[i].data) assert(0); } - union m_option_value temp = {0}; - memcpy(&temp, co.data, arg->type->size); - memset(co.data, 0, arg->type->size); - m_option_copy(arg, co.data, &temp); } + // In case this is dynamic data, it has to be allocated and copied. + union m_option_value temp = {0}; + memcpy(&temp, co.default_data, arg->type->size); + memset(co.data, 0, arg->type->size); + m_option_copy(arg, co.data, &temp); } } @@ -612,32 +613,11 @@ int m_config_option_requires_param(struct m_config *config, bstr name) return M_OPT_UNKNOWN; } -static struct m_config *get_defaults(const struct m_config *config) -{ - return m_config_new(NULL, config->optstruct_size, - config->optstruct_defaults, config->options, - config->suboptinit); -} - -static char *get_option_value_string(const struct m_config *config, - const char *name) -{ - struct m_config_option *co = m_config_get_co(config, bstr0(name)); - if (!co || !co->data) - return NULL; - return m_option_print(co->opt, co->data); -} - void m_config_print_option_list(const struct m_config *config) { char min[50], max[50]; int count = 0; - if (!config->opts) - return; - - struct m_config *defaults = get_defaults(config); - mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "Options:\n\n"); for (int i = 0; i < config->num_opts; i++) { struct m_config_option *co = &config->opts[i]; @@ -666,7 +646,9 @@ void m_config_print_option_list(const struct m_config *config) snprintf(max, sizeof(max), "%.14g", opt->max); mp_msg(MSGT_CFGPARSER, MSGL_INFO, " (%s to %s)", min, max); } - char *def = get_option_value_string(defaults, co->name); + char *def = NULL; + if (co->default_data) + def = m_option_print(co->opt, co->default_data); if (def) { mp_msg(MSGT_CFGPARSER, MSGL_INFO, " (default: %s)", def); talloc_free(def); @@ -679,8 +661,6 @@ void m_config_print_option_list(const struct m_config *config) count++; } mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d options\n", count); - - talloc_free(defaults); } struct m_profile *m_config_get_profile(const struct m_config *config, bstr name) diff --git a/mpvcore/m_config.h b/mpvcore/m_config.h index f16d1ea7fe..c5d1d35e49 100644 --- a/mpvcore/m_config.h +++ b/mpvcore/m_config.h @@ -43,6 +43,7 @@ struct m_config_option { const struct m_option *opt; // Raw value of the option. void *data; + const void *default_data; }; // Config object @@ -65,7 +66,6 @@ typedef struct m_config { const void *optstruct_defaults; size_t optstruct_size; const struct m_option *options; // top-level options - const char *suboptinit; void *optstruct; // struct mpopts or other } m_config_t; @@ -81,8 +81,7 @@ typedef struct m_config { // Note that the m_config object will keep pointers to defaults and options. struct m_config *m_config_new(void *talloc_parent, size_t size, const void *defaults, - const struct m_option *options, - const char *suboptinit); + const struct m_option *options); struct m_config *m_config_from_obj_desc(void *talloc_parent, struct m_obj_desc *desc); diff --git a/mpvcore/m_option.c b/mpvcore/m_option.c index c8a656a9c8..095e86a2b5 100644 --- a/mpvcore/m_option.c +++ b/mpvcore/m_option.c @@ -2139,6 +2139,15 @@ static int parse_obj_settings(struct bstr opt, struct bstr *pstr, skip = true; } + if (_ret && desc.init_options) { + struct m_config *config = m_config_from_obj_desc(NULL, &desc); + bstr s = bstr0(desc.init_options); + m_obj_parse_sub_config(opt, str, &s, config, + M_SETOPT_CHECK_ONLY, &plist); + assert(s.len == 0); + talloc_free(config); + } + if (has_param) { if (legacy) { // Should perhaps be parsed as escape-able string. But this is a diff --git a/mpvcore/m_option.h b/mpvcore/m_option.h index 96219b317a..d357456f63 100644 --- a/mpvcore/m_option.h +++ b/mpvcore/m_option.h @@ -107,8 +107,8 @@ struct m_obj_desc { // For free use by the implementer of m_obj_list.get_desc const void *p; // If not NULL, options which should be set before applying other options. - // This member is usually set my m_obj_list_find() only. - // Only works if options is not NULL. + // This member is usually set by m_obj_list_find() only, and read by the + // option parser. It's not used anywhere else. const char *init_options; // Don't list entries with "help" bool hidden; diff --git a/mpvcore/mplayer.c b/mpvcore/mplayer.c index bfc5f7c4e1..f05fcd9795 100644 --- a/mpvcore/mplayer.c +++ b/mpvcore/mplayer.c @@ -4930,7 +4930,7 @@ static int mpv_main(int argc, char *argv[]) // Create the config context and register the options mpctx->mconfig = m_config_new(mpctx, sizeof(struct MPOpts), - &mp_default_opts, mp_opts, NULL); + &mp_default_opts, mp_opts); mpctx->opts = mpctx->mconfig->optstruct; mpctx->mconfig->includefunc = cfg_include; mpctx->mconfig->use_profiles = true; diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 8bab6a5c4c..603f334c9b 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -275,6 +275,16 @@ static const struct gl_video_opts gl_video_opts_def = { .alpha_mode = 2, }; +const struct gl_video_opts gl_video_opts_hq_def = { + .npot = 1, + .dither_depth = 0, + .dither_size = 6, + .fbo_format = GL_RGB16, + .scale_sep = 1, + .scalers = { "lanczos2", "bilinear" }, + .scaler_params = {NAN, NAN}, + .alpha_mode = 2, +}; static int validate_scaler_opt(const m_option_t *opt, struct bstr name, struct bstr param); diff --git a/video/out/gl_video.h b/video/out/gl_video.h index 3b21edc223..dcec9f3888 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -49,6 +49,7 @@ struct gl_video_opts { }; extern const struct m_sub_options gl_video_conf; +extern const struct gl_video_opts gl_video_opts_hq_def; struct gl_video; diff --git a/video/out/vo.c b/video/out/vo.c index b29e3f7c95..061fc9caf3 100644 --- a/video/out/vo.c +++ b/video/out/vo.c @@ -123,7 +123,6 @@ static bool get_desc(struct m_obj_desc *dst, int index) .priv_size = vo->priv_size, .priv_defaults = vo->priv_defaults, .options = vo->options, - .init_options = vo->init_option_string, .hidden = vo->encode, .p = vo, }; diff --git a/video/out/vo.h b/video/out/vo.h index 57d5cfb6d0..1777245c96 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -216,9 +216,6 @@ struct vo_driver { // List of options to parse into priv struct (requires privsize to be set) const struct m_option *options; - - // Parse these options before parsing user options - const char *init_option_string; }; struct vo { diff --git a/video/out/vo_direct3d.c b/video/out/vo_direct3d.c index 9ad2322499..cd440f89f6 100644 --- a/video/out/vo_direct3d.c +++ b/video/out/vo_direct3d.c @@ -1720,6 +1720,13 @@ static const struct m_option opts[] = { {0} }; +static const d3d_priv defaults_noshaders = { + .colorspace = MP_CSP_DETAILS_DEFAULTS, + .video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX }, + .opt_disable_shaders = 1, + .opt_disable_textures = 1, +}; + static const d3d_priv defaults = { .colorspace = MP_CSP_DETAILS_DEFAULTS, .video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX }, @@ -1737,9 +1744,8 @@ const struct vo_driver video_out_direct3d = { .flip_page = flip_page, .uninit = uninit, .priv_size = sizeof(d3d_priv), - .priv_defaults = &defaults, + .priv_defaults = &defaults_noshaders, .options = opts, - .init_option_string = "disable-shaders:disable-textures", }; const struct vo_driver video_out_direct3d_shaders = { diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index e1c07d8621..cf1b3b3400 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -200,9 +200,10 @@ static bool reparse_cmdline(struct gl_priv *p, char *args) if (strcmp(args, "-") == 0) { opts = p->renderer_opts; } else { - cfg = m_config_new(NULL, sizeof(*opts), gl_video_conf.defaults, - gl_video_conf.opts, - p->vo->driver->init_option_string); + const struct gl_priv *vodef = p->vo->driver->priv_defaults; + const struct gl_video_opts *def = + vodef ? vodef->renderer_opts : gl_video_conf.defaults; + cfg = m_config_new(NULL, sizeof(*opts), def, gl_video_conf.opts); opts = cfg->optstruct; r = m_config_parse_suboptions(cfg, "opengl", args); } @@ -376,6 +377,8 @@ const struct vo_driver video_out_opengl_hq = { .flip_page = flip_page, .uninit = uninit, .priv_size = sizeof(struct gl_priv), + .priv_defaults = &(const struct gl_priv){ + .renderer_opts = (struct gl_video_opts *)&gl_video_opts_hq_def, + }, .options = options, - .init_option_string = "lscale=lanczos2:dither-depth=auto:fbo-format=rgb16", };