v4l2: use a dynamic pod builder to handle larger PropInfo

The labels from the vivid driver need more space so use a dynamic
builder to make sure we can handle them.

See #4063
This commit is contained in:
Wim Taymans 2024-07-09 09:23:49 +02:00
parent b79f77b73d
commit bc9eb76a6e

View file

@ -11,6 +11,8 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <poll.h> #include <poll.h>
#include <spa/pod/dynamic.h>
#include <spa/utils/cleanup.h>
#include <spa/utils/result.h> #include <spa/utils/result.h>
static int xioctl(int fd, int request, void *arg) static int xioctl(int fd, int request, void *arg)
@ -1116,7 +1118,8 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
struct spa_v4l2_device *dev = &port->dev; struct spa_v4l2_device *dev = &port->dev;
struct v4l2_query_ext_ctrl queryctrl; struct v4l2_query_ext_ctrl queryctrl;
struct spa_pod *param; struct spa_pod *param;
struct spa_pod_builder b = { 0 }; spa_auto(spa_pod_dynamic_builder) b = { 0 };
struct spa_pod_builder_state state;
uint32_t prop_id, ctrl_id; uint32_t prop_id, ctrl_id;
uint8_t buffer[1024]; uint8_t buffer[1024];
int res; int res;
@ -1128,6 +1131,9 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
if ((res = spa_v4l2_open(dev, this->props.device)) < 0) if ((res = spa_v4l2_open(dev, this->props.device)) < 0)
return res; return res;
spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096);
spa_pod_builder_get_state(&b.b, &state);
result.id = SPA_PARAM_PropInfo; result.id = SPA_PARAM_PropInfo;
result.next = start; result.next = start;
next: next:
@ -1178,7 +1184,7 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
ctrl_id = queryctrl.id & ~next_fl; ctrl_id = queryctrl.id & ~next_fl;
spa_pod_builder_init(&b, buffer, sizeof(buffer)); spa_pod_builder_reset(&b.b, &state);
prop_id = control_to_prop_id(this, ctrl_id); prop_id = control_to_prop_id(this, ctrl_id);
@ -1191,7 +1197,7 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
switch (queryctrl.type) { switch (queryctrl.type) {
case V4L2_CTRL_TYPE_INTEGER: case V4L2_CTRL_TYPE_INTEGER:
port->controls[port->n_controls].type = SPA_TYPE_Int; port->controls[port->n_controls].type = SPA_TYPE_Int;
param = spa_pod_builder_add_object(&b, param = spa_pod_builder_add_object(&b.b,
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
SPA_PROP_INFO_id, SPA_POD_Id(prop_id), SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
SPA_PROP_INFO_type, SPA_POD_CHOICE_STEP_Int( SPA_PROP_INFO_type, SPA_POD_CHOICE_STEP_Int(
@ -1203,7 +1209,7 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
break; break;
case V4L2_CTRL_TYPE_BOOLEAN: case V4L2_CTRL_TYPE_BOOLEAN:
port->controls[port->n_controls].type = SPA_TYPE_Bool; port->controls[port->n_controls].type = SPA_TYPE_Bool;
param = spa_pod_builder_add_object(&b, param = spa_pod_builder_add_object(&b.b,
SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo,
SPA_PROP_INFO_id, SPA_POD_Id(prop_id), SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool((bool)queryctrl.default_value), SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool((bool)queryctrl.default_value),
@ -1212,11 +1218,10 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
case V4L2_CTRL_TYPE_MENU: case V4L2_CTRL_TYPE_MENU:
{ {
struct v4l2_querymenu querymenu; struct v4l2_querymenu querymenu;
struct spa_pod_builder_state state;
port->controls[port->n_controls].type = SPA_TYPE_Int; port->controls[port->n_controls].type = SPA_TYPE_Int;
spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo); spa_pod_builder_push_object(&b.b, &f[0], SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo);
spa_pod_builder_add(&b, spa_pod_builder_add(&b.b,
SPA_PROP_INFO_id, SPA_POD_Id(prop_id), SPA_PROP_INFO_id, SPA_POD_Id(prop_id),
SPA_PROP_INFO_type, SPA_POD_CHOICE_ENUM_Int(1, (int32_t)queryctrl.default_value), SPA_PROP_INFO_type, SPA_POD_CHOICE_ENUM_Int(1, (int32_t)queryctrl.default_value),
SPA_PROP_INFO_description, SPA_POD_String(queryctrl.name), SPA_PROP_INFO_description, SPA_POD_String(queryctrl.name),
@ -1225,25 +1230,19 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
spa_zero(querymenu); spa_zero(querymenu);
querymenu.id = queryctrl.id; querymenu.id = queryctrl.id;
spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0); spa_pod_builder_prop(&b.b, SPA_PROP_INFO_labels, 0);
spa_pod_builder_get_state(&b, &state); spa_pod_builder_push_struct(&b.b, &f[1]);
spa_pod_builder_push_struct(&b, &f[1]);
for (querymenu.index = queryctrl.minimum; for (querymenu.index = queryctrl.minimum;
querymenu.index <= queryctrl.maximum; querymenu.index <= queryctrl.maximum;
querymenu.index++) { querymenu.index++) {
if (xioctl(dev->fd, VIDIOC_QUERYMENU, &querymenu) == 0) { if (xioctl(dev->fd, VIDIOC_QUERYMENU, &querymenu) == 0) {
spa_pod_builder_int(&b, querymenu.index); spa_pod_builder_int(&b.b, querymenu.index);
spa_pod_builder_string(&b, (const char *)querymenu.name); spa_pod_builder_string(&b.b, (const char *)querymenu.name);
} }
} }
if (spa_pod_builder_pop(&b, &f[1]) == NULL) { spa_pod_builder_pop(&b.b, &f[1]);
spa_log_warn(this->log, "can't create Control '%s' overflow %d", param = spa_pod_builder_pop(&b.b, &f[0]);
queryctrl.name, b.state.offset);
spa_pod_builder_reset(&b, &state);
spa_pod_builder_none(&b);
}
param = spa_pod_builder_pop(&b, &f[0]);
break; break;
} }
case V4L2_CTRL_TYPE_INTEGER_MENU: case V4L2_CTRL_TYPE_INTEGER_MENU:
@ -1258,7 +1257,7 @@ spa_v4l2_enum_controls(struct impl *this, int seq,
port->n_controls++; port->n_controls++;
if (spa_pod_filter(&b, &result.param, param, filter) < 0) if (spa_pod_filter(&b.b, &result.param, param, filter) < 0)
goto next; goto next;
spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result); spa_node_emit_result(&this->hooks, seq, 0, SPA_RESULT_TYPE_NODE_PARAMS, &result);