summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-06-15 15:15:05 +0200
committerwm4 <wm4@nowhere>2017-06-15 15:23:25 +0200
commitfd7de84833a7f492678e0caa18125ff9f9aa38a5 (patch)
tree1d1d8997ca4d29576a0734b19e08ff6eeb66e743
parent6489b112ad8f3edf19bc7e741980414d8e93dcbd (diff)
downloadmpv-fd7de84833a7f492678e0caa18125ff9f9aa38a5.tar.bz2
mpv-fd7de84833a7f492678e0caa18125ff9f9aa38a5.tar.xz
options: make mess to allow setting profile option with libmpv
Certain options, such as --profile, --help, and many others require special-handling, because they don't fit conceptually into the option and property model. They don't store data, but perform actions. This caused the situation that profiles could not be set when using libmpv in encoding mode (although you should probably not used libmpv in encoding mode). Using libmpv always ends up in calling m_config_set_option_raw_direct(), while --profile was handled in m_config_parse_option(). Solve this by moving the handling of this from m_config_parse_option() to m_config_set_option_raw_direct(). Actually we just stuff most of this into m_config_handle_special_options(), which is only called by the aforementioned function. Strangely this also means that the --h/--help option declarations need to be changed, because they used OPT_PRINT, and now the option "parser" is always invoked before the special code. Thus, make them a string. Them being OPT_PRINT was apparently always redundant. (The other option declarations are moved for cosmetic purposes only.) The most weird change is how co->data==NULL is handled. We now allow passing down involved options to m_config_set_option_raw_direct(). The thing is that we don't want them to error if the command line parser is using them (with special handling done there), while all other code paths should raise an error. We try using M_SETOPT_FROM_CMDLINE to distinguish these cases. Note that normal libmpv users are supposed to use the "apply-profile" command instead. This probably contains a bunch of bugs, which you should report.
-rw-r--r--options/m_config.c162
-rw-r--r--options/options.c19
2 files changed, 87 insertions, 94 deletions
diff --git a/options/m_config.c b/options/m_config.c
index b6e1720f39..dabea4647c 100644
--- a/options/m_config.c
+++ b/options/m_config.c
@@ -83,57 +83,6 @@ struct m_opt_backup {
void *backup;
};
-static int parse_include(struct m_config *config, struct bstr param, bool set,
- int flags)
-{
- if (param.len == 0)
- return M_OPT_MISSING_PARAM;
- if (!set)
- return 1;
- if (config->recursion_depth >= MAX_RECURSION_DEPTH) {
- MP_ERR(config, "Maximum 'include' nesting depth exceeded.\n");
- return M_OPT_INVALID;
- }
- char *filename = bstrdup0(NULL, param);
- config->recursion_depth += 1;
- config->includefunc(config->includefunc_ctx, filename, flags);
- config->recursion_depth -= 1;
- talloc_free(filename);
- return 1;
-}
-
-static int parse_profile(struct m_config *config, const struct m_option *opt,
- struct bstr name, struct bstr param, bool set, int flags)
-{
- if (!bstrcmp0(param, "help")) {
- struct m_profile *p;
- if (!config->profiles) {
- MP_INFO(config, "No profiles have been defined.\n");
- return M_OPT_EXIT;
- }
- MP_INFO(config, "Available profiles:\n");
- for (p = config->profiles; p; p = p->next)
- MP_INFO(config, "\t%s\t%s\n", p->name, p->desc ? p->desc : "");
- MP_INFO(config, "\n");
- return M_OPT_EXIT;
- }
-
- char **list = NULL;
- int r = m_option_type_string_list.parse(config->log, opt, name, param, &list);
- if (r < 0)
- return r;
- if (!list || !list[0])
- return M_OPT_INVALID;
- for (int i = 0; list[i]; i++) {
- if (set)
- r = m_config_set_profile(config, list[i], flags);
- if (r < 0)
- break;
- }
- m_option_free(opt, &list);
- return r;
-}
-
static int show_profile(struct m_config *config, bstr param)
{
struct m_profile *p;
@@ -171,17 +120,6 @@ static int show_profile(struct m_config *config, bstr param)
return M_OPT_EXIT;
}
-static int list_options(struct m_config *config, bstr val, bool show_help)
-{
- char s[100];
- snprintf(s, sizeof(s), "%.*s", BSTR_P(val));
- if (show_help)
- mp_info(config->log, "%s", mp_help_text);
- if (s[0])
- m_config_print_option_list(config, s);
- return M_OPT_EXIT;
-}
-
// 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* ). The dummy struct type is in
@@ -729,6 +667,73 @@ void m_config_mark_co_flags(struct m_config_option *co, int flags)
co->is_set_from_config = true;
}
+// Special options that don't really fit into the option handling mode. They
+// usually store no data, but trigger actions. Caller is assumed to have called
+// handle_set_opt_flags() to make sure the option can be set.
+// Returns M_OPT_UNKNOWN if the option is not a special option.
+static int m_config_handle_special_options(struct m_config *config,
+ struct m_config_option *co,
+ void *data, int flags)
+{
+ if (config->use_profiles && strcmp(co->name, "profile") == 0) {
+ char **list = *(char ***)data;
+
+ if (list && list[0] && !list[1] && strcmp(list[0], "help") == 0) {
+ if (!config->profiles) {
+ MP_INFO(config, "No profiles have been defined.\n");
+ return M_OPT_EXIT;
+ }
+ MP_INFO(config, "Available profiles:\n");
+ for (struct m_profile *p = config->profiles; p; p = p->next)
+ MP_INFO(config, "\t%s\t%s\n", p->name, p->desc ? p->desc : "");
+ MP_INFO(config, "\n");
+ return M_OPT_EXIT;
+ }
+
+ for (int n = 0; list && list[n]; n++) {
+ int r = m_config_set_profile(config, list[n], flags);
+ if (r < 0)
+ return r;
+ }
+ return 0;
+ }
+
+ if (config->includefunc && strcmp(co->name, "include") == 0) {
+ char *param = *(char **)data;
+ if (!param || !param[0])
+ return M_OPT_MISSING_PARAM;
+ if (config->recursion_depth >= MAX_RECURSION_DEPTH) {
+ MP_ERR(config, "Maximum 'include' nesting depth exceeded.\n");
+ return M_OPT_INVALID;
+ }
+ config->recursion_depth += 1;
+ config->includefunc(config->includefunc_ctx, param, flags);
+ config->recursion_depth -= 1;
+ return 1;
+ }
+
+ if (config->use_profiles && strcmp(co->name, "show-profile") == 0)
+ return show_profile(config, bstr0(*(char **)data));
+
+ if (config->is_toplevel && (strcmp(co->name, "h") == 0 ||
+ strcmp(co->name, "help") == 0))
+ {
+ char *h = *(char **)data;
+ mp_info(config->log, "%s", mp_help_text);
+ if (h && h[0])
+ m_config_print_option_list(config, h);
+ return M_OPT_EXIT;
+ }
+
+ if (strcmp(co->name, "list-options") == 0) {
+ m_config_print_option_list(config, "*");
+ return M_OPT_EXIT;
+ }
+
+ return M_OPT_UNKNOWN;
+}
+
+
// Unlike m_config_set_option_raw() this does not go through the property layer
// via config.option_set_callback.
int m_config_set_option_raw_direct(struct m_config *config,
@@ -738,15 +743,19 @@ int m_config_set_option_raw_direct(struct m_config *config,
if (!co)
return M_OPT_UNKNOWN;
- // This affects some special options like "include", "profile". Maybe these
- // should work, or maybe not. For now they would require special code.
- if (!co->data)
- return M_OPT_UNKNOWN;
-
int r = handle_set_opt_flags(config, co, flags);
if (r <= 1)
return r;
+ r = m_config_handle_special_options(config, co, data, flags);
+ if (r != M_OPT_UNKNOWN)
+ return r;
+
+ // This affects some special options like "playlist", "v". Maybe these
+ // should work, or maybe not. For now they would require special code.
+ if (!co->data)
+ return flags & M_SETOPT_FROM_CMDLINE ? 0 : M_OPT_UNKNOWN;
+
m_option_copy(co->opt, co->data, data);
m_config_mark_co_flags(co, flags);
@@ -761,6 +770,9 @@ int m_config_set_option_raw_direct(struct m_config *config,
int m_config_set_option_raw(struct m_config *config, struct m_config_option *co,
void *data, int flags)
{
+ if (!co)
+ return M_OPT_UNKNOWN;
+
if (config->option_set_callback) {
int r = handle_set_opt_flags(config, co, flags);
if (r <= 1)
@@ -824,18 +836,6 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
BSTR_P(name), BSTR_P(param), flags);
}
- if (config->includefunc && bstr_equals0(name, "include"))
- return parse_include(config, param, set, flags);
- if (config->use_profiles && bstr_equals0(name, "profile"))
- return parse_profile(config, co->opt, name, param, set, flags);
- if (config->use_profiles && bstr_equals0(name, "show-profile"))
- return show_profile(config, param);
- if (config->is_toplevel && (bstr_equals0(name, "h") ||
- bstr_equals0(name, "help")))
- return list_options(config, param, true);
- if (bstr_equals0(name, "list-options"))
- return list_options(config, bstr0("*"), false);
-
union m_option_value val = {0};
// Some option types are "impure" and work on the existing data.
@@ -845,7 +845,7 @@ static int m_config_parse_option(struct m_config *config, struct bstr name,
r = m_option_parse(config->log, co->opt, name, param, &val);
- if (r >= 0 && co->data)
+ if (r >= 0)
r = m_config_set_option_raw(config, co, &val, flags);
m_option_free(co->opt, &val);
@@ -1076,7 +1076,7 @@ int m_config_set_profile(struct m_config *config, char *name, int flags)
if (config->profile_depth > MAX_PROFILE_DEPTH) {
MP_WARN(config, "WARNING: Profile inclusion too deep.\n");
- return M_OPT_UNKNOWN;
+ return M_OPT_INVALID;
}
config->profile_depth++;
for (int i = 0; i < p->num_opts; i++) {
diff --git a/options/options.c b/options/options.c
index 324a1c9a3e..1bcdc720f2 100644
--- a/options/options.c
+++ b/options/options.c
@@ -56,18 +56,11 @@
#include "video/out/opengl/hwdec.h"
#endif
-extern const char mp_help_text[];
-
static void print_version(struct mp_log *log)
{
mp_print_version(log, true);
}
-static void print_help(struct mp_log *log)
-{
- mp_info(log, "%s", mp_help_text);
-}
-
extern const struct m_sub_options tv_params_conf;
extern const struct m_sub_options stream_cdda_conf;
extern const struct m_sub_options stream_dvb_conf;
@@ -274,6 +267,12 @@ const m_option_t mp_opts[] = {
{ "list-options", CONF_TYPE_STORE, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
OPT_FLAG("list-properties", property_print_help,
CONF_NOCFG | M_OPT_FIXED | M_OPT_NOPROP),
+ { "help", CONF_TYPE_STRING, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
+ { "h", CONF_TYPE_STRING, CONF_NOCFG | M_OPT_FIXED, .offset = -1},
+
+ OPT_PRINT("list-protocols", stream_print_proto_list),
+ OPT_PRINT("version", print_version),
+ OPT_PRINT("V", print_version),
OPT_CHOICE("player-operation-mode", operation_mode,
M_OPT_FIXED | M_OPT_PRE_PARSE | M_OPT_NOPROP,
@@ -704,12 +703,6 @@ const m_option_t mp_opts[] = {
OPT_SUBSTRUCT("", input_opts, input_config, 0),
- OPT_PRINT("list-protocols", stream_print_proto_list),
- OPT_PRINT("help", print_help),
- OPT_PRINT("h", print_help),
- OPT_PRINT("version", print_version),
- OPT_PRINT("V", print_version),
-
OPT_SUBSTRUCT("", vo, vo_sub_opts, 0),
OPT_SUBSTRUCT("", demux_opts, demux_conf, 0),