options/m_option: add m_option_type_prop_array

Add adaptor for arrays of properties, this is not used as real option,
as those are always string list. But as a connector struct for creating
typed node arrays, in (sub)_properties.
This commit is contained in:
Kacper Michajłow committed 2026-05-01 11:41:31 +02:00
1 parent eedadc24ae
commit 28ce461a84
3 files changed
+122

No files matched your search

+103
View File
@@ -1666,6 +1666,109 @@ const m_option_type_t m_option_type_string_list = {
},
};
//////////// Property array
// Adaptor that converts a typed C array into a MPV_FORMAT_NODE_ARRAY
// sub-property. This is for read-only access, parse/set are not intentionally
// omitted.
static int prop_array_get(const m_option_t *opt, void *ta_parent,
struct mpv_node *dst, void *src)
{
struct m_prop_arr *arr = src;
mp_assert(arr->elem_type);
mp_assert(arr->elem_type->size > 0);
size_t elem_size = arr->elem_type->size;
const char *base = arr->data;
dst->format = MPV_FORMAT_NODE_ARRAY;
dst->u.list = talloc_zero(ta_parent, mpv_node_list);
struct mpv_node_list *list = dst->u.list;
struct m_option elem_opt = {.type = arr->elem_type};
for (int i = 0; i < arr->count; i++) {
MP_TARRAY_GROW(list, list->values, list->num);
if (m_option_get_node(&elem_opt, list, &list->values[list->num],
(void *)&base[i * elem_size]) >= 0)
list->num++;
}
return 1;
}
static char *print_prop_array(const m_option_t *opt, const void *val)
{
const struct m_prop_arr *arr = val;
mp_assert(arr->elem_type);
mp_assert(arr->elem_type->size > 0);
size_t elem_size = arr->elem_type->size;
const char *base = arr->data;
struct m_option elem_opt = {.type = arr->elem_type};
char *ret = talloc_strdup(NULL, "");
for (int i = 0; i < arr->count; i++) {
char *s = m_option_print(&elem_opt, &base[i * elem_size]);
if (i > 0)
ret = talloc_strdup_append(ret, ",");
ret = talloc_strdup_append(ret, s ? s : "?");
talloc_free(s);
}
return ret;
}
static void free_prop_array(void *val)
{
struct m_prop_arr *arr = val;
if (!arr->data)
return;
size_t elem_size = arr->elem_type->size;
char *base = (char *)arr->data;
struct m_option elem_opt = {.type = arr->elem_type};
for (int i = 0; i < arr->count; i++)
m_option_free(&elem_opt, &base[i * elem_size]);
talloc_free(base);
arr->data = NULL;
arr->count = 0;
}
static void copy_prop_array(const m_option_t *opt, void *dst, const void *src)
{
const struct m_prop_arr *s = src;
struct m_prop_arr *d = dst;
free_prop_array(d);
*d = (struct m_prop_arr){.elem_type = s->elem_type, .count = s->count};
if (!s->data || !s->count)
return;
size_t elem_size = s->elem_type->size;
const char *sbase = s->data;
char *dbase = talloc_zero_size(NULL, (size_t)s->count * elem_size);
struct m_option elem_opt = {.type = s->elem_type};
for (int i = 0; i < s->count; i++)
m_option_copy(&elem_opt, &dbase[i * elem_size], &sbase[i * elem_size]);
d->data = dbase;
}
static bool equal_prop_array(const m_option_t *opt, void *a, void *b)
{
struct m_prop_arr *pa = a, *pb = b;
if (pa->count != pb->count || pa->elem_type != pb->elem_type)
return false;
size_t elem_size = pa->elem_type->size;
char *abase = pa->data;
char *bbase = pb->data;
struct m_option elem_opt = {.type = pa->elem_type};
for (int i = 0; i < pa->count; i++) {
if (!m_option_equal(&elem_opt, &abase[i * elem_size], &bbase[i * elem_size]))
return false;
}
return true;
}
const m_option_type_t m_option_type_prop_array = {
.name = "Property array",
.size = sizeof(struct m_prop_arr),
.print = print_prop_array,
.copy = copy_prop_array,
.free = free_prop_array,
.get = prop_array_get,
.equal = equal_prop_array,
};
static int read_subparam(struct mp_log *log, bstr optname, char *termset,
bstr *str, bstr *out_subparam);
+9
View File
@@ -50,6 +50,7 @@ extern const m_option_type_t m_option_type_float;
extern const m_option_type_t m_option_type_double;
extern const m_option_type_t m_option_type_string;
extern const m_option_type_t m_option_type_string_list;
extern const m_option_type_t m_option_type_prop_array;
extern const m_option_type_t m_option_type_string_append_list;
extern const m_option_type_t m_option_type_keyvalue_list;
extern const m_option_type_t m_option_type_time;
@@ -227,6 +228,13 @@ struct m_sub_options {
bool (*get_sub_options)(int index, const struct m_sub_options **sub);
};
// A typed C array value for use with m_option_type_prop_array.
struct m_prop_arr {
void *data; // first element; owned iff produced by copy
int count; // number of elements
const m_option_type_t *elem_type; // element type (must have a .get callback)
};
#define CONF_TYPE_BOOL (&m_option_type_bool)
#define CONF_TYPE_FLAG (&m_option_type_flag)
#define CONF_TYPE_INT (&m_option_type_int)
@@ -257,6 +265,7 @@ union m_option_value {
char *string;
char **string_list;
char **keyvalue_list;
struct m_prop_arr prop_arr;
int imgfmt;
unsigned int fourcc;
int afmt;
+10
View File
@@ -226,6 +226,16 @@ struct m_sub_property {
.type = {.type = &m_option_type_time}, .value = {.double_ = (f)}
#define SUB_PROP_KEYVALUE_LIST(l) \
.type = {.type = &m_option_type_keyvalue_list}, .value = {.keyvalue_list = (l)}
// Expose a C array as a read-only array sub-property. The caller retains
// ownership of the data pointer. It will be copied if needed. Used for
// to expose arrays as sub-properties.
#define SUB_PROP_TYPE_ARRAY(etype, ptr, n) \
.type = {.type = &m_option_type_prop_array}, \
.value = {.prop_arr = {.data = (ptr), .count = (n), .elem_type = (etype)}}
#define SUB_PROP_INT_ARRAY(ptr, n) SUB_PROP_TYPE_ARRAY(CONF_TYPE_INT, ptr, n)
#define SUB_PROP_INT64_ARRAY(ptr, n) SUB_PROP_TYPE_ARRAY(CONF_TYPE_INT64, ptr, n)
#define SUB_PROP_FLOAT_ARRAY(ptr, n) SUB_PROP_TYPE_ARRAY(CONF_TYPE_FLOAT, ptr, n)
#define SUB_PROP_DOUBLE_ARRAY(ptr, n) SUB_PROP_TYPE_ARRAY(CONF_TYPE_DOUBLE, ptr, n)
int m_property_read_sub_validate(void *ctx, struct m_property *prop,
int action, void *arg);