diff options
Diffstat (limited to 'm_option.c')
-rw-r--r-- | m_option.c | 137 |
1 files changed, 135 insertions, 2 deletions
diff --git a/m_option.c b/m_option.c index 015b8f8e20..14a1a0a3d7 100644 --- a/m_option.c +++ b/m_option.c @@ -26,15 +26,18 @@ #include <math.h> #include <stdio.h> #include <stdarg.h> +#include <limits.h> #include <inttypes.h> #include <unistd.h> #include <assert.h> +#include <libavutil/common.h> +#include <libavutil/avstring.h> + #include "talloc.h" #include "m_option.h" #include "mp_msg.h" #include "stream/url.h" -#include "libavutil/avstring.h" char *m_option_strerror(int code) { @@ -128,6 +131,15 @@ static char *print_flag(const m_option_t *opt, const void *val) return talloc_strdup(NULL, "yes"); } +static void add_flag(const m_option_t *opt, void *val, double add, bool wrap) +{ + if (fabs(add) < 0.5) + return; + bool state = VAL(val) != opt->min; + state = wrap ? !state : add > 0; + VAL(val) = state ? opt->max : opt->min; +} + const m_option_type_t m_option_type_flag = { // need yes or no in config files .name = "Flag", @@ -136,10 +148,13 @@ const m_option_type_t m_option_type_flag = { .parse = parse_flag, .print = print_flag, .copy = copy_opt, + .add = add_flag, }; // Integer +#undef VAL + static int parse_longlong(const m_option_t *opt, struct bstr name, struct bstr param, void *dst) { @@ -202,7 +217,35 @@ static char *print_int(const m_option_t *opt, const void *val) { if (opt->type->size == sizeof(int64_t)) return talloc_asprintf(NULL, "%"PRId64, *(const int64_t *)val); - return talloc_asprintf(NULL, "%d", VAL(val)); + return talloc_asprintf(NULL, "%d", *(const int *)val); +} + +static void add_int64(const m_option_t *opt, void *val, double add, bool wrap) +{ + int64_t v = *(int64_t *)val; + + v = v + add; + + bool is64 = opt->type->size == sizeof(int64_t); + int64_t nmin = is64 ? INT64_MIN : INT_MIN; + int64_t nmax = is64 ? INT64_MAX : INT_MAX; + + int64_t min = (opt->flags & M_OPT_MIN) ? opt->min : nmin; + int64_t max = (opt->flags & M_OPT_MAX) ? opt->max : nmax; + + if (v < min) + v = wrap ? max : min; + if (v > max) + v = wrap ? min : max; + + *(int64_t *)val = v; +} + +static void add_int(const m_option_t *opt, void *val, double add, bool wrap) +{ + int64_t tmp = *(int *)val; + add_int64(opt, &tmp, add, wrap); + *(int *)val = tmp; } const m_option_type_t m_option_type_int = { @@ -211,6 +254,7 @@ const m_option_type_t m_option_type_int = { .parse = parse_int, .print = print_int, .copy = copy_opt, + .add = add_int, }; const m_option_type_t m_option_type_int64 = { @@ -219,6 +263,7 @@ const m_option_type_t m_option_type_int64 = { .parse = parse_int64, .print = print_int, .copy = copy_opt, + .add = add_int64, }; static int parse_intpair(const struct m_option *opt, struct bstr name, @@ -311,12 +356,74 @@ static char *print_choice(const m_option_t *opt, const void *val) abort(); } +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 void add_choice(const m_option_t *opt, void *val, double add, bool wrap) +{ + assert(opt->type == &m_option_type_choice); + int dir = add > 0 ? +1 : -1; + bool found = false; + int ival = *(int *)val; + int best = 0; // init. value unused + + if (fabs(add) < 0.5) + return; + + if ((opt->flags & M_OPT_MIN) && (opt->flags & M_OPT_MAX)) { + int newval = ival + add; + if (ival >= opt->min && ival <= opt->max && + newval >= opt->min && newval <= opt->max) + { + found = true; + best = newval; + } else { + check_choice(dir, ival, &found, &best, opt->min); + check_choice(dir, ival, &found, &best, opt->max); + } + } + + for (struct m_opt_choice_alternatives *alt = opt->priv; alt->name; alt++) + check_choice(dir, ival, &found, &best, alt->value); + + if (!found) { + int min, max; + choice_get_min_max(opt, &min, &max); + best = (dir == -1) ^ wrap ? min : max; + } + + *(int *)val = best; +} + const struct m_option_type m_option_type_choice = { .name = "String", // same as arbitrary strings in option list for now .size = sizeof(int), .parse = parse_choice, .print = print_choice, .copy = copy_opt, + .add = add_choice, }; // Float @@ -386,6 +493,23 @@ static char *print_double(const m_option_t *opt, const void *val) return talloc_asprintf(NULL, "%f", VAL(val)); } +static void add_double(const m_option_t *opt, void *val, double add, bool wrap) +{ + double v = VAL(val); + + v = v + add; + + double min = (opt->flags & M_OPT_MIN) ? opt->min : -INFINITY; + double max = (opt->flags & M_OPT_MAX) ? opt->max : +INFINITY; + + if (v < min) + v = wrap ? max : min; + if (v > max) + v = wrap ? min : max; + + VAL(val) = v; +} + const m_option_type_t m_option_type_double = { // double precision float or ratio (numerator[:/]denominator) .name = "Double", @@ -414,6 +538,13 @@ static char *print_float(const m_option_t *opt, const void *val) return talloc_asprintf(NULL, "%f", VAL(val)); } +static void add_float(const m_option_t *opt, void *val, double add, bool wrap) +{ + double tmp = VAL(val); + add_double(opt, &tmp, add, wrap); + VAL(val) = tmp; +} + const m_option_type_t m_option_type_float = { // floating point number or ratio (numerator[:/]denominator) .name = "Float", @@ -421,6 +552,7 @@ const m_option_type_t m_option_type_float = { .parse = parse_float, .print = print_float, .copy = copy_opt, + .add = add_float, }; ///////////// String @@ -1009,6 +1141,7 @@ const m_option_type_t m_option_type_time = { .parse = parse_time, .print = print_double, .copy = copy_opt, + .add = add_double, }; |