mirror of
https://github.com/mpv-player/mpv
synced 2024-11-14 22:48:35 +01:00
m_option: add option comparison
Looks like this will be needed for fine-grained option change notifications. There are some other parts in the player which implement parts of this.
This commit is contained in:
parent
82735d1287
commit
63270ff898
@ -40,6 +40,7 @@
|
||||
#include "common/msg.h"
|
||||
#include "common/msg_control.h"
|
||||
#include "misc/json.h"
|
||||
#include "misc/node.h"
|
||||
#include "m_option.h"
|
||||
#include "m_config.h"
|
||||
|
||||
@ -169,6 +170,11 @@ static int flag_get(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool flag_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return VAL(a) == VAL(b);
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_flag = {
|
||||
// need yes or no in config files
|
||||
.name = "Flag",
|
||||
@ -180,6 +186,7 @@ const m_option_type_t m_option_type_flag = {
|
||||
.add = add_flag,
|
||||
.set = flag_set,
|
||||
.get = flag_get,
|
||||
.equal = flag_equal,
|
||||
};
|
||||
|
||||
// Integer
|
||||
@ -359,6 +366,16 @@ static int int_get(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool int_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return *(int *)a == *(int *)b;
|
||||
}
|
||||
|
||||
static bool int64_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return *(int64_t *)a == *(int64_t *)b;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_int = {
|
||||
.name = "Integer",
|
||||
.size = sizeof(int),
|
||||
@ -369,6 +386,7 @@ const m_option_type_t m_option_type_int = {
|
||||
.multiply = multiply_int,
|
||||
.set = int_set,
|
||||
.get = int_get,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
const m_option_type_t m_option_type_int64 = {
|
||||
@ -381,6 +399,7 @@ const m_option_type_t m_option_type_int64 = {
|
||||
.multiply = multiply_int64,
|
||||
.set = int64_set,
|
||||
.get = int64_get,
|
||||
.equal = int64_equal,
|
||||
};
|
||||
|
||||
static int parse_byte_size(struct mp_log *log, const m_option_t *opt,
|
||||
@ -478,6 +497,7 @@ const m_option_type_t m_option_type_byte_size = {
|
||||
.multiply = multiply_int64,
|
||||
.set = int64_set,
|
||||
.get = int64_get,
|
||||
.equal = int64_equal,
|
||||
};
|
||||
|
||||
static int parse_intpair(struct mp_log *log, const struct m_option *opt,
|
||||
@ -746,6 +766,7 @@ const struct m_option_type m_option_type_choice = {
|
||||
.add = add_choice,
|
||||
.set = choice_set,
|
||||
.get = choice_get,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
static int apply_flag(const struct m_option *opt, int *val, bstr flag)
|
||||
@ -868,6 +889,7 @@ const struct m_option_type m_option_type_flags = {
|
||||
.copy = copy_opt,
|
||||
.set = flags_set,
|
||||
.get = flags_get,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
// Float
|
||||
@ -1002,6 +1024,14 @@ static int double_get(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool double_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
double fa = VAL(a), fb = VAL(b);
|
||||
if (isnan(fa) || isnan(fb))
|
||||
return isnan(fa) == isnan(fb);
|
||||
return fa == fb;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_double = {
|
||||
// double precision float or ratio (numerator[:/]denominator)
|
||||
.name = "Double",
|
||||
@ -1014,6 +1044,7 @@ const m_option_type_t m_option_type_double = {
|
||||
.multiply = multiply_double,
|
||||
.set = double_set,
|
||||
.get = double_get,
|
||||
.equal = double_equal,
|
||||
};
|
||||
|
||||
#undef VAL
|
||||
@ -1071,6 +1102,11 @@ static int float_get(const m_option_t *opt, void *ta_parent,
|
||||
return double_get(opt, ta_parent, dst, &tmp);
|
||||
}
|
||||
|
||||
static bool float_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return double_equal(opt, &(double){VAL(a)}, &(double){VAL(b)});
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_float = {
|
||||
// floating point number or ratio (numerator[:/]denominator)
|
||||
.name = "Float",
|
||||
@ -1083,6 +1119,7 @@ const m_option_type_t m_option_type_float = {
|
||||
.multiply = multiply_float,
|
||||
.set = float_set,
|
||||
.get = float_get,
|
||||
.equal = float_equal,
|
||||
};
|
||||
|
||||
static int parse_float_aspect(struct mp_log *log, const m_option_t *opt,
|
||||
@ -1108,6 +1145,7 @@ const m_option_type_t m_option_type_aspect = {
|
||||
.multiply = multiply_float,
|
||||
.set = float_set,
|
||||
.get = float_get,
|
||||
.equal = float_equal,
|
||||
};
|
||||
|
||||
///////////// String
|
||||
@ -1188,6 +1226,11 @@ static int str_get(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool str_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return bstr_equals(bstr0(VAL(a)), bstr0(VAL(b)));
|
||||
}
|
||||
|
||||
static void free_str(void *src)
|
||||
{
|
||||
if (src && VAL(src)) {
|
||||
@ -1205,6 +1248,7 @@ const m_option_type_t m_option_type_string = {
|
||||
.free = free_str,
|
||||
.set = str_set,
|
||||
.get = str_get,
|
||||
.equal = str_equal,
|
||||
};
|
||||
|
||||
//////////// String list
|
||||
@ -1530,6 +1574,26 @@ static int parse_str_list(struct mp_log *log, const m_option_t *opt,
|
||||
return parse_str_list_impl(log, opt, name, param, dst, OP_NONE);
|
||||
}
|
||||
|
||||
static bool str_list_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
char **la = VAL(a);
|
||||
char **lb = VAL(b);
|
||||
|
||||
bool a_empty = !la || !la[0];
|
||||
bool b_empty = !lb || !lb[0];
|
||||
if (a_empty || b_empty)
|
||||
return a_empty == b_empty;
|
||||
|
||||
for (int n = 0; la[n] || lb[n]; n++) {
|
||||
if (!la[n] || !lb[n])
|
||||
return false;
|
||||
if (strcmp(la[n], lb[n]) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_string_list = {
|
||||
.name = "String list",
|
||||
.size = sizeof(char **),
|
||||
@ -1539,6 +1603,7 @@ const m_option_type_t m_option_type_string_list = {
|
||||
.free = free_str_list,
|
||||
.get = str_list_get,
|
||||
.set = str_list_set,
|
||||
.equal = str_list_equal,
|
||||
.actions = (const struct m_option_action[]){
|
||||
{"add"},
|
||||
{"append"},
|
||||
@ -1688,6 +1753,7 @@ const m_option_type_t m_option_type_keyvalue_list = {
|
||||
.free = free_str_list,
|
||||
.get = keyvalue_list_get,
|
||||
.set = keyvalue_list_set,
|
||||
.equal = str_list_equal,
|
||||
.actions = (const struct m_option_action[]){
|
||||
{"add"},
|
||||
{"append"},
|
||||
@ -1760,6 +1826,7 @@ const m_option_type_t m_option_type_msglevels = {
|
||||
.free = free_str_list,
|
||||
.get = keyvalue_list_get,
|
||||
.set = set_msglevels,
|
||||
.equal = str_list_equal,
|
||||
};
|
||||
|
||||
static int parse_print(struct mp_log *log, const m_option_t *opt,
|
||||
@ -1972,12 +2039,20 @@ static char *print_color(const m_option_t *opt, const void *val)
|
||||
return talloc_asprintf(NULL, "#%02X%02X%02X%02X", c->a, c->r, c->g, c->b);
|
||||
}
|
||||
|
||||
static bool color_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
struct m_color *ca = a;
|
||||
struct m_color *cb = b;
|
||||
return ca->a == cb->a && ca->r == cb->r && ca->g == cb->g && ca->b == cb->b;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_color = {
|
||||
.name = "Color",
|
||||
.size = sizeof(struct m_color),
|
||||
.parse = parse_color,
|
||||
.print = print_color,
|
||||
.copy = copy_opt,
|
||||
.equal = color_equal,
|
||||
};
|
||||
|
||||
|
||||
@ -2154,12 +2229,24 @@ exit:
|
||||
return is_help ? M_OPT_EXIT : M_OPT_INVALID;
|
||||
}
|
||||
|
||||
static bool geometry_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
struct m_geometry *ga = a;
|
||||
struct m_geometry *gb = b;
|
||||
return ga->x == gb->x && ga->y == gb->y && ga->w == gb->w && ga->h == gb->h &&
|
||||
ga->xy_valid == gb->xy_valid && ga->wh_valid == gb->wh_valid &&
|
||||
ga->w_per == gb->w_per && ga->h_per == gb->h_per &&
|
||||
ga->x_per == gb->x_per && ga->y_per == gb->y_per &&
|
||||
ga->x_sign == gb->x_sign && ga->y_sign == gb->y_sign;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_geometry = {
|
||||
.name = "Window geometry",
|
||||
.size = sizeof(struct m_geometry),
|
||||
.parse = parse_geometry,
|
||||
.print = print_geometry,
|
||||
.copy = copy_opt,
|
||||
.equal = geometry_equal,
|
||||
};
|
||||
|
||||
static int parse_size_box(struct mp_log *log, const m_option_t *opt,
|
||||
@ -2196,6 +2283,7 @@ const m_option_type_t m_option_type_size_box = {
|
||||
.parse = parse_size_box,
|
||||
.print = print_geometry,
|
||||
.copy = copy_opt,
|
||||
.equal = geometry_equal,
|
||||
};
|
||||
|
||||
|
||||
@ -2246,6 +2334,7 @@ const m_option_type_t m_option_type_imgfmt = {
|
||||
.parse = parse_imgfmt,
|
||||
.print = print_imgfmt,
|
||||
.copy = copy_opt,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
static int parse_fourcc(struct mp_log *log, const m_option_t *opt,
|
||||
@ -2287,6 +2376,7 @@ const m_option_type_t m_option_type_fourcc = {
|
||||
.parse = parse_fourcc,
|
||||
.print = print_fourcc,
|
||||
.copy = copy_opt,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
#include "audio/format.h"
|
||||
@ -2334,6 +2424,7 @@ const m_option_type_t m_option_type_afmt = {
|
||||
.parse = parse_afmt,
|
||||
.print = print_afmt,
|
||||
.copy = copy_opt,
|
||||
.equal = int_equal,
|
||||
};
|
||||
|
||||
#include "audio/chmap.h"
|
||||
@ -2436,6 +2527,13 @@ static void copy_channels(const m_option_t *opt, void *dst, const void *src)
|
||||
talloc_memdup(NULL, ch->chmaps, sizeof(ch->chmaps[0]) * ch->num_chmaps);
|
||||
}
|
||||
|
||||
static bool channels_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
struct mp_chmap *ca = a;
|
||||
struct mp_chmap *cb = b;
|
||||
return mp_chmap_equals(ca, cb);
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_channels = {
|
||||
.name = "Audio channels or channel map",
|
||||
.size = sizeof(struct m_channels),
|
||||
@ -2443,6 +2541,7 @@ const m_option_type_t m_option_type_channels = {
|
||||
.print = print_channels,
|
||||
.copy = copy_channels,
|
||||
.free = free_channels,
|
||||
.equal = channels_equal,
|
||||
};
|
||||
|
||||
static int parse_timestring(struct bstr str, double *time, char endchar)
|
||||
@ -2535,6 +2634,7 @@ const m_option_type_t m_option_type_time = {
|
||||
.add = add_double,
|
||||
.set = time_set,
|
||||
.get = time_get,
|
||||
.equal = double_equal,
|
||||
};
|
||||
|
||||
|
||||
@ -2611,12 +2711,20 @@ static char *print_rel_time(const m_option_t *opt, const void *val)
|
||||
return talloc_strdup(NULL, "none");
|
||||
}
|
||||
|
||||
static bool rel_time_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
struct m_rel_time *ta = a;
|
||||
struct m_rel_time *tb = b;
|
||||
return ta->type == tb->type && ta->pos == tb->pos;
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_rel_time = {
|
||||
.name = "Relative time or percent position",
|
||||
.size = sizeof(struct m_rel_time),
|
||||
.parse = parse_rel_time,
|
||||
.print = print_rel_time,
|
||||
.copy = copy_opt,
|
||||
.equal = rel_time_equal,
|
||||
};
|
||||
|
||||
|
||||
@ -3447,6 +3555,26 @@ static int get_obj_settings_list(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool obj_settings_list_equal(const m_option_t *opt, void *pa, void *pb)
|
||||
{
|
||||
struct m_obj_settings *a = VAL(pa);
|
||||
struct m_obj_settings *b = VAL(pb);
|
||||
|
||||
if (a == b || !a || !b)
|
||||
return a == b;
|
||||
|
||||
if (!str_equal(NULL, &a->name, &b->name))
|
||||
return false;
|
||||
|
||||
if (!str_equal(NULL, &a->label, &b->label))
|
||||
return false;
|
||||
|
||||
if (a->enabled != b->enabled)
|
||||
return false;
|
||||
|
||||
return str_list_equal(NULL, &a->attribs, &b->attribs);
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_obj_settings_list = {
|
||||
.name = "Object settings list",
|
||||
.size = sizeof(m_obj_settings_t *),
|
||||
@ -3456,6 +3584,7 @@ const m_option_type_t m_option_type_obj_settings_list = {
|
||||
.free = free_obj_settings_list,
|
||||
.set = set_obj_settings_list,
|
||||
.get = get_obj_settings_list,
|
||||
.equal = obj_settings_list_equal,
|
||||
.actions = (const struct m_option_action[]){
|
||||
{"add"},
|
||||
{"clr", M_OPT_TYPE_OPTIONAL_PARAM},
|
||||
@ -3587,6 +3716,11 @@ static int node_get(const m_option_t *opt, void *ta_parent,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool node_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
return equal_mpv_node(&VAL(a), &VAL(b));
|
||||
}
|
||||
|
||||
const m_option_type_t m_option_type_node = {
|
||||
.name = "Complex",
|
||||
.size = sizeof(struct mpv_node),
|
||||
@ -3597,6 +3731,7 @@ const m_option_type_t m_option_type_node = {
|
||||
.free = free_node,
|
||||
.set = node_set,
|
||||
.get = node_get,
|
||||
.equal = node_equal,
|
||||
};
|
||||
|
||||
// Special-cased by m_config.c.
|
||||
|
@ -338,6 +338,17 @@ struct m_option_type {
|
||||
int (*get)(const m_option_t *opt, void *ta_parent, struct mpv_node *dst,
|
||||
void *src);
|
||||
|
||||
// Return whether the values are the same. (There are no "unordered"
|
||||
// results; for example, two floats with the value NaN compare equal. Other
|
||||
// ambiguous floats, such as +0 and -0 compare equal. Some option types may
|
||||
// incorrectly report unequal for values that are equal, such as sets (if
|
||||
// the element order is different, which incorrectly matters), but values
|
||||
// duplicated with m_option_copy() always return as equal. Empty strings
|
||||
// and NULL strings are equal. Ambiguous unicode representations compare
|
||||
// unequal.)
|
||||
// If not set, values are always considered equal (=> not really optional).
|
||||
bool (*equal)(const m_option_t *opt, void *a, void *b);
|
||||
|
||||
// Optional: list of suffixes, terminated with a {0} entry. An empty list
|
||||
// behaves like the list being NULL.
|
||||
const struct m_option_action *actions;
|
||||
@ -543,6 +554,15 @@ static inline int m_option_get_node(const m_option_t *opt, void *ta_parent,
|
||||
return M_OPT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline bool m_option_equal(const m_option_t *opt, void *a, void *b)
|
||||
{
|
||||
// Handle trivial equivalence.
|
||||
// If not implemented, assume this type has no actual values => always equal.
|
||||
if (a == b || !opt->type->equal)
|
||||
return true;
|
||||
return opt->type->equal(opt, a, b);
|
||||
}
|
||||
|
||||
int m_option_required_params(const m_option_t *opt);
|
||||
|
||||
extern const char m_option_path_separator;
|
||||
|
Loading…
Reference in New Issue
Block a user