diff options
-rw-r--r-- | DOCS/man/en/changes.rst | 1 | ||||
-rw-r--r-- | DOCS/man/en/options.rst | 5 | ||||
-rw-r--r-- | cfg-mplayer.h | 4 | ||||
-rw-r--r-- | command.c | 90 | ||||
-rw-r--r-- | m_option.c | 12 | ||||
-rw-r--r-- | m_option.h | 4 |
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}, @@ -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. |