camera-streamer/device/v4l2/device_options.c
2022-04-11 12:42:17 +02:00

154 lines
3.8 KiB
C

#include "v4l2.h"
#include "device/device.h"
#include "opts/log.h"
#include "opts/control.h"
int v4l2_device_set_option_by_id(device_t *dev, const char *name, uint32_t id, int32_t value)
{
struct v4l2_control ctl = {0};
if (!dev) {
return -1;
}
ctl.id = id;
ctl.value = value;
E_LOG_DEBUG(dev, "Configuring option %s (%08x) = %d", name, id, value);
E_XIOCTL(dev, dev->v4l2->subdev_fd >= 0 ? dev->v4l2->subdev_fd : dev->v4l2->dev_fd, VIDIOC_S_CTRL, &ctl, "Can't set option %s", name);
return 0;
error:
return -1;
}
static int v4l2_device_set_option_string_fd_iter_id(device_t *dev, int fd, uint32_t *id, char *name, char *value)
{
struct v4l2_query_ext_ctrl qctrl = { .id = *id };
void *data = NULL;
if (0 != ioctl (fd, VIDIOC_QUERY_EXT_CTRL, &qctrl)) {
*id = 0;
return 0;
}
*id = qctrl.id;
device_option_normalize_name(qctrl.name, qctrl.name);
if (strcmp(qctrl.name, name) != 0)
return 0;
if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
E_LOG_INFO(dev, "The '%s' is disabled", name);
return 0;
} else if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
E_LOG_INFO(dev, "The '%s' is read-only", name);
return 0;
}
switch(qctrl.type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
{
struct v4l2_control ctl = {
.id = *id,
.value = atoi(value)
};
E_LOG_INFO(dev, "Configuring option %s (%08x) = %d", name, ctl.id, ctl.value);
E_XIOCTL(dev, fd, VIDIOC_S_CTRL, &ctl, "Can't set option %s", name);
}
return 1;
case V4L2_CTRL_TYPE_U8:
case V4L2_CTRL_TYPE_U16:
case V4L2_CTRL_TYPE_U32:
{
struct v4l2_ext_control ctl = {
.id = *id,
.size = qctrl.elem_size * qctrl.elems,
.ptr = data = calloc(qctrl.elems, qctrl.elem_size)
};
struct v4l2_ext_controls ctrls = {
.count = 1,
.ctrl_class = V4L2_CTRL_ID2CLASS(*id),
.controls = &ctl,
};
char *string = value;
char *token;
int tokens = 0;
for ( ; token = strsep(&string, ","); tokens++) {
if (tokens >= qctrl.elems)
continue;
switch(qctrl.type) {
case V4L2_CTRL_TYPE_U8:
ctl.p_u8[tokens] = atoi(token);
break;
case V4L2_CTRL_TYPE_U16:
ctl.p_u16[tokens] = atoi(token);
break;
case V4L2_CTRL_TYPE_U32:
ctl.p_u32[tokens] = atoi(token);
break;
}
}
E_LOG_INFO(dev, "Configuring option %s (%08x) = [%d tokens, expected %d]", name, ctl.id, tokens, qctrl.elems);
E_XIOCTL(dev, fd, VIDIOC_S_EXT_CTRLS, &ctrls, "Can't set option %s", name);
free(data);
}
return 1;
default:
E_LOG_INFO(dev, "The '%s' control type '%d' is not supported", name, qctrl.type);
return -1;
}
error:
free(data);
return -1;
}
static int v4l2_device_set_option_string_fd(device_t *dev, int fd, char *name, char *value)
{
int ret = 0;
uint32_t id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
while ((ret = v4l2_device_set_option_string_fd_iter_id(dev, fd, &id, name, value)) == 0 && id) {
id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
}
return ret;
}
int v4l2_device_set_option(device_t *dev, const char *key, const char *value)
{
char *keyp = strdup(key);
char *valuep = strdup(value);
int ret = 0;
device_option_normalize_name(keyp, keyp);
if (dev->v4l2->subdev_fd >= 0)
ret = v4l2_device_set_option_string_fd(dev, dev->v4l2->subdev_fd, keyp, valuep);
if (ret <= 0)
ret = v4l2_device_set_option_string_fd(dev, dev->v4l2->dev_fd, keyp, valuep);
free(keyp);
free(valuep);
if (ret == 0)
E_LOG_ERROR(dev, "The '%s=%s' was failed to find.", key, value);
else if (ret < 0)
E_LOG_ERROR(dev, "The '%s=%s' did fail to be set.", key, value);
return 0;
error:
return -1;
}