1
0
mirror of https://github.com/mpv-player/mpv synced 2025-01-19 13:51:14 +00:00

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.
This commit is contained in:
wm4 2012-09-05 02:17:13 +02:00
parent d29d4df634
commit c955549204
6 changed files with 90 additions and 26 deletions

View File

@ -93,6 +93,7 @@ Command line switches
=================================== ===================================
-nosound --no-audio
-use-filename-title --title="${filename}"
-loop 0 --loop=inf
=================================== ===================================
input.conf and slave commands

View File

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

View File

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

View File

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

View File

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

View File

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