summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2012-09-05 02:17:13 +0200
committerwm4 <wm4@nowhere>2012-09-18 21:07:29 +0200
commitc955549204c433abd1a3c8783f1b988e29315337 (patch)
tree47da7a2a9f552a810713b788513683f694eeec0c
parentd29d4df634a9d847a2b5ef7a04f32726cd03c1ef (diff)
downloadmpv-c955549204c433abd1a3c8783f1b988e29315337.tar.bz2
mpv-c955549204c433abd1a3c8783f1b988e29315337.tar.xz
options: change --loop option, and extend choice option type
The --loop option takes slightly different parameters now. --loop=0 used to mean looping forever. Now it means looping is disabled (this is more logical: 2 means playing 2 more times, 1 means playing 1 more time, and 0 should mean playing not again). Now --loop=inf must be used to enable looping forever. Extend choice types to allow an optional range of integers as values. If CONF_RANGE is added to the flags of a m_option_type_choice option, m_option.min/max specify a range of allowed integer values. This can be used to remove "special" values from make integer range options. These special values are unintuitive, and sometimes expose mplayer internals to the user. The (internal) choice values can be freely mixed with the specified integer value range. If there are overlaps, the choice values are preferred for conversion to/from strings. Also make sure the extension to choice options works with properties. Add the ability to step choice properties downwards, instead of just upwards.
-rw-r--r--DOCS/man/en/changes.rst1
-rw-r--r--DOCS/man/en/options.rst5
-rw-r--r--cfg-mplayer.h4
-rw-r--r--command.c90
-rw-r--r--m_option.c12
-rw-r--r--m_option.h4
6 files changed, 90 insertions, 26 deletions
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index ee08aa2a60..e4f331e807 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -93,6 +93,7 @@ Command line switches
=================================== ===================================
-nosound --no-audio
-use-filename-title --title="${filename}"
+ -loop 0 --loop=inf
=================================== ===================================
input.conf and slave commands
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index 4e8ee56d68..cf622e5c31 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -1142,8 +1142,9 @@
*NOTE*: This option is obsolete now that MPlayer has OpenDML support.
---loop=<number>
- Loops movie playback <number> times. 0 means forever.
+--loop=<number|inf|off>
+ Loops playback <number> times. ``inf`` means forever and ``off`` disables
+ looping.
--mc=<seconds/frame>
Maximum A-V sync correction per frame (in seconds)
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index d27ee323d3..e433e91955 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -688,7 +688,9 @@ const m_option_t mplayer_opts[]={
{"leak-report", "", CONF_TYPE_PRINT, 0, 0, 0, (void*)1},
OPT_FLAG_CONSTANTS("no-loop", loop_times, 0, 0, -1),
- OPT_INTRANGE("loop", loop_times, 0, -1, 10000),
+ OPT_CHOICE_OR_INT("loop", loop_times, 0, 1, 10000,
+ ({"off", -1}, {"0", -1},
+ {"inf", 0})),
{"playlist", NULL, CONF_TYPE_STRING, CONF_NOCFG | M_OPT_MIN, 1, 0, NULL},
{"shuffle", NULL, CONF_TYPE_FLAG, CONF_NOCFG, 0, 0, NULL},
diff --git a/command.c b/command.c
index 7947f83d6a..8a7f17dfba 100644
--- a/command.c
+++ b/command.c
@@ -105,6 +105,66 @@ static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy,
vo->dheight, vo_fs);
}
+static void choice_get_min_max(const struct m_option *opt, int *min, int *max)
+{
+ assert(opt->type == &m_option_type_choice);
+ *min = INT_MAX;
+ *max = INT_MIN;
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) {
+ *min = FFMIN(*min, alt->value);
+ *max = FFMAX(*max, alt->value);
+ }
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ *min = FFMIN(*min, opt->min);
+ *max = FFMAX(*max, opt->max);
+ }
+}
+
+static void check_choice(int dir, int val, bool *found, int *best, int choice)
+{
+ if ((dir == -1 && (!(*found) || choice > (*best)) && choice < val) ||
+ (dir == +1 && (!(*found) || choice < (*best)) && choice > val))
+ {
+ *found = true;
+ *best = choice;
+ }
+}
+
+static int step_choice(const struct m_option *opt, int val, int add, bool wrap)
+{
+ assert(opt->type == &m_option_type_choice);
+ int dir = add > 0 ? +1 : -1;
+ bool found = false;
+ int best = 0; // init. value unused
+
+ if (add == 0)
+ return val;
+
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ int newval = val + add;
+ if (val >= opt->min && val <= opt->max &&
+ newval >= opt->min && newval <= opt->max)
+ {
+ found = true;
+ best = newval;
+ } else {
+ check_choice(dir, val, &found, &best, opt->min);
+ check_choice(dir, val, &found, &best, opt->max);
+ }
+ }
+
+ for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++)
+ check_choice(dir, val, &found, &best, alt->value);
+
+ if (!found) {
+ int min, max;
+ choice_get_min_max(opt, &min, &max);
+ best = (dir == -1) ^ wrap ? min : max;
+ }
+
+ return best;
+}
+
static int mp_property_generic_option(struct m_option *prop, int action,
void *arg, MPContext *mpctx)
{
@@ -125,13 +185,9 @@ static int mp_property_generic_option(struct m_option *prop, int action,
return M_PROPERTY_OK;
case M_PROPERTY_STEP_UP:
if (opt->type == &m_option_type_choice) {
+ int add = arg ? (*(int *)arg) : +1;
int v = *(int *) valptr;
- int best = v;
- struct m_opt_choice_alternatives *alt;
- for (alt = opt->priv; alt->name; alt++)
- if ((unsigned) alt->value - v - 1 < (unsigned) best - v - 1)
- best = alt->value;
- *(int *) valptr = best;
+ *(int *) valptr = step_choice(opt, v, add, true);
return M_PROPERTY_OK;
}
break;
@@ -150,20 +206,7 @@ static int mp_property_osdlevel(m_option_t *prop, int action, void *arg,
static int mp_property_loop(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
- struct MPOpts *opts = &mpctx->opts;
- switch (action) {
- case M_PROPERTY_PRINT:
- if (!arg)
- return M_PROPERTY_ERROR;
- if (opts->loop_times < 0)
- *(char **)arg = talloc_strdup(NULL, "off");
- else if (opts->loop_times == 0)
- *(char **)arg = talloc_strdup(NULL, "inf");
- else
- break;
- return M_PROPERTY_OK;
- }
- return m_property_int_range(prop, action, arg, &opts->loop_times);
+ return mp_property_generic_option(prop, action, arg, mpctx);
}
/// Playback speed (RW)
@@ -1628,8 +1671,8 @@ static const m_option_t mp_properties[] = {
// General
{ "osdlevel", mp_property_osdlevel, CONF_TYPE_INT,
M_OPT_RANGE, 0, 3, NULL },
- { "loop", mp_property_loop, CONF_TYPE_INT,
- M_OPT_MIN, -1, 0, NULL },
+ { "loop", mp_property_loop, &m_option_type_choice,
+ 0, 0, 0, "loop" },
{ "speed", mp_property_playback_speed, CONF_TYPE_FLOAT,
M_OPT_RANGE, 0.01, 100.0, NULL },
{ "filename", mp_property_filename, CONF_TYPE_STRING,
@@ -2192,7 +2235,8 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
&prop, mpctx)) <= 0)
goto step_prop_err;
if (prop->type == CONF_TYPE_INT ||
- prop->type == CONF_TYPE_FLAG)
+ prop->type == CONF_TYPE_FLAG ||
+ prop->type == &m_option_type_choice)
i = cmd->args[1].v.f, arg = &i;
else if (prop->type == CONF_TYPE_FLOAT)
arg = &cmd->args[1].v.f;
diff --git a/m_option.c b/m_option.c
index d2ab925a70..2f8daa42de 100644
--- a/m_option.c
+++ b/m_option.c
@@ -274,6 +274,14 @@ static int parse_choice(const struct m_option *opt, struct bstr name,
if (!alt->name) {
if (param.len == 0)
return M_OPT_MISSING_PARAM;
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ long long val;
+ if (parse_longlong(opt, name, param, &val) == 1) {
+ if (dst)
+ *(int *)dst = val;
+ return 1;
+ }
+ }
mp_msg(MSGT_CFGPARSER, MSGL_ERR,
"Invalid value for option %.*s: %.*s\n",
BSTR_P(name), BSTR_P(param));
@@ -296,6 +304,10 @@ static char *print_choice(const m_option_t *opt, const void *val)
for (alt = opt->priv; alt->name; alt++)
if (alt->value == v)
return talloc_strdup(NULL, alt->name);
+ if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) {
+ if (v >= opt->min && v <= opt->max)
+ return talloc_asprintf(NULL, "%d", v);
+ }
abort();
}
diff --git a/m_option.h b/m_option.h
index f46b14281c..2b3ab13355 100644
--- a/m_option.h
+++ b/m_option.h
@@ -465,6 +465,10 @@ static inline void m_option_free(const m_option_t *opt, void *dst)
#define OPT_HELPER_REMOVEPAREN(...) __VA_ARGS__
#define OPT_CHOICE(...) OPT_CHOICE_(__VA_ARGS__, .type = &m_option_type_choice)
#define OPT_CHOICE_(optname, varname, flags, choices, ...) OPT_GENERAL(optname, varname, flags, .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, __VA_ARGS__)
+// Union of choices and an int range. The choice values can be included in the
+// int range, or be completely separate - both works.
+#define OPT_CHOICE_OR_INT(...) OPT_CHOICE_OR_INT_(__VA_ARGS__, .type = &m_option_type_choice)
+#define OPT_CHOICE_OR_INT_(optname, varname, flags, minval, maxval, choices, ...) OPT_GENERAL(optname, varname, (flags) | CONF_RANGE, .min = minval, .max = maxval, .priv = (void *)&(const struct m_opt_choice_alternatives[]){OPT_HELPER_REMOVEPAREN choices, {NULL}}, __VA_ARGS__)
#define OPT_TIME(...) OPT_GENERAL(__VA_ARGS__, .type = &m_option_type_time)
// subconf must have the type struct m_sub_options.