mirror of
https://github.com/mpv-player/mpv
synced 2025-01-11 09:29:29 +00:00
m_config: refactor option defaults handling
Keep track of the default values directly, instead of creating a new instance of the option struct just to get the defaults. Also get rid of the special handling of m_obj_desc.init_options. Instead, handle it purely by the option parser. Originally, I wanted to handle --vo=opengl-hq and --vo=direct3d_shaders with this (by making them aliases to the real VOs with a different preset), but since --vo =opengl-hq=help prints the wrong values (as consequence of the simplification), I'm not doing that, and instead use something different.
This commit is contained in:
parent
f6bceacaff
commit
60aea74f44
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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 = {
|
||||
|
@ -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",
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user