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:
wm4 2013-10-24 22:20:16 +02:00
parent f6bceacaff
commit 60aea74f44
11 changed files with 79 additions and 75 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,
};

View File

@ -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 {

View File

@ -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 = {

View File

@ -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",
};