pod: improve parser and builder

Remove the spa_pod_iter helpers
Remove builder/parser vararg recurse option, you have to
manually recurse into structures when needed. This simplifies
things a lot.
Pass spa_pod_frames to builder and parser explicitly, we don't
have to keep an internal stack anymore.
The parser is now almost a mirror image of the builder.
Make the parser safer when iterating over objects, add functions
to check and get pod contents in a safe way.
Make the builder return errno style results on errors
Improve performance of object properties when they are stored and
retrieved in the same order.
Add many more tests for the builder and parser
Add some benchmarks
This commit is contained in:
Wim Taymans 2019-01-22 17:38:23 +01:00
parent 878ae769ef
commit 351fb9ce29
36 changed files with 1605 additions and 973 deletions

View file

@ -84,6 +84,7 @@ static void fill_item(struct impl *this, struct udev_device *dev,
struct spa_pod **result, struct spa_pod_builder *builder)
{
const char *str, *name;
struct spa_pod_frame f[2];
name = udev_device_get_property_value(dev, "ID_V4L_PRODUCT");
if (!(name && *name)) {
@ -98,7 +99,7 @@ static void fill_item(struct impl *this, struct udev_device *dev,
if (!(name && *name))
name = "Unknown";
spa_pod_builder_push_object(builder, SPA_TYPE_OBJECT_MonitorItem, 0);
spa_pod_builder_push_object(builder, &f[0], SPA_TYPE_OBJECT_MonitorItem, 0);
spa_pod_builder_add(builder,
SPA_MONITOR_ITEM_id, SPA_POD_String(udev_device_get_syspath(dev)),
SPA_MONITOR_ITEM_flags, SPA_POD_Id(SPA_MONITOR_ITEM_FLAG_NONE),
@ -110,7 +111,7 @@ static void fill_item(struct impl *this, struct udev_device *dev,
0);
spa_pod_builder_prop(builder, SPA_MONITOR_ITEM_info, 0);
spa_pod_builder_push_struct(builder);
spa_pod_builder_push_struct(builder, &f[1]);
add_dict(builder, "udev-probed", "1");
add_dict(builder, "device.path", udev_device_get_devnode(dev));
@ -159,8 +160,8 @@ static void fill_item(struct impl *this, struct udev_device *dev,
add_dict(builder, "device.capabilities", str);
}
spa_pod_builder_pop(builder);
*result = spa_pod_builder_pop(builder);
spa_pod_builder_pop(builder, &f[1]);
*result = spa_pod_builder_pop(builder, &f[0]);
}
static int emit_device(struct impl *this, uint32_t id, struct udev_device *dev)

View file

@ -430,13 +430,14 @@ static int port_get_format(struct spa_node *node,
{
struct impl *this = SPA_CONTAINER_OF(node, struct impl, node);
struct port *port = GET_PORT(this, direction, port_id);
struct spa_pod_frame f;
if (!port->have_format)
return -EIO;
if (*index > 0)
return 0;
spa_pod_builder_push_object(builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_Format);
spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_Format, SPA_PARAM_Format);
spa_pod_builder_add(builder,
SPA_FORMAT_mediaType, SPA_POD_Id(port->current_format.media_type),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(port->current_format.media_subtype),
@ -467,7 +468,7 @@ static int port_get_format(struct spa_node *node,
return -EIO;
}
*param = spa_pod_builder_pop(builder);
*param = spa_pod_builder_pop(builder, &f);
return 1;
}

View file

@ -402,12 +402,12 @@ enum_filter_format(uint32_t media_type, int32_t media_subtype,
case SPA_MEDIA_TYPE_video:
case SPA_MEDIA_TYPE_image:
if (media_subtype == SPA_MEDIA_SUBTYPE_raw) {
struct spa_pod_prop *p;
const struct spa_pod_prop *p;
const struct spa_pod *val;
uint32_t n_values, choice;
const uint32_t *values;
if (!(p = spa_pod_find_prop(filter, SPA_FORMAT_VIDEO_format)))
if (!(p = spa_pod_find_prop(filter, NULL, SPA_FORMAT_VIDEO_format)))
return SPA_VIDEO_FORMAT_UNKNOWN;
val = spa_pod_get_values(&p->value, &n_values, &choice);
@ -532,6 +532,7 @@ spa_v4l2_enum_format(struct impl *this,
struct spa_pod_choice *choice;
uint32_t filter_media_type, filter_media_subtype, video_format;
struct spa_v4l2_device *dev = &port->dev;
struct spa_pod_frame f[2];
if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
return res;
@ -592,12 +593,12 @@ spa_v4l2_enum_format(struct impl *this,
next_frmsize:
while (port->next_frmsize) {
if (filter) {
struct spa_pod_prop *p;
const struct spa_pod_prop *p;
struct spa_pod *val;
uint32_t n_vals, choice;
/* check if we have a fixed frame size */
if (!(p = spa_pod_find_prop(filter, SPA_FORMAT_VIDEO_size)))
if (!(p = spa_pod_find_prop(filter, NULL, SPA_FORMAT_VIDEO_size)))
goto do_frmsize;
val = spa_pod_get_values(&p->value, &n_vals, &choice);
@ -626,13 +627,13 @@ spa_v4l2_enum_format(struct impl *this,
goto exit;
}
if (filter) {
struct spa_pod_prop *p;
const struct spa_pod_prop *p;
struct spa_pod *val;
const struct spa_rectangle step = { 1, 1 }, *values;
uint32_t choice, i, n_values;
/* check if we have a fixed frame size */
if (!(p = spa_pod_find_prop(filter, SPA_FORMAT_VIDEO_size)))
if (!(p = spa_pod_find_prop(filter, NULL, SPA_FORMAT_VIDEO_size)))
goto have_size;
val = spa_pod_get_values(&p->value, &n_values, &choice);
@ -680,7 +681,7 @@ spa_v4l2_enum_format(struct impl *this,
}
}
spa_pod_builder_push_object(builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_push_object(builder, &f[0], SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(builder,
SPA_FORMAT_mediaType, SPA_POD_Id(info->media_type),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(info->media_subtype),
@ -697,8 +698,8 @@ spa_v4l2_enum_format(struct impl *this,
n_fractions = 0;
choice = spa_pod_builder_deref(builder,
spa_pod_builder_push_choice(builder, SPA_CHOICE_None, 0));
spa_pod_builder_push_choice(builder, &f[1], SPA_CHOICE_None, 0);
choice = (struct spa_pod_choice*)spa_pod_builder_frame(builder, &f[1]);
port->frmival.index = 0;
while (true) {
@ -715,12 +716,12 @@ spa_v4l2_enum_format(struct impl *this,
goto exit;
}
if (filter) {
struct spa_pod_prop *p;
const struct spa_pod_prop *p;
struct spa_pod *val;
uint32_t i, n_values, choice;
const struct spa_fraction step = { 1, 1 }, *values;
if (!(p = spa_pod_find_prop(filter, SPA_FORMAT_VIDEO_framerate)))
if (!(p = spa_pod_find_prop(filter, NULL, SPA_FORMAT_VIDEO_framerate)))
goto have_framerate;
val = spa_pod_get_values(&p->value, &n_values, &choice);
@ -800,8 +801,8 @@ spa_v4l2_enum_format(struct impl *this,
if (n_fractions <= 1)
choice->body.type = SPA_CHOICE_None;
spa_pod_builder_pop(builder);
*result = spa_pod_builder_pop(builder);
spa_pod_builder_pop(builder, &f[1]);
*result = spa_pod_builder_pop(builder, &f[0]);
(*index)++;
@ -1009,6 +1010,7 @@ spa_v4l2_enum_controls(struct impl *this,
uint8_t buffer[1024];
int res;
const unsigned next_fl = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
struct spa_pod_frame f[2];
if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
return res;
@ -1091,7 +1093,7 @@ spa_v4l2_enum_controls(struct impl *this,
{
struct v4l2_querymenu querymenu;
spa_pod_builder_push_object(&b, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo);
spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo);
spa_pod_builder_add(&b,
SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
SPA_PROP_INFO_type, SPA_POD_CHOICE_ENUM_Int(1, queryctrl.default_value),
@ -1102,7 +1104,7 @@ spa_v4l2_enum_controls(struct impl *this,
querymenu.id = queryctrl.id;
spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0);
spa_pod_builder_push_struct(&b);
spa_pod_builder_push_struct(&b, &f[1]);
for (querymenu.index = queryctrl.minimum;
querymenu.index <= queryctrl.maximum;
querymenu.index++) {
@ -1111,8 +1113,8 @@ spa_v4l2_enum_controls(struct impl *this,
spa_pod_builder_string(&b, (const char *)querymenu.name);
}
}
spa_pod_builder_pop(&b);
param = spa_pod_builder_pop(&b);
spa_pod_builder_pop(&b, &f[1]);
param = spa_pod_builder_pop(&b, &f[0]);
break;
}
case V4L2_CTRL_TYPE_INTEGER_MENU: