* [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
@ 2018-07-08 21:32 Pavel Machek
2018-07-19 20:53 ` Pavel Machek
2018-07-27 12:47 ` [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Mauro Carvalho Chehab
0 siblings, 2 replies; 9+ messages in thread
From: Pavel Machek @ 2018-07-08 21:32 UTC (permalink / raw)
To: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 12488 bytes --]
Add support for opening multiple devices in v4l2_open(), and for
mapping controls between devices.
This is necessary for complex devices, such as Nokia N900.
Signed-off-by: Pavel Machek <pavel@ucw.cz>
diff --git a/lib/include/libv4l2.h b/lib/include/libv4l2.h
index ea1870d..a0ec0a9 100644
--- a/lib/include/libv4l2.h
+++ b/lib/include/libv4l2.h
@@ -58,6 +58,10 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file;
invalid memory address will not lead to failure with errno being EFAULT,
as it would with a real ioctl, but will cause libv4l2 to break, and you
get to keep both pieces.
+
+ You can open complex pipelines by passing ".cv" file with pipeline
+ description to v4l2_open(). libv4l2 will open all the required
+ devices automatically in that case.
*/
LIBV4L_PUBLIC int v4l2_open(const char *file, int oflag, ...);
diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
index 1924c91..1ee697a 100644
--- a/lib/libv4l2/libv4l2-priv.h
+++ b/lib/libv4l2/libv4l2-priv.h
@@ -104,6 +104,7 @@ struct v4l2_dev_info {
void *plugin_library;
void *dev_ops_priv;
const struct libv4l_dev_ops *dev_ops;
+ struct v4l2_controls_map *map;
};
/* From v4l2-plugin.c */
@@ -130,4 +131,20 @@ static inline void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
extern const char *v4l2_ioctls[];
void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
+
+struct v4l2_control_map {
+ unsigned long control;
+ int fd;
+};
+
+struct v4l2_controls_map {
+ int main_fd;
+ int num_fds;
+ int num_controls;
+ struct v4l2_control_map map[];
+};
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags);
+LIBV4L_PUBLIC int v4l2_get_fd_for_control(int fd, unsigned long control);
+
#endif
diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
index 2db25d1..ac430f0 100644
--- a/lib/libv4l2/libv4l2.c
+++ b/lib/libv4l2/libv4l2.c
@@ -70,6 +70,8 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <dirent.h>
+
#include "libv4l2.h"
#include "libv4l2-priv.h"
#include "libv4l-plugin.h"
@@ -618,6 +620,8 @@ static void v4l2_update_fps(int index, struct v4l2_streamparm *parm)
devices[index].fps = 0;
}
+static int v4l2_open_complex(int fd, int v4l2_flags);
+
int v4l2_open(const char *file, int oflag, ...)
{
int fd;
@@ -641,6 +645,21 @@ int v4l2_open(const char *file, int oflag, ...)
if (fd == -1)
return fd;
+ int len = strlen(file);
+ char *end = ".cv";
+ int len2 = strlen(end);
+ if ((len > len2) && (!strcmp(file + len - len2, end))) {
+ /* .cv extension */
+ struct stat sb;
+
+ if (fstat(fd, &sb) == 0) {
+ if ((sb.st_mode & S_IFMT) == S_IFREG) {
+ return v4l2_open_complex(fd, 0);
+ }
+ }
+
+ }
+
if (v4l2_fd_open(fd, 0) == -1) {
int saved_err = errno;
@@ -787,6 +806,8 @@ no_capture:
if (index >= devices_used)
devices_used = index + 1;
+ devices[index].map = NULL;
+
/* Note we always tell v4lconvert to optimize src fmt selection for
our default fps, the only exception is the app explicitly selecting
a frame rate using the S_PARM ioctl after a S_FMT */
@@ -1056,12 +1077,47 @@ static int v4l2_s_fmt(int index, struct v4l2_format *dest_fmt)
return 0;
}
+int v4l2_get_fd_for_control(int fd, unsigned long control)
+{
+ int index = v4l2_get_index(fd);
+ struct v4l2_controls_map *map;
+ int lo = 0;
+ int hi;
+
+ if (index < 0)
+ return fd;
+
+ map = devices[index].map;
+ if (!map)
+ return fd;
+ hi = map->num_controls;
+
+ while (lo < hi) {
+ int i = (lo + hi) / 2;
+ if (map->map[i].control == control) {
+ return map->map[i].fd;
+ }
+ if (map->map[i].control > control) {
+ hi = i;
+ continue;
+ }
+ if (map->map[i].control < control) {
+ lo = i+1;
+ continue;
+ }
+ printf("Bad: impossible condition in binary search\n");
+ exit(1);
+ }
+ return fd;
+}
+
int v4l2_ioctl(int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
int result, index, saved_err;
- int is_capture_request = 0, stream_needs_locking = 0;
+ int is_capture_request = 0, stream_needs_locking = 0,
+ is_subdev_request = 0;
va_start(ap, request);
arg = va_arg(ap, void *);
@@ -1076,18 +1132,19 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
ioctl, causing it to get sign extended, depending upon this behavior */
request = (unsigned int)request;
if (devices[index].convert == NULL)
goto no_capture_request;
/* Is this a capture request and do we need to take the stream lock? */
switch (request) {
- case VIDIOC_QUERYCAP:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
+ is_subdev_request = 1;
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
is_capture_request = 1;
@@ -1151,10 +1209,15 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
}
if (!is_capture_request) {
+ int sub_fd;
no_capture_request:
+ sub_fd = fd;
+ if (is_subdev_request) {
+ sub_fd = v4l2_get_fd_for_control(index, ((struct v4l2_queryctrl *) arg)->id);
+ }
result = devices[index].dev_ops->ioctl(
devices[index].dev_ops_priv,
- fd, request, arg);
+ sub_fd, request, arg);
saved_err = errno;
v4l2_log_ioctl(request, arg, result);
errno = saved_err;
@@ -1782,3 +1845,194 @@ int v4l2_get_control(int fd, int cid)
(qctrl.maximum - qctrl.minimum) / 2) /
(qctrl.maximum - qctrl.minimum);
}
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags)
+{
+ int index;
+ int i;
+
+ for (i=0; i<map->num_controls; i++) {
+ if (map->map[i].fd <= 0) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Bad fd in map.\n");
+ return -1;
+ }
+ if (i>=1 && map->map[i].control <= map->map[i-1].control) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Controls not sorted.\n");
+ return -1;
+ }
+ }
+
+ i = v4l2_fd_open(map->main_fd, v4l2_flags);
+ index = v4l2_get_index(map->main_fd);
+ devices[index].map = map;
+ return i;
+}
+
+static void scan_devices(char **device_names, int *device_fds, int num)
+{
+ struct dirent **namelist;
+ int n;
+ char *class_v4l = "/sys/class/video4linux";
+
+ n = scandir(class_v4l, &namelist, NULL, alphasort);
+ if (n < 0) {
+ perror("scandir");
+ return;
+ }
+
+ while (n--) {
+ if (namelist[n]->d_name[0] != '.') {
+ char filename[1024], content[1024];
+ sprintf(filename, "%s/%s/name", class_v4l, namelist[n]->d_name);
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+ printf("Strange, can't open %s", filename);
+ } else {
+ fgets(content, 1024, f);
+ fclose(f);
+
+ int i;
+ for (i = num-1; i >=0; i--) {
+ if (!strcmp(content, device_names[i])) {
+ sprintf(filename, "/dev/%s", namelist[n]->d_name);
+ device_fds[i] = open(filename, O_RDWR);
+ if (device_fds[i] < 0) {
+ V4L2_LOG_ERR("Error opening %s: %m\n", filename);
+ }
+ }
+ }
+ }
+ }
+ free(namelist[n]);
+ }
+ free(namelist);
+
+}
+
+static int v4l2_open_complex(int fd, int v4l2_flags)
+{
+#define perr(s) V4L2_LOG_ERR("open_complex: " s "\n")
+#define BUF 256
+ FILE *f = fdopen(fd, "r");
+
+ int res = -1;
+ char buf[BUF];
+ int version, num_modes, num_devices, num_controls;
+ int dev, control;
+
+ if (!f) {
+ perr("open of .cv file failed: %m");
+ goto err;
+ }
+
+ if (fscanf(f, "Complex Video: %d\n", &version) != 1) {
+ perr(".cv file does not have required header");
+ goto close;
+ }
+
+ if (version != 0) {
+ perr(".cv file has unknown version");
+ goto close;
+ }
+
+ if (fscanf(f, "#modes: %d\n", &num_modes) != 1) {
+ perr("could not parse modes");
+ goto close;
+ }
+
+ if (num_modes != 1) {
+ perr("only single mode is supported for now");
+ goto close;
+ }
+
+ if (fscanf(f, "Mode: %s\n", buf) != 1) {
+ perr("could not parse mode name");
+ goto close;
+ }
+
+ if (fscanf(f, " #devices: %d\n", &num_devices) != 1) {
+ perr("could not parse number of devices");
+ goto close;
+ }
+#define MAX_DEVICES 16
+ char *device_names[MAX_DEVICES] = { NULL, };
+ int device_fds[MAX_DEVICES];
+ if (num_devices > MAX_DEVICES) {
+ perr("too many devices");
+ goto close;
+ }
+
+ for (dev = 0; dev < num_devices; dev++) {
+ int tmp;
+ if (fscanf(f, "%d: ", &tmp) != 1) {
+ perr("could not parse device");
+ goto free_devices;
+ }
+ if (tmp != dev) {
+ perr("bad device number");
+ goto free_devices;
+ }
+ fgets(buf, BUF, f);
+ device_names[dev] = strdup(buf);
+ device_fds[dev] = -1;
+ }
+
+ scan_devices(device_names, device_fds, num_devices);
+
+ for (dev = 0; dev < num_devices; dev++) {
+ if (device_fds[dev] == -1) {
+ perr("Could not open all required devices");
+ goto close_devices;
+ }
+ }
+
+ if (fscanf(f, " #controls: %d\n", &num_controls) != 1) {
+ perr("can not parse number of controls");
+ goto close_devices;
+ }
+
+ struct v4l2_controls_map *map = malloc(sizeof(struct v4l2_controls_map) +
+ num_controls*sizeof(struct v4l2_control_map));
+
+ map->num_controls = num_controls;
+ map->num_fds = num_devices;
+ map->main_fd = device_fds[0];
+
+ for (control = 0; control < num_controls; control++) {
+ unsigned long num;
+ int dev;
+ if (fscanf(f, "0x%lx: %d\n", &num, &dev) != 2) {
+ perr("could not parse control");
+ goto free_map;
+ }
+ if ((dev < 0) || (dev >= num_devices)) {
+ perr("device out of range");
+ goto free_map;
+ }
+ map->map[control].control = num;
+ map->map[control].fd = device_fds[dev];
+ }
+ if (fscanf(f, "%s", buf) > 0) {
+ perr("junk at end of file");
+ goto free_map;
+ }
+
+ res = v4l2_open_pipeline(map, v4l2_flags);
+
+ if (res < 0) {
+free_map:
+ free(map);
+close_devices:
+ for (dev = 0; dev < num_devices; dev++)
+ close(device_fds[dev]);
+ }
+free_devices:
+ for (dev = 0; dev < num_devices; dev++) {
+ free(device_names[dev]);
+ }
+close:
+ fclose(f);
+err:
+ return res;
+}
+
diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c
index 59f28b1..c1e6f93 100644
--- a/lib/libv4lconvert/control/libv4lcontrol.c
+++ b/lib/libv4lconvert/control/libv4lcontrol.c
@@ -863,6 +863,7 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
struct v4l2_queryctrl *ctrl = arg;
int retval;
uint32_t orig_id = ctrl->id;
+ int fd;
/* if we have an exact match return it */
for (i = 0; i < V4LCONTROL_COUNT; i++)
@@ -872,8 +873,9 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
/* find out what the kernel driver would respond. */
- retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ retval = data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_QUERYCTRL, arg);
if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) &&
@@ -903,6 +905,7 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -911,7 +914,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_G_CTRL, arg);
}
@@ -994,6 +998,7 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -1008,7 +1013,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_S_CTRL, arg);
}
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-07-08 21:32 [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Pavel Machek
@ 2018-07-19 20:53 ` Pavel Machek
2018-07-23 18:36 ` Mauro Carvalho Chehab
2018-07-27 12:47 ` [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Mauro Carvalho Chehab
1 sibling, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-07-19 20:53 UTC (permalink / raw)
To: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 13537 bytes --]
On Sun 2018-07-08 23:32:58, Pavel Machek wrote:
>
> Add support for opening multiple devices in v4l2_open(), and for
> mapping controls between devices.
>
> This is necessary for complex devices, such as Nokia N900.
>
> Signed-off-by: Pavel Machek <pavel@ucw.cz>
Ping?
There's a lot of work to do on libv4l2... timely patch handling would
be nice.
> diff --git a/lib/include/libv4l2.h b/lib/include/libv4l2.h
> index ea1870d..a0ec0a9 100644
> --- a/lib/include/libv4l2.h
> +++ b/lib/include/libv4l2.h
> @@ -58,6 +58,10 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file;
> invalid memory address will not lead to failure with errno being EFAULT,
> as it would with a real ioctl, but will cause libv4l2 to break, and you
> get to keep both pieces.
> +
> + You can open complex pipelines by passing ".cv" file with pipeline
> + description to v4l2_open(). libv4l2 will open all the required
> + devices automatically in that case.
> */
>
> LIBV4L_PUBLIC int v4l2_open(const char *file, int oflag, ...);
> diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
> index 1924c91..1ee697a 100644
> --- a/lib/libv4l2/libv4l2-priv.h
> +++ b/lib/libv4l2/libv4l2-priv.h
> @@ -104,6 +104,7 @@ struct v4l2_dev_info {
> void *plugin_library;
> void *dev_ops_priv;
> const struct libv4l_dev_ops *dev_ops;
> + struct v4l2_controls_map *map;
> };
>
> /* From v4l2-plugin.c */
> @@ -130,4 +131,20 @@ static inline void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
> extern const char *v4l2_ioctls[];
> void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
>
> +
> +struct v4l2_control_map {
> + unsigned long control;
> + int fd;
> +};
> +
> +struct v4l2_controls_map {
> + int main_fd;
> + int num_fds;
> + int num_controls;
> + struct v4l2_control_map map[];
> +};
> +
> +int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags);
> +LIBV4L_PUBLIC int v4l2_get_fd_for_control(int fd, unsigned long control);
> +
> #endif
> diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
> index 2db25d1..ac430f0 100644
> --- a/lib/libv4l2/libv4l2.c
> +++ b/lib/libv4l2/libv4l2.c
> @@ -70,6 +70,8 @@
> #include <sys/types.h>
> #include <sys/mman.h>
> #include <sys/stat.h>
> +#include <dirent.h>
> +
> #include "libv4l2.h"
> #include "libv4l2-priv.h"
> #include "libv4l-plugin.h"
> @@ -618,6 +620,8 @@ static void v4l2_update_fps(int index, struct v4l2_streamparm *parm)
> devices[index].fps = 0;
> }
>
> +static int v4l2_open_complex(int fd, int v4l2_flags);
> +
> int v4l2_open(const char *file, int oflag, ...)
> {
> int fd;
> @@ -641,6 +645,21 @@ int v4l2_open(const char *file, int oflag, ...)
> if (fd == -1)
> return fd;
>
> + int len = strlen(file);
> + char *end = ".cv";
> + int len2 = strlen(end);
> + if ((len > len2) && (!strcmp(file + len - len2, end))) {
> + /* .cv extension */
> + struct stat sb;
> +
> + if (fstat(fd, &sb) == 0) {
> + if ((sb.st_mode & S_IFMT) == S_IFREG) {
> + return v4l2_open_complex(fd, 0);
> + }
> + }
> +
> + }
> +
> if (v4l2_fd_open(fd, 0) == -1) {
> int saved_err = errno;
>
> @@ -787,6 +806,8 @@ no_capture:
> if (index >= devices_used)
> devices_used = index + 1;
>
> + devices[index].map = NULL;
> +
> /* Note we always tell v4lconvert to optimize src fmt selection for
> our default fps, the only exception is the app explicitly selecting
> a frame rate using the S_PARM ioctl after a S_FMT */
> @@ -1056,12 +1077,47 @@ static int v4l2_s_fmt(int index, struct v4l2_format *dest_fmt)
> return 0;
> }
>
> +int v4l2_get_fd_for_control(int fd, unsigned long control)
> +{
> + int index = v4l2_get_index(fd);
> + struct v4l2_controls_map *map;
> + int lo = 0;
> + int hi;
> +
> + if (index < 0)
> + return fd;
> +
> + map = devices[index].map;
> + if (!map)
> + return fd;
> + hi = map->num_controls;
> +
> + while (lo < hi) {
> + int i = (lo + hi) / 2;
> + if (map->map[i].control == control) {
> + return map->map[i].fd;
> + }
> + if (map->map[i].control > control) {
> + hi = i;
> + continue;
> + }
> + if (map->map[i].control < control) {
> + lo = i+1;
> + continue;
> + }
> + printf("Bad: impossible condition in binary search\n");
> + exit(1);
> + }
> + return fd;
> +}
> +
> int v4l2_ioctl(int fd, unsigned long int request, ...)
> {
> void *arg;
> va_list ap;
> int result, index, saved_err;
> - int is_capture_request = 0, stream_needs_locking = 0;
> + int is_capture_request = 0, stream_needs_locking = 0,
> + is_subdev_request = 0;
>
> va_start(ap, request);
> arg = va_arg(ap, void *);
> @@ -1076,18 +1132,19 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
> ioctl, causing it to get sign extended, depending upon this behavior */
> request = (unsigned int)request;
>
> if (devices[index].convert == NULL)
> goto no_capture_request;
>
> /* Is this a capture request and do we need to take the stream lock? */
> switch (request) {
> - case VIDIOC_QUERYCAP:
> case VIDIOC_QUERYCTRL:
> case VIDIOC_G_CTRL:
> case VIDIOC_S_CTRL:
> case VIDIOC_G_EXT_CTRLS:
> - case VIDIOC_TRY_EXT_CTRLS:
> case VIDIOC_S_EXT_CTRLS:
> + is_subdev_request = 1;
> + case VIDIOC_QUERYCAP:
> + case VIDIOC_TRY_EXT_CTRLS:
> case VIDIOC_ENUM_FRAMESIZES:
> case VIDIOC_ENUM_FRAMEINTERVALS:
> is_capture_request = 1;
> @@ -1151,10 +1209,15 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
> }
>
> if (!is_capture_request) {
> + int sub_fd;
> no_capture_request:
> + sub_fd = fd;
> + if (is_subdev_request) {
> + sub_fd = v4l2_get_fd_for_control(index, ((struct v4l2_queryctrl *) arg)->id);
> + }
> result = devices[index].dev_ops->ioctl(
> devices[index].dev_ops_priv,
> - fd, request, arg);
> + sub_fd, request, arg);
> saved_err = errno;
> v4l2_log_ioctl(request, arg, result);
> errno = saved_err;
> @@ -1782,3 +1845,194 @@ int v4l2_get_control(int fd, int cid)
> (qctrl.maximum - qctrl.minimum) / 2) /
> (qctrl.maximum - qctrl.minimum);
> }
> +
> +int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags)
> +{
> + int index;
> + int i;
> +
> + for (i=0; i<map->num_controls; i++) {
> + if (map->map[i].fd <= 0) {
> + V4L2_LOG_ERR("v4l2_open_pipeline: Bad fd in map.\n");
> + return -1;
> + }
> + if (i>=1 && map->map[i].control <= map->map[i-1].control) {
> + V4L2_LOG_ERR("v4l2_open_pipeline: Controls not sorted.\n");
> + return -1;
> + }
> + }
> +
> + i = v4l2_fd_open(map->main_fd, v4l2_flags);
> + index = v4l2_get_index(map->main_fd);
> + devices[index].map = map;
> + return i;
> +}
> +
> +static void scan_devices(char **device_names, int *device_fds, int num)
> +{
> + struct dirent **namelist;
> + int n;
> + char *class_v4l = "/sys/class/video4linux";
> +
> + n = scandir(class_v4l, &namelist, NULL, alphasort);
> + if (n < 0) {
> + perror("scandir");
> + return;
> + }
> +
> + while (n--) {
> + if (namelist[n]->d_name[0] != '.') {
> + char filename[1024], content[1024];
> + sprintf(filename, "%s/%s/name", class_v4l, namelist[n]->d_name);
> + FILE *f = fopen(filename, "r");
> + if (!f) {
> + printf("Strange, can't open %s", filename);
> + } else {
> + fgets(content, 1024, f);
> + fclose(f);
> +
> + int i;
> + for (i = num-1; i >=0; i--) {
> + if (!strcmp(content, device_names[i])) {
> + sprintf(filename, "/dev/%s", namelist[n]->d_name);
> + device_fds[i] = open(filename, O_RDWR);
> + if (device_fds[i] < 0) {
> + V4L2_LOG_ERR("Error opening %s: %m\n", filename);
> + }
> + }
> + }
> + }
> + }
> + free(namelist[n]);
> + }
> + free(namelist);
> +
> +}
> +
> +static int v4l2_open_complex(int fd, int v4l2_flags)
> +{
> +#define perr(s) V4L2_LOG_ERR("open_complex: " s "\n")
> +#define BUF 256
> + FILE *f = fdopen(fd, "r");
> +
> + int res = -1;
> + char buf[BUF];
> + int version, num_modes, num_devices, num_controls;
> + int dev, control;
> +
> + if (!f) {
> + perr("open of .cv file failed: %m");
> + goto err;
> + }
> +
> + if (fscanf(f, "Complex Video: %d\n", &version) != 1) {
> + perr(".cv file does not have required header");
> + goto close;
> + }
> +
> + if (version != 0) {
> + perr(".cv file has unknown version");
> + goto close;
> + }
> +
> + if (fscanf(f, "#modes: %d\n", &num_modes) != 1) {
> + perr("could not parse modes");
> + goto close;
> + }
> +
> + if (num_modes != 1) {
> + perr("only single mode is supported for now");
> + goto close;
> + }
> +
> + if (fscanf(f, "Mode: %s\n", buf) != 1) {
> + perr("could not parse mode name");
> + goto close;
> + }
> +
> + if (fscanf(f, " #devices: %d\n", &num_devices) != 1) {
> + perr("could not parse number of devices");
> + goto close;
> + }
> +#define MAX_DEVICES 16
> + char *device_names[MAX_DEVICES] = { NULL, };
> + int device_fds[MAX_DEVICES];
> + if (num_devices > MAX_DEVICES) {
> + perr("too many devices");
> + goto close;
> + }
> +
> + for (dev = 0; dev < num_devices; dev++) {
> + int tmp;
> + if (fscanf(f, "%d: ", &tmp) != 1) {
> + perr("could not parse device");
> + goto free_devices;
> + }
> + if (tmp != dev) {
> + perr("bad device number");
> + goto free_devices;
> + }
> + fgets(buf, BUF, f);
> + device_names[dev] = strdup(buf);
> + device_fds[dev] = -1;
> + }
> +
> + scan_devices(device_names, device_fds, num_devices);
> +
> + for (dev = 0; dev < num_devices; dev++) {
> + if (device_fds[dev] == -1) {
> + perr("Could not open all required devices");
> + goto close_devices;
> + }
> + }
> +
> + if (fscanf(f, " #controls: %d\n", &num_controls) != 1) {
> + perr("can not parse number of controls");
> + goto close_devices;
> + }
> +
> + struct v4l2_controls_map *map = malloc(sizeof(struct v4l2_controls_map) +
> + num_controls*sizeof(struct v4l2_control_map));
> +
> + map->num_controls = num_controls;
> + map->num_fds = num_devices;
> + map->main_fd = device_fds[0];
> +
> + for (control = 0; control < num_controls; control++) {
> + unsigned long num;
> + int dev;
> + if (fscanf(f, "0x%lx: %d\n", &num, &dev) != 2) {
> + perr("could not parse control");
> + goto free_map;
> + }
> + if ((dev < 0) || (dev >= num_devices)) {
> + perr("device out of range");
> + goto free_map;
> + }
> + map->map[control].control = num;
> + map->map[control].fd = device_fds[dev];
> + }
> + if (fscanf(f, "%s", buf) > 0) {
> + perr("junk at end of file");
> + goto free_map;
> + }
> +
> + res = v4l2_open_pipeline(map, v4l2_flags);
> +
> + if (res < 0) {
> +free_map:
> + free(map);
> +close_devices:
> + for (dev = 0; dev < num_devices; dev++)
> + close(device_fds[dev]);
> + }
> +free_devices:
> + for (dev = 0; dev < num_devices; dev++) {
> + free(device_names[dev]);
> + }
> +close:
> + fclose(f);
> +err:
> + return res;
> +}
> +
> diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c
> index 59f28b1..c1e6f93 100644
> --- a/lib/libv4lconvert/control/libv4lcontrol.c
> +++ b/lib/libv4lconvert/control/libv4lcontrol.c
> @@ -863,6 +863,7 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
> struct v4l2_queryctrl *ctrl = arg;
> int retval;
> uint32_t orig_id = ctrl->id;
> + int fd;
>
> /* if we have an exact match return it */
> for (i = 0; i < V4LCONTROL_COUNT; i++)
> @@ -872,8 +873,9 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
> return 0;
> }
>
> + fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
> /* find out what the kernel driver would respond. */
> - retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
> + retval = data->dev_ops->ioctl(data->dev_ops_priv, fd,
> VIDIOC_QUERYCTRL, arg);
>
> if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) &&
> @@ -903,6 +905,7 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
> {
> int i;
> struct v4l2_control *ctrl = arg;
> + int fd;
>
> for (i = 0; i < V4LCONTROL_COUNT; i++)
> if ((data->controls & (1 << i)) &&
> @@ -911,7 +914,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
> return 0;
> }
>
> - return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
> + fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
> + return data->dev_ops->ioctl(data->dev_ops_priv, fd,
> VIDIOC_G_CTRL, arg);
> }
>
> @@ -994,6 +998,7 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
> {
> int i;
> struct v4l2_control *ctrl = arg;
> + int fd;
>
> for (i = 0; i < V4LCONTROL_COUNT; i++)
> if ((data->controls & (1 << i)) &&
> @@ -1008,7 +1013,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
> return 0;
> }
>
> - return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
> + fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
> + return data->dev_ops->ioctl(data->dev_ops_priv, fd,
> VIDIOC_S_CTRL, arg);
> }
>
>
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-07-19 20:53 ` Pavel Machek
@ 2018-07-23 18:36 ` Mauro Carvalho Chehab
2018-07-28 19:36 ` Pavel Machek
2018-07-28 21:11 ` new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline) Pavel Machek
0 siblings, 2 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-07-23 18:36 UTC (permalink / raw)
To: Pavel Machek
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
Hi Pavel,
Em Thu, 19 Jul 2018 22:53:44 +0200
Pavel Machek <pavel@ucw.cz> escreveu:
> On Sun 2018-07-08 23:32:58, Pavel Machek wrote:
> >
> > Add support for opening multiple devices in v4l2_open(), and for
> > mapping controls between devices.
> >
> > This is necessary for complex devices, such as Nokia N900.
> >
> > Signed-off-by: Pavel Machek <pavel@ucw.cz>
>
> Ping?
>
> There's a lot of work to do on libv4l2... timely patch handling would
> be nice.
As we're be start working at the new library in order to support
complex cameras, and I don't want to prevent you keeping doing your
work, IMHO the best way to keep doing it would be to create two
libv4l2 forks:
- one to be used by you - meant to support N900 camera;
- another one to be used by Google/Intel people that will
be working at the Complex camera.
This way, we can proceed with the development without causing
instability to v4l-utils. Once we have the projects done at the
separate repositories, we can work on merging them back upstream.
So, please send me, in priv, a .ssh key for me to add you an
account at linuxtv.org. I'll send you instructions about how to
use the new account.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-07-23 18:36 ` Mauro Carvalho Chehab
@ 2018-07-28 19:36 ` Pavel Machek
2018-07-28 21:11 ` new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline) Pavel Machek
1 sibling, 0 replies; 9+ messages in thread
From: Pavel Machek @ 2018-07-28 19:36 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 1559 bytes --]
Hi!
> > > Add support for opening multiple devices in v4l2_open(), and for
> > > mapping controls between devices.
> > >
> > > This is necessary for complex devices, such as Nokia N900.
> > >
> > > Signed-off-by: Pavel Machek <pavel@ucw.cz>
> >
> > Ping?
> >
> > There's a lot of work to do on libv4l2... timely patch handling would
> > be nice.
>
> As we're be start working at the new library in order to support
> complex cameras, and I don't want to prevent you keeping doing your
> work, IMHO the best way to keep doing it would be to create two
> libv4l2 forks:
>
> - one to be used by you - meant to support N900 camera;
> - another one to be used by Google/Intel people that will
> be working at the Complex camera.
Actually, I guess it would be better to share branches. N900 really
has Complex camera :-). Yes, there are some details that are different
(IPU3 will need to pass data between sensor and processing pipeline),
but it
1) will probably need to "propagate controls"
2) will need autofocus
3) would benefit from same autogain improvements
4) [probably most difficult] figure out how to support more than
8-bits depth.
> So, please send me, in priv, a .ssh key for me to add you an
> account at linuxtv.org. I'll send you instructions about how to
> use the new account.
Done, you should have key in your inbox.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline)
2018-07-23 18:36 ` Mauro Carvalho Chehab
2018-07-28 19:36 ` Pavel Machek
@ 2018-07-28 21:11 ` Pavel Machek
2018-07-30 9:31 ` Mauro Carvalho Chehab
1 sibling, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-07-28 21:11 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 1065 bytes --]
Hi!
> > > Add support for opening multiple devices in v4l2_open(), and for
> > > mapping controls between devices.
> > >
> > > This is necessary for complex devices, such as Nokia N900.
> > >
> > > Signed-off-by: Pavel Machek <pavel@ucw.cz>
> >
> > Ping?
> >
> > There's a lot of work to do on libv4l2... timely patch handling would
> > be nice.
>
> As we're be start working at the new library in order to support
> complex cameras, and I don't want to prevent you keeping doing your
> work, IMHO the best way to keep doing it would be to create two
> libv4l2 forks:
BTW.. new library. Was there decision what langauge to use? I know C
is obvious choice, but while working on libv4l2, I wished it would be
Rust...
Rewriting same routine over and over, with slightly different types
was not too much fun, and it looked like textbook example for
generics...
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline)
2018-07-28 21:11 ` new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline) Pavel Machek
@ 2018-07-30 9:31 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-07-30 9:31 UTC (permalink / raw)
To: Pavel Machek
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
Em Sat, 28 Jul 2018 23:11:10 +0200
Pavel Machek <pavel@ucw.cz> escreveu:
> Hi!
>
> > > > Add support for opening multiple devices in v4l2_open(), and for
> > > > mapping controls between devices.
> > > >
> > > > This is necessary for complex devices, such as Nokia N900.
> > > >
> > > > Signed-off-by: Pavel Machek <pavel@ucw.cz>
> > >
> > > Ping?
> > >
> > > There's a lot of work to do on libv4l2... timely patch handling would
> > > be nice.
> >
> > As we're be start working at the new library in order to support
> > complex cameras, and I don't want to prevent you keeping doing your
> > work, IMHO the best way to keep doing it would be to create two
> > libv4l2 forks:
>
> BTW.. new library. Was there decision what langauge to use? I know C
> is obvious choice, but while working on libv4l2, I wished it would be
> Rust...
>
> Rewriting same routine over and over, with slightly different types
> was not too much fun, and it looked like textbook example for
> generics...
Whatever language it uses, the library should provide a standard C API
interface and avoid using libraries that may not be available on
the systems supported by the v4l-utils package, as other packages
and a libv4l-compatible interface should be linked using it.
It should also be something that the existing v4l-utils developers are
familiar with. Right now, we have only C and C++ code inside v4l-utils.
So, I'd say that the language should be either C (the obvious choice)
or C++.
It should also be licensed using the same terms as v4l-utils libraries,
e. g. LGPL 2.1+.
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-07-08 21:32 [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Pavel Machek
2018-07-19 20:53 ` Pavel Machek
@ 2018-07-27 12:47 ` Mauro Carvalho Chehab
2018-07-28 21:02 ` Pavel Machek
1 sibling, 1 reply; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-07-27 12:47 UTC (permalink / raw)
To: Pavel Machek
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
Em Sun, 8 Jul 2018 23:32:58 +0200
Pavel Machek <pavel@ucw.cz> escreveu:
> Add support for opening multiple devices in v4l2_open(), and for
> mapping controls between devices.
>
> This is necessary for complex devices, such as Nokia N900.
Hi Pavel,
I tried to apply it here, but it seems that there are something
wrong with the patch:
$ quilt push -f --merge
Applying patch patches/lmml_50901_libv4l_make_libv4l2_usable_on_devices_with_complex_pipeline.patch
patching file lib/include/libv4l2.h
patching file lib/libv4l2/libv4l2-priv.h
patching file lib/libv4l2/libv4l2.c
Hunk #6 NOT MERGED at 1830-1857.
misordered hunks! output would be garbled
Hunk #7 FAILED at 1224.
Hunk #8 NOT MERGED at 1858-2057.
1 out of 8 hunks FAILED -- saving rejects to file lib/libv4l2/libv4l2.c.rej
patching file lib/libv4lconvert/control/libv4lcontrol.c
Applied patch patches/lmml_50901_libv4l_make_libv4l2_usable_on_devices_with_complex_pipeline.patch (forced; needs refresh)
I even tried to reset the tree to a patchset earlier than July, 8.
Same issue.
I could manually try to fix it, but that misordered hunks
warning is weird. Makes me wonder if the patch is not mangled.
Could you please re-send it on the top of upstream? Better to use
git send-email, as it won't mangle your patch.
Alternatively, please send me a ssh public key in private, and I'll
give you access to the repository where you can store those patches.
Thanks!
Mauro
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-07-27 12:47 ` [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Mauro Carvalho Chehab
@ 2018-07-28 21:02 ` Pavel Machek
0 siblings, 0 replies; 9+ messages in thread
From: Pavel Machek @ 2018-07-28 21:02 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: pali.rohar, sre, kernel list, linux-arm-kernel, linux-omap, tony,
khilman, aaro.koskinen, ivo.g.dimitrov.75, patrikbachan, serge,
abcloriens, clayton, martijn, sakari.ailus, Filip Matijević,
mchehab, sakari.ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 354 bytes --]
Hi!
> Alternatively, please send me a ssh public key in private, and I'll
> give you access to the repository where you can store those patches.
Lets do it that way. Sorry for the confusion.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
@ 2018-03-19 12:15 Hans Verkuil
2018-03-19 13:26 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 9+ messages in thread
From: Hans Verkuil @ 2018-03-19 12:15 UTC (permalink / raw)
To: Pavel Machek
Cc: Mauro Carvalho Chehab, Ivaylo Dimitrov, pali.rohar, sre,
Sakari Ailus, Sakari Ailus, linux-media, hans.verkuil
On 03/19/2018 01:00 PM, Pavel Machek wrote:
> Hi!
>
>>> Pavel,
>>>
>>> I appreciate your efforts of adding support for mc-based devices to
>>> libv4l.
>
> Thanks.
>
>>> I guess the main poin that Hans is pointing is that we should take
>>> extra care in order to avoid adding new symbols to libv4l ABI/API
>>> without being sure that they'll be needed in long term, as removing
>>> or changing the API is painful for app developers, and keeping it
>>> ABI compatible with apps compiled against previous versions of the
>>> library is very painful for us.
>>
>> Indeed. Sorry if I wasn't clear on that.
>
> Aha, ok, no, I did not get that.
>
>>> The hole idea is that generic applications shouldn't notice
>>> if the device is using a mc-based device or not.
>>
>> What is needed IMHO is an RFC that explains how you want to solve this
>> problem, what the parser would look like, how this would configure a
>> complex pipeline for use with libv4l-using applications, etc.
>>
>> I.e., a full design.
>>
>> And once everyone agrees that that design is solid, then it needs to be
>> implemented.
>>
>> I really want to work with you on this, but I am not looking for partial
>> solutions.
>
> Well, expecting design to be done for opensource development is a bit
> unusual :-).
Why? We have done that quite often in the past. Media is complex and you need
to decide on a design up front.
> I really see two separate tasks
>
> 1) support for configuring pipeline. I believe this is best done out
> of libv4l2. It outputs description file, format below. Currently I
> have implemented this is in Python. File format is below.
You do need this, but why outside of libv4l2? I'm not saying I disagree
with you, but you need to give reasons for that.
> 2) support for running libv4l2 on mc-based devices. I'd like to do
> that.
>
> Description file would look like. (# comments would not be not part of file).
>
> V4L2MEDIADESC
> 3 # number of files to open
> /dev/video2
> /dev/video6
> /dev/video3
This won't work. The video nodes numbers (or even names) can change.
Instead these should be entity names from the media controller.
> 3 # number of controls to map. Controls not mentioned here go to
> # device 0 automatically. Sorted by control id.
> # Device 0
> 00980913 1
> 009a0003 1
> 009a000a 2
You really don't need to specify the files to open. All you need is to
specify the entity ID and the list of controls that you need.
Then libv4l can just figure out which device node(s) to open for that.
>
> We can parse that easily without requiring external libraries. Sorted
> data allow us to do binary search.
But none of this addresses setting up the initial video pipeline or
changing formats. We probably want to support that as well.
For that matter: what is it exactly that we want to support? I.e. where do
we draw the line?
A good test platform for this (outside the N900) is the i.MX6 platform.
Regards,
Hans
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-03-19 12:15 [RFC, " Hans Verkuil
@ 2018-03-19 13:26 ` Mauro Carvalho Chehab
2018-05-15 20:01 ` Pavel Machek
0 siblings, 1 reply; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-03-19 13:26 UTC (permalink / raw)
To: Pavel Machek
Cc: Hans Verkuil, pali.rohar, sre, Sakari Ailus, linux-media,
hans.verkuil
Em Mon, 19 Mar 2018 13:15:22 +0100
Hans Verkuil <hverkuil@xs4all.nl> escreveu:
> On 03/19/2018 01:00 PM, Pavel Machek wrote:
> > Hi!
> >
> >>> Pavel,
> >>>
> >>> I appreciate your efforts of adding support for mc-based devices to
> >>> libv4l.
> >
> > Thanks.
> >
> >>> I guess the main poin that Hans is pointing is that we should take
> >>> extra care in order to avoid adding new symbols to libv4l ABI/API
> >>> without being sure that they'll be needed in long term, as removing
> >>> or changing the API is painful for app developers, and keeping it
> >>> ABI compatible with apps compiled against previous versions of the
> >>> library is very painful for us.
> >>
> >> Indeed. Sorry if I wasn't clear on that.
> >
> > Aha, ok, no, I did not get that.
> >
> >>> The hole idea is that generic applications shouldn't notice
> >>> if the device is using a mc-based device or not.
> >>
> >> What is needed IMHO is an RFC that explains how you want to solve this
> >> problem, what the parser would look like, how this would configure a
> >> complex pipeline for use with libv4l-using applications, etc.
> >>
> >> I.e., a full design.
> >>
> >> And once everyone agrees that that design is solid, then it needs to be
> >> implemented.
> >>
> >> I really want to work with you on this, but I am not looking for partial
> >> solutions.
> >
> > Well, expecting design to be done for opensource development is a bit
> > unusual :-).
>
> Why? We have done that quite often in the past. Media is complex and you need
> to decide on a design up front.
>
> > I really see two separate tasks
> >
> > 1) support for configuring pipeline. I believe this is best done out
> > of libv4l2. It outputs description file, format below. Currently I
> > have implemented this is in Python. File format is below.
>
> You do need this, but why outside of libv4l2? I'm not saying I disagree
> with you, but you need to give reasons for that.
>
> > 2) support for running libv4l2 on mc-based devices. I'd like to do
> > that.
> >
> > Description file would look like. (# comments would not be not part of file).
> >
> > V4L2MEDIADESC
> > 3 # number of files to open
> > /dev/video2
> > /dev/video6
> > /dev/video3
"Easy" file formats usually means maintenance troubles as new
things are needed, and makes worse for users to write it.
You should take a look at lib/libdvbv5/dvb-file.c, mainly at
fill_entry() and dvb_read_file().
It has a parser there for things like:
[foo]
bar = value
and it doesn't require external libraries. I considered writing it
as a small helper function, but it turns that parsing this format
is so simple that can easily be added anywhere else.
The advantage of such format is that it should be simple enough
to add more stuff there, and intuitive enough for end users.
> This won't work. The video nodes numbers (or even names) can change.
Yes. That all depends on how udev is set on a given system.
Btw, the logic should likely use libudev in order to get the
devname.
> Instead these should be entity names from the media controller.
Agreed that it should use MC. Yet, IMHO, the best would be to use
the entity function instead, as entity names might eventually
change on newer versions of the Kernel.
So, IMHO, entities should be described as:
[entity entity1]
name = foo
function = bar
(again, user may specify just name, just function or both)
> > 3 # number of controls to map. Controls not mentioned here go to
> > # device 0 automatically. Sorted by control id.
> > # Device 0
> > 00980913 1
> > 009a0003 1
> > 009a000a 2
I would, instead, encode it as:
[control white balance]
control_id = 0x00980913
entity = foo_entity_name
[control exposure]
control_id = V4L2_CID_EXPOSURE_ABSOLUTE
entity = bar_entity_name
...
Allowing both hexadecimal values and control macro names (can easily parsed
from the header file, as we already do for other things with "make sync").
Makes a way easier for people to understand what that means and to write
such files.
> You really don't need to specify the files to open. All you need is to
> specify the entity ID and the list of controls that you need.
>
> Then libv4l can just figure out which device node(s) to open for that.
The only file it could make sense to specify is the media
controller device or the name of the media controller device,
as more than one /dev/media? devnode could be present on a given
system.
I would actually support both, e. g.:
[media controller]
name = foo
devname = bar
Only "name" or "devname" would be required:
- If "name" is blank, it would just use "devname";
- If "devname" is blank, it would open all /dev/media?
devices until it matches "name";
- If both are given, it would open "devname" and check
if "name" matches the media controller name, failing
otherwise.
> >
> > We can parse that easily without requiring external libraries. Sorted
> > data allow us to do binary search.
>
> But none of this addresses setting up the initial video pipeline or
> changing formats. We probably want to support that as well.
It should probably be easy to add a generic pipeline descriptor
with a format like:
[pipeline pipe1]
link0 = SGRBG10 640x480: entity1:0 -> entity2:0[1]
link1 = SGRBG10 640x480: entity2:2-> entity3:0[1]
link2 = UYVY 640x480: entity3:1-> entity4:0[1]
link3 = UYVY 640x480: entity4:1-> entity5:0[1]
sink0 = UYVY 320x200: entity5:0[1]
sink1 = UYVY 640x480: entity3:0[1]
>
> For that matter: what is it exactly that we want to support? I.e. where do
> we draw the line?
>
> A good test platform for this (outside the N900) is the i.MX6 platform.
>
> Regards,
>
> Hans
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-03-19 13:26 ` Mauro Carvalho Chehab
@ 2018-05-15 20:01 ` Pavel Machek
2018-05-15 22:03 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-05-15 20:01 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Hans Verkuil, pali.rohar, sre, Sakari Ailus, linux-media,
hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 1118 bytes --]
Hi!
> So, IMHO, entities should be described as:
>
> [entity entity1]
> name = foo
> function = bar
I don't really think windows-style config file is suitable here, as we
have more than two "nested blocks".
What about something like this? Note that I'd only implement the
controls mapping for now... but it should be extensible later to setup
mappings for the application.
Best regards,
Pavel
#modes: 2
Driver name: OMAP 3 resizer
Mode: 3000x1800
#devices: 2
0: et8ek8 sensor
1: OMAP3 resizer
#controls: 2
0x4321a034: 1
0x4113aab0: 1
#links: 1
link:
entity1: et8ek8 sensor:1
entity2: OMAP3 resizer:0
resolution1: 1024x768
resolution2: 1024x768
Mode: 1024x768
#devices: 2
0: et8ek8 sensor
1: OMAP3 resizer
#controls: 2
0x4321a034: 1
0x4113aab0: 1
#links: 1
link:
entity1: et8ek8 sensor:1
entity2: OMAP3 resizer:0
resolution1: 1024x768
resolution2: 1024x768
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-05-15 20:01 ` Pavel Machek
@ 2018-05-15 22:03 ` Mauro Carvalho Chehab
2018-06-02 21:01 ` Pavel Machek
0 siblings, 1 reply; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-05-15 22:03 UTC (permalink / raw)
To: Pavel Machek
Cc: Mauro Carvalho Chehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, linux-media, hans.verkuil
Em Tue, 15 May 2018 22:01:17 +0200
Pavel Machek <pavel@ucw.cz> escreveu:
> Hi!
>
> > So, IMHO, entities should be described as:
> >
> > [entity entity1]
> > name = foo
> > function = bar
>
> I don't really think windows-style config file is suitable here, as we
> have more than two "nested blocks".
>
> What about something like this? Note that I'd only implement the
> controls mapping for now... but it should be extensible later to setup
> mappings for the application.
>
> Best regards,
> Pavel
>
>
> #modes: 2
> Driver name: OMAP 3 resizer
It probably makes sense to place the driver name before #modes.
From what I understood, the "#foo: <number>" is a tag that makes the
parser to expect for <number> of "foo".
I would also add a first line at the beginning describing the
version of the format, just in case we add more stuff that
would require to change something at the format.
Except for that, it seems ok.
> Mode: 3000x1800
> #devices: 2
> 0: et8ek8 sensor
> 1: OMAP3 resizer
> #controls: 2
> 0x4321a034: 1
> 0x4113aab0: 1
> #links: 1
> link:
> entity1: et8ek8 sensor:1
> entity2: OMAP3 resizer:0
> resolution1: 1024x768
> resolution2: 1024x768
> Mode: 1024x768
> #devices: 2
> 0: et8ek8 sensor
> 1: OMAP3 resizer
> #controls: 2
> 0x4321a034: 1
> 0x4113aab0: 1
> #links: 1
> link:
> entity1: et8ek8 sensor:1
> entity2: OMAP3 resizer:0
> resolution1: 1024x768
> resolution2: 1024x768
>
>
>
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-05-15 22:03 ` Mauro Carvalho Chehab
@ 2018-06-02 21:01 ` Pavel Machek
2018-06-06 6:18 ` Tomasz Figa
0 siblings, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-06-02 21:01 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Mauro Carvalho Chehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, linux-media, hans.verkuil
[-- Attachment #1: Type: text/plain, Size: 11769 bytes --]
Hi!
Ok, can I get any comments on this one?
v4l2_open_complex("/file/with/descriptor", 0) can be used to open
whole pipeline at once, and work if it as if it was one device.
Thanks,
Pavel
diff --git a/lib/include/libv4l2.h b/lib/include/libv4l2.h
index ea1870d..f170c3d 100644
--- a/lib/include/libv4l2.h
+++ b/lib/include/libv4l2.h
@@ -109,6 +109,12 @@ LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid);
(note the fd is left open in this case). */
LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags);
+/* v4l2_open_complex: open complex pipeline. Name of pipeline descriptor
+ is passed to v4l2_open_complex(). It opens devices described there and
+ handles mapping controls between devices.
+ */
+LIBV4L_PUBLIC int v4l2_open_complex(char *name, int v4l2_flags);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
index 1924c91..1ee697a 100644
--- a/lib/libv4l2/libv4l2-priv.h
+++ b/lib/libv4l2/libv4l2-priv.h
@@ -104,6 +104,7 @@ struct v4l2_dev_info {
void *plugin_library;
void *dev_ops_priv;
const struct libv4l_dev_ops *dev_ops;
+ struct v4l2_controls_map *map;
};
/* From v4l2-plugin.c */
@@ -130,4 +131,20 @@ static inline void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
extern const char *v4l2_ioctls[];
void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
+
+struct v4l2_control_map {
+ unsigned long control;
+ int fd;
+};
+
+struct v4l2_controls_map {
+ int main_fd;
+ int num_fds;
+ int num_controls;
+ struct v4l2_control_map map[];
+};
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags);
+LIBV4L_PUBLIC int v4l2_get_fd_for_control(int fd, unsigned long control);
+
#endif
diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
index 2db25d1..39f69db 100644
--- a/lib/libv4l2/libv4l2.c
+++ b/lib/libv4l2/libv4l2.c
@@ -70,6 +70,8 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <dirent.h>
+
#include "libv4l2.h"
#include "libv4l2-priv.h"
#include "libv4l-plugin.h"
@@ -787,6 +789,8 @@ no_capture:
if (index >= devices_used)
devices_used = index + 1;
+ devices[index].map = NULL;
+
/* Note we always tell v4lconvert to optimize src fmt selection for
our default fps, the only exception is the app explicitly selecting
a frame rate using the S_PARM ioctl after a S_FMT */
@@ -1056,12 +1060,47 @@ static int v4l2_s_fmt(int index, struct v4l2_format *dest_fmt)
return 0;
}
+int v4l2_get_fd_for_control(int fd, unsigned long control)
+{
+ int index = v4l2_get_index(fd);
+ struct v4l2_controls_map *map;
+ int lo = 0;
+ int hi;
+
+ if (index < 0)
+ return fd;
+
+ map = devices[index].map;
+ if (!map)
+ return fd;
+ hi = map->num_controls;
+
+ while (lo < hi) {
+ int i = (lo + hi) / 2;
+ if (map->map[i].control == control) {
+ return map->map[i].fd;
+ }
+ if (map->map[i].control > control) {
+ hi = i;
+ continue;
+ }
+ if (map->map[i].control < control) {
+ lo = i+1;
+ continue;
+ }
+ printf("Bad: impossible condition in binary search\n");
+ exit(1);
+ }
+ return fd;
+}
+
int v4l2_ioctl(int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
int result, index, saved_err;
- int is_capture_request = 0, stream_needs_locking = 0;
+ int is_capture_request = 0, stream_needs_locking = 0,
+ is_subdev_request = 0;
va_start(ap, request);
arg = va_arg(ap, void *);
@@ -1076,18 +1115,20 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
ioctl, causing it to get sign extended, depending upon this behavior */
request = (unsigned int)request;
+ /* FIXME */
if (devices[index].convert == NULL)
goto no_capture_request;
/* Is this a capture request and do we need to take the stream lock? */
switch (request) {
- case VIDIOC_QUERYCAP:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
+ is_subdev_request = 1;
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
is_capture_request = 1;
@@ -1151,10 +1192,15 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
}
if (!is_capture_request) {
+ int sub_fd;
no_capture_request:
+ sub_fd = fd;
+ if (is_subdev_request) {
+ sub_fd = v4l2_get_fd_for_control(index, ((struct v4l2_queryctrl *) arg)->id);
+ }
result = devices[index].dev_ops->ioctl(
devices[index].dev_ops_priv,
- fd, request, arg);
+ sub_fd, request, arg);
saved_err = errno;
v4l2_log_ioctl(request, arg, result);
errno = saved_err;
@@ -1782,3 +1828,195 @@ int v4l2_get_control(int fd, int cid)
(qctrl.maximum - qctrl.minimum) / 2) /
(qctrl.maximum - qctrl.minimum);
}
+
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags)
+{
+ int index;
+ int i;
+
+ for (i=0; i<map->num_controls; i++) {
+ if (map->map[i].fd <= 0) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Bad fd in map.\n");
+ return -1;
+ }
+ if (i>=1 && map->map[i].control <= map->map[i-1].control) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Controls not sorted.\n");
+ return -1;
+ }
+ }
+
+ i = v4l2_fd_open(map->main_fd, v4l2_flags);
+ index = v4l2_get_index(map->main_fd);
+ devices[index].map = map;
+ return i;
+}
+
+static void scan_devices(char **device_names, int *device_fds, int num)
+{
+ struct dirent **namelist;
+ int n;
+ char *class_v4l = "/sys/class/video4linux";
+
+ n = scandir(class_v4l, &namelist, NULL, alphasort);
+ if (n < 0) {
+ perror("scandir");
+ return;
+ }
+
+ while (n--) {
+ if (namelist[n]->d_name[0] != '.') {
+ char filename[1024], content[1024];
+ sprintf(filename, "%s/%s/name", class_v4l, namelist[n]->d_name);
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+ printf("Strange, can't open %s", filename);
+ } else {
+ fgets(content, 1024, f);
+ fclose(f);
+
+ int i;
+ for (i = num-1; i >=0; i--) {
+ if (!strcmp(content, device_names[i])) {
+ sprintf(filename, "/dev/%s", namelist[n]->d_name);
+ device_fds[i] = open(filename, O_RDWR);
+ if (device_fds[i] < 0) {
+ V4L2_LOG_ERR("Error opening %s: %m\n", filename);
+ }
+ }
+ }
+ }
+ }
+ free(namelist[n]);
+ }
+ free(namelist);
+
+}
+
+int v4l2_open_complex(char *name, int v4l2_flags)
+{
+#define perr(s) V4L2_LOG_ERR("open_complex: " s "\n")
+#define BUF 256
+ FILE *f = fopen(name, "r");
+
+ int res = -1;
+ char buf[BUF];
+ int version, num_modes, num_devices, num_controls;
+ int dev, control;
+
+ if (!f) {
+ perr("open of .cv file failed: %m");
+ goto err;
+ }
+
+ if (fscanf(f, "Complex Video: %d\n", &version) != 1) {
+ perr(".cv file does not have required header");
+ goto close;
+ }
+
+ if (version != 0) {
+ perr(".cv file has unknown version");
+ goto close;
+ }
+
+ if (fscanf(f, "#modes: %d\n", &num_modes) != 1) {
+ perr("could not parse modes");
+ goto close;
+ }
+
+ if (num_modes != 1) {
+ perr("only single mode is supported for now");
+ goto close;
+ }
+
+ if (fscanf(f, "Mode: %s\n", buf) != 1) {
+ perr("could not parse mode name");
+ goto close;
+ }
+
+ if (fscanf(f, " #devices: %d\n", &num_devices) != 1) {
+ perr("could not parse number of devices");
+ goto close;
+ }
+#define MAX_DEVICES 16
+ char *device_names[MAX_DEVICES] = { NULL, };
+ int device_fds[MAX_DEVICES];
+ if (num_devices > MAX_DEVICES) {
+ perr("too many devices");
+ goto close;
+ }
+
+ for (dev = 0; dev < num_devices; dev++) {
+ int tmp;
+ if (fscanf(f, "%d: ", &tmp) != 1) {
+ perr("could not parse device");
+ goto free_devices;
+ }
+ if (tmp != dev) {
+ perr("bad device number");
+ goto free_devices;
+ }
+ fgets(buf, BUF, f);
+ device_names[dev] = strdup(buf);
+ device_fds[dev] = -1;
+ }
+
+ scan_devices(device_names, device_fds, num_devices);
+
+ for (dev = 0; dev < num_devices; dev++) {
+ if (device_fds[dev] == -1) {
+ perr("Could not open all required devices");
+ goto close_devices;
+ }
+ }
+
+ if (fscanf(f, " #controls: %d\n", &num_controls) != 1) {
+ perr("can not parse number of controls");
+ goto close_devices;
+ }
+
+ struct v4l2_controls_map *map = malloc(sizeof(struct v4l2_controls_map) +
+ num_controls*sizeof(struct v4l2_control_map));
+
+ map->num_controls = num_controls;
+ map->num_fds = num_devices;
+ map->main_fd = device_fds[0];
+
+ for (control = 0; control < num_controls; control++) {
+ unsigned long num;
+ int dev;
+ if (fscanf(f, "0x%lx: %d\n", &num, &dev) != 2) {
+ perr("could not parse control");
+ goto free_map;
+ }
+ if ((dev < 0) || (dev >= num_devices)) {
+ perr("device out of range");
+ goto free_map;
+ }
+ map->map[control].control = num;
+ map->map[control].fd = device_fds[dev];
+ }
+ if (fscanf(f, "%s", buf) > 0) {
+ perr("junk at end of file");
+ goto free_map;
+ }
+
+ res = v4l2_open_pipeline(map, v4l2_flags);
+
+ if (res < 0) {
+free_map:
+ free(map);
+close_devices:
+ for (dev = 0; dev < num_devices; dev++)
+ close(device_fds[dev]);
+ }
+free_devices:
+ for (dev = 0; dev < num_devices; dev++) {
+ free(device_names[dev]);
+ }
+close:
+ fclose(f);
+err:
+ return res;
+}
+
diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c
index 59f28b1..c1e6f93 100644
--- a/lib/libv4lconvert/control/libv4lcontrol.c
+++ b/lib/libv4lconvert/control/libv4lcontrol.c
@@ -863,6 +863,7 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
struct v4l2_queryctrl *ctrl = arg;
int retval;
uint32_t orig_id = ctrl->id;
+ int fd;
/* if we have an exact match return it */
for (i = 0; i < V4LCONTROL_COUNT; i++)
@@ -872,8 +873,9 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
/* find out what the kernel driver would respond. */
- retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ retval = data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_QUERYCTRL, arg);
if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) &&
@@ -903,6 +905,7 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -911,7 +914,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_G_CTRL, arg);
}
@@ -994,6 +998,7 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -1008,7 +1013,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_S_CTRL, arg);
}
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-02 21:01 ` Pavel Machek
@ 2018-06-06 6:18 ` Tomasz Figa
2018-06-06 8:46 ` Pavel Machek
0 siblings, 1 reply; 9+ messages in thread
From: Tomasz Figa @ 2018-06-06 6:18 UTC (permalink / raw)
To: Pavel Machek
Cc: mchehab+samsung, mchehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, Linux Media Mailing List, Hans Verkuil
Hi Pavel,
Thanks for coming up with this proposal. Please see my comments below.
On Sun, Jun 3, 2018 at 6:01 AM Pavel Machek <pavel@ucw.cz> wrote:
>
> Hi!
>
> Ok, can I get any comments on this one?
> v4l2_open_complex("/file/with/descriptor", 0) can be used to open
> whole pipeline at once, and work if it as if it was one device.
I'm not convinced if we should really be piggy backing on libv4l, but
it's just a matter of where we put the code added by your patch, so
let's put that aside.
Who would be calling this function?
The scenario that I could think of is:
- legacy app would call open(/dev/video?), which would be handled by
libv4l open hook (v4l2_open()?),
- v4l2_open() would check if given /dev/video? figures in its list of
complex pipelines, for example by calling v4l2_open_complex() and
seeing if it succeeds,
- if it succeeds, the resulting fd would represent the complex
pipeline, otherwise it would just open the requested node directly.
I guess that could give some basic camera functionality on OMAP3-like hardware.
For most of the current generation of imaging subsystems (e.g. Intel
IPU3, Rockchip RKISP1) it's not enough. The reason is that there is
more to be handled by userspace than just setting controls:
- configuring pixel formats, resolutions, crops, etc. through the
whole pipeline - I guess that could be preconfigured per use case
inside the configuration file, though,
- forwarding buffers between capture and processing pipelines, i.e.
DQBUF raw frame from CSI2 video node and QBUF to ISP video node,
- handling metadata CAPTURE and OUTPUT buffers controlling the 3A
feedback loop - this might be optional if all we need is just ability
to capture some frames, but required for getting good quality,
- actually mapping legacy controls into the above metadata,
I guess it's just a matter of adding further code to handle those,
though. However, it would build up a separate legacy framework that
locks us up into the legacy USB camera model, while we should rather
be leaning towards a more flexible framework, such as Android Camera
HALv3 or Pipewire. On top of such framework, we could just have a very
thin layer to emulate the legacy, single video node, camera.
Other than that, I agree that we should be able to have pre-generated
configuration files and use them to build and setup the pipeline.
That's actually what we have in camera HALs on Chrome OS (Android
camera HALv3 model adopted to Chrome OS).
Some minor comments for the code follow.
[snip]
> +int v4l2_get_fd_for_control(int fd, unsigned long control)
> +{
> + int index = v4l2_get_index(fd);
> + struct v4l2_controls_map *map;
> + int lo = 0;
> + int hi;
> +
> + if (index < 0)
> + return fd;
> +
> + map = devices[index].map;
> + if (!map)
> + return fd;
> + hi = map->num_controls;
> +
> + while (lo < hi) {
> + int i = (lo + hi) / 2;
> + if (map->map[i].control == control) {
> + return map->map[i].fd;
> + }
> + if (map->map[i].control > control) {
> + hi = i;
> + continue;
> + }
> + if (map->map[i].control < control) {
> + lo = i+1;
> + continue;
> + }
> + printf("Bad: impossible condition in binary search\n");
> + exit(1);
> + }
Could we use bsearch() here?
> + return fd;
> +}
> +
> int v4l2_ioctl(int fd, unsigned long int request, ...)
> {
> void *arg;
> va_list ap;
> int result, index, saved_err;
> - int is_capture_request = 0, stream_needs_locking = 0;
> + int is_capture_request = 0, stream_needs_locking = 0,
> + is_subdev_request = 0;
>
> va_start(ap, request);
> arg = va_arg(ap, void *);
> @@ -1076,18 +1115,20 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
> ioctl, causing it to get sign extended, depending upon this behavior */
> request = (unsigned int)request;
>
> + /* FIXME */
> if (devices[index].convert == NULL)
> goto no_capture_request;
>
> /* Is this a capture request and do we need to take the stream lock? */
> switch (request) {
> - case VIDIOC_QUERYCAP:
> case VIDIOC_QUERYCTRL:
> case VIDIOC_G_CTRL:
> case VIDIOC_S_CTRL:
> case VIDIOC_G_EXT_CTRLS:
> - case VIDIOC_TRY_EXT_CTRLS:
> case VIDIOC_S_EXT_CTRLS:
> + is_subdev_request = 1;
> + case VIDIOC_QUERYCAP:
> + case VIDIOC_TRY_EXT_CTRLS:
I'm not sure why we are moving those around. Is this perhaps related
to the FIXME comment above? If so, it would be helpful to have some
short explanation next to it.
> case VIDIOC_ENUM_FRAMESIZES:
> case VIDIOC_ENUM_FRAMEINTERVALS:
> is_capture_request = 1;
> @@ -1151,10 +1192,15 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
> }
>
> if (!is_capture_request) {
> + int sub_fd;
> no_capture_request:
> + sub_fd = fd;
> + if (is_subdev_request) {
> + sub_fd = v4l2_get_fd_for_control(index, ((struct v4l2_queryctrl *) arg)->id);
> + }
nit: Looks like something weird going on here with indentation.
> result = devices[index].dev_ops->ioctl(
> devices[index].dev_ops_priv,
> - fd, request, arg);
> + sub_fd, request, arg);
> saved_err = errno;
> v4l2_log_ioctl(request, arg, result);
> errno = saved_err;
> @@ -1782,3 +1828,195 @@ int v4l2_get_control(int fd, int cid)
> (qctrl.maximum - qctrl.minimum) / 2) /
> (qctrl.maximum - qctrl.minimum);
> }
> +
> +
nit: Double blank line.
> +int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags)
> +{
> + int index;
> + int i;
> +
> + for (i=0; i<map->num_controls; i++) {
> + if (map->map[i].fd <= 0) {
> + V4L2_LOG_ERR("v4l2_open_pipeline: Bad fd in map.\n");
> + return -1;
> + }
> + if (i>=1 && map->map[i].control <= map->map[i-1].control) {
> + V4L2_LOG_ERR("v4l2_open_pipeline: Controls not sorted.\n");
> + return -1;
I guess we could just sort them at startup with qsort()?
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-06 6:18 ` Tomasz Figa
@ 2018-06-06 8:46 ` Pavel Machek
2018-06-06 8:53 ` Tomasz Figa
0 siblings, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-06-06 8:46 UTC (permalink / raw)
To: Tomasz Figa
Cc: mchehab+samsung, mchehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, Linux Media Mailing List, Hans Verkuil
[-- Attachment #1: Type: text/plain, Size: 3873 bytes --]
Hi!
> Thanks for coming up with this proposal. Please see my comments below.
>
> > Ok, can I get any comments on this one?
> > v4l2_open_complex("/file/with/descriptor", 0) can be used to open
> > whole pipeline at once, and work if it as if it was one device.
>
> I'm not convinced if we should really be piggy backing on libv4l, but
> it's just a matter of where we put the code added by your patch, so
> let's put that aside.
There was some talk about this before, and libv4l2 is what we came
with. Only libv4l2 is in position to propagate controls to right
devices.
> Who would be calling this function?
>
> The scenario that I could think of is:
> - legacy app would call open(/dev/video?), which would be handled by
> libv4l open hook (v4l2_open()?),
I don't think that kind of legacy apps is in use any more. I'd prefer
not to deal with them.
> - v4l2_open() would check if given /dev/video? figures in its list of
> complex pipelines, for example by calling v4l2_open_complex() and
> seeing if it succeeds,
I'd rather not have v4l2_open_complex() called on devices. We could
test if argument is regular file and then call it... But again, that's
next step.
> - if it succeeds, the resulting fd would represent the complex
> pipeline, otherwise it would just open the requested node directly.
> I guess that could give some basic camera functionality on OMAP3-like hardware.
It definitely gives camera functionality on OMAP3. I'm using it to
take photos with Nokia N900.
> For most of the current generation of imaging subsystems (e.g. Intel
> IPU3, Rockchip RKISP1) it's not enough. The reason is that there is
> more to be handled by userspace than just setting controls:
> - configuring pixel formats, resolutions, crops, etc. through the
> whole pipeline - I guess that could be preconfigured per use case
> inside the configuration file, though,
That may be future plan. Note that these can be preconfigured; unlike
controls propagation...
> - forwarding buffers between capture and processing pipelines, i.e.
> DQBUF raw frame from CSI2 video node and QBUF to ISP video node,
My hardware does not need that, so I could not test it. I'll rely on
someone with required hardware to provide that.
(And you can take DQBUF and process it with software, at cost of
slightly higher CPU usage, right?)
> - handling metadata CAPTURE and OUTPUT buffers controlling the 3A
> feedback loop - this might be optional if all we need is just ability
> to capture some frames, but required for getting good quality,
> - actually mapping legacy controls into the above metadata,
I'm not sure what 3A is. If you mean hardware histograms and friends,
yes, it would be nice to support that, but, again, statistics can be
computed in software.
> I guess it's just a matter of adding further code to handle those,
> though. However, it would build up a separate legacy framework that
> locks us up into the legacy USB camera model, while we should rather
> be leaning towards a more flexible framework, such as Android Camera
> HALv3 or Pipewire. On top of such framework, we could just have a very
> thin layer to emulate the legacy, single video node, camera.
Yes, we'll need something more advanced.
But.. we also need something to run the devices today, so that kernel
drivers can be tested and do not bitrot. That's why I'm doing this
work.
And I believe we should work in steps before getting there... controls
propagation can not be done from external application, so I'm starting
with it.
> Some minor comments for the code follow.
Ok, let me send this, then go through the comments.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-06 8:46 ` Pavel Machek
@ 2018-06-06 8:53 ` Tomasz Figa
2018-06-06 10:01 ` Pavel Machek
0 siblings, 1 reply; 9+ messages in thread
From: Tomasz Figa @ 2018-06-06 8:53 UTC (permalink / raw)
To: Pavel Machek
Cc: mchehab+samsung, mchehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, Linux Media Mailing List, Hans Verkuil
On Wed, Jun 6, 2018 at 5:46 PM Pavel Machek <pavel@ucw.cz> wrote:
>
> Hi!
>
> > Thanks for coming up with this proposal. Please see my comments below.
> >
> > > Ok, can I get any comments on this one?
> > > v4l2_open_complex("/file/with/descriptor", 0) can be used to open
> > > whole pipeline at once, and work if it as if it was one device.
> >
> > I'm not convinced if we should really be piggy backing on libv4l, but
> > it's just a matter of where we put the code added by your patch, so
> > let's put that aside.
>
> There was some talk about this before, and libv4l2 is what we came
> with. Only libv4l2 is in position to propagate controls to right
> devices.
>
> > Who would be calling this function?
> >
> > The scenario that I could think of is:
> > - legacy app would call open(/dev/video?), which would be handled by
> > libv4l open hook (v4l2_open()?),
>
> I don't think that kind of legacy apps is in use any more. I'd prefer
> not to deal with them.
In another thread ("[ANN v2] Complex Camera Workshop - Tokyo - Jun,
19"), Mauro has mentioned a number of those:
"open source ones (Camorama, Cheese, Xawtv, Firefox, Chromium, ...) and closed
source ones (Skype, Chrome, ...)"
>
> > - v4l2_open() would check if given /dev/video? figures in its list of
> > complex pipelines, for example by calling v4l2_open_complex() and
> > seeing if it succeeds,
>
> I'd rather not have v4l2_open_complex() called on devices. We could
> test if argument is regular file and then call it... But again, that's
> next step.
>
> > - if it succeeds, the resulting fd would represent the complex
> > pipeline, otherwise it would just open the requested node directly.
What's the answer to my original question of who would be calling
v4l2_open_complex(), then?
>
> > I guess that could give some basic camera functionality on OMAP3-like hardware.
>
> It definitely gives camera functionality on OMAP3. I'm using it to
> take photos with Nokia N900.
>
> > For most of the current generation of imaging subsystems (e.g. Intel
> > IPU3, Rockchip RKISP1) it's not enough. The reason is that there is
> > more to be handled by userspace than just setting controls:
> > - configuring pixel formats, resolutions, crops, etc. through the
> > whole pipeline - I guess that could be preconfigured per use case
> > inside the configuration file, though,
>
> That may be future plan. Note that these can be preconfigured; unlike
> controls propagation...
>
> > - forwarding buffers between capture and processing pipelines, i.e.
> > DQBUF raw frame from CSI2 video node and QBUF to ISP video node,
>
> My hardware does not need that, so I could not test it. I'll rely on
> someone with required hardware to provide that.
>
> (And you can take DQBUF and process it with software, at cost of
> slightly higher CPU usage, right?)
>
> > - handling metadata CAPTURE and OUTPUT buffers controlling the 3A
> > feedback loop - this might be optional if all we need is just ability
> > to capture some frames, but required for getting good quality,
> > - actually mapping legacy controls into the above metadata,
>
> I'm not sure what 3A is. If you mean hardware histograms and friends,
> yes, it would be nice to support that, but, again, statistics can be
> computed in software.
Auto-exposure, auto-white-balance, auto-focus. In complex camera
subsystems these need to be done in software. On most hardware
platforms, ISP provides necessary input data (statistics) and software
calculates required processing parameters.
>
> > I guess it's just a matter of adding further code to handle those,
> > though. However, it would build up a separate legacy framework that
> > locks us up into the legacy USB camera model, while we should rather
> > be leaning towards a more flexible framework, such as Android Camera
> > HALv3 or Pipewire. On top of such framework, we could just have a very
> > thin layer to emulate the legacy, single video node, camera.
>
> Yes, we'll need something more advanced.
>
> But.. we also need something to run the devices today, so that kernel
> drivers can be tested and do not bitrot. That's why I'm doing this
> work.
I guess the most important bit I missed then is what is the intended
use case for this. It seems to be related to my earlier, unanswered
question about who would be calliing v4l2_open_complex(), though.
What userspace applications would be used for this testing?
Best regards,
Tomasz
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-06 8:53 ` Tomasz Figa
@ 2018-06-06 10:01 ` Pavel Machek
2018-06-06 16:57 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 9+ messages in thread
From: Pavel Machek @ 2018-06-06 10:01 UTC (permalink / raw)
To: Tomasz Figa
Cc: mchehab+samsung, mchehab, Hans Verkuil, pali.rohar, sre,
Sakari Ailus, Linux Media Mailing List, Hans Verkuil
[-- Attachment #1: Type: text/plain, Size: 3530 bytes --]
Hi!
> > > Who would be calling this function?
> > >
> > > The scenario that I could think of is:
> > > - legacy app would call open(/dev/video?), which would be handled by
> > > libv4l open hook (v4l2_open()?),
> >
> > I don't think that kind of legacy apps is in use any more. I'd prefer
> > not to deal with them.
>
> In another thread ("[ANN v2] Complex Camera Workshop - Tokyo - Jun,
> 19"), Mauro has mentioned a number of those:
>
> "open source ones (Camorama, Cheese, Xawtv, Firefox, Chromium, ...) and closed
> source ones (Skype, Chrome, ...)"
Yep, ok. Still would prefer not to deal with them.
(Opening additional fds behind application's back is quite nasty,
those apps should really switch to v4l2_ variants).
> > > - v4l2_open() would check if given /dev/video? figures in its list of
> > > complex pipelines, for example by calling v4l2_open_complex() and
> > > seeing if it succeeds,
> >
> > I'd rather not have v4l2_open_complex() called on devices. We could
> > test if argument is regular file and then call it... But again, that's
> > next step.
> >
> > > - if it succeeds, the resulting fd would represent the complex
> > > pipeline, otherwise it would just open the requested node directly.
>
> What's the answer to my original question of who would be calling
> v4l2_open_complex(), then?
Application ready to deal with additional fds being
opened. contrib/test/sdlcam will be the first one.
We may do some magic to do v4l2_open_complex() in v4l2_open(), but I
believe that should be separate step.
> > > - handling metadata CAPTURE and OUTPUT buffers controlling the 3A
> > > feedback loop - this might be optional if all we need is just ability
> > > to capture some frames, but required for getting good quality,
> > > - actually mapping legacy controls into the above metadata,
> >
> > I'm not sure what 3A is. If you mean hardware histograms and friends,
> > yes, it would be nice to support that, but, again, statistics can be
> > computed in software.
>
> Auto-exposure, auto-white-balance, auto-focus. In complex camera
> subsystems these need to be done in software. On most hardware
> platforms, ISP provides necessary input data (statistics) and software
> calculates required processing parameters.
Ok, so... statistics support would be nice, but that is really
separate problem.
v4l2 already contains auto-exposure and auto-white-balance. I have
patches for auto-focus. But hardware statistics are not used.
> > Yes, we'll need something more advanced.
> >
> > But.. we also need something to run the devices today, so that kernel
> > drivers can be tested and do not bitrot. That's why I'm doing this
> > work.
>
> I guess the most important bit I missed then is what is the intended
> use case for this. It seems to be related to my earlier, unanswered
> question about who would be calliing v4l2_open_complex(), though.
>
> What userspace applications would be used for this testing?
Main use case is kernel testing.
Secondary use case is taking .jpg photos using sdlcam.
Test apps such as qv4l2 would be nice to have, and maybe I'll
experiment with capturing video somehow one day. I'm pretty sure it
will not be easy.
Oh and I guess a link to how well it works? See
https://www.youtube.com/watch?v=fH6zuK2OOVU .
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [RFC, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-06 10:01 ` Pavel Machek
@ 2018-06-06 16:57 ` Mauro Carvalho Chehab
2018-06-07 12:22 ` [PATCH, " Pavel Machek
0 siblings, 1 reply; 9+ messages in thread
From: Mauro Carvalho Chehab @ 2018-06-06 16:57 UTC (permalink / raw)
To: Pavel Machek
Cc: Tomasz Figa, mchehab, Hans Verkuil, pali.rohar, sre, Sakari Ailus,
Linux Media Mailing List, Hans Verkuil
Em Wed, 6 Jun 2018 12:01:50 +0200
Pavel Machek <pavel@ucw.cz> escreveu:
> Hi!
>
> > > > Who would be calling this function?
> > > >
> > > > The scenario that I could think of is:
> > > > - legacy app would call open(/dev/video?), which would be handled by
> > > > libv4l open hook (v4l2_open()?),
> > >
> > > I don't think that kind of legacy apps is in use any more. I'd prefer
> > > not to deal with them.
> >
> > In another thread ("[ANN v2] Complex Camera Workshop - Tokyo - Jun,
> > 19"), Mauro has mentioned a number of those:
> >
> > "open source ones (Camorama, Cheese, Xawtv, Firefox, Chromium, ...) and closed
> > source ones (Skype, Chrome, ...)"
>
> Yep, ok. Still would prefer not to deal with them.
I guess we'll end by needing to handle them. Anyway, now that PCs are
starting to come with complex cameras[1], we'll need to address this
with a focus on adding support for existing apps.
[1] we had a report from one specific model but I heard from a reliable
source that there are already other devices with similar issues.
> (Opening additional fds behind application's back is quite nasty,
> those apps should really switch to v4l2_ variants).
Only closed source apps use the LD_PRELOAD hack. All the others
use v4l2_ variants, but, as Nicolas mentioned at the other
thread, there are a number of problems with the current approach.
Perhaps is time for us to not be limited to the current ABI, writing
a new API from scratch, and then adding a compatibility layer to be
used by apps that rely on v4l2_ variants, in order to avoid breaking
the ABI and keep providing LD_PRELOAD. We can then convert the apps
we use/care most to use the new ABI.
>
> > > > - v4l2_open() would check if given /dev/video? figures in its list of
> > > > complex pipelines, for example by calling v4l2_open_complex() and
> > > > seeing if it succeeds,
> > >
> > > I'd rather not have v4l2_open_complex() called on devices. We could
> > > test if argument is regular file and then call it... But again, that's
> > > next step.
> > >
> > > > - if it succeeds, the resulting fd would represent the complex
> > > > pipeline, otherwise it would just open the requested node directly.
> >
> > What's the answer to my original question of who would be calling
> > v4l2_open_complex(), then?
>
> Application ready to deal with additional fds being
> opened. contrib/test/sdlcam will be the first one.
>
> We may do some magic to do v4l2_open_complex() in v4l2_open(), but I
> believe that should be separate step.
In order to avoid breaking the ABI for existing apps, v4l2_open() should
internally call v4l2_open_complex() (or whatever we call it at the new
API design).
> > > > - handling metadata CAPTURE and OUTPUT buffers controlling the 3A
> > > > feedback loop - this might be optional if all we need is just ability
> > > > to capture some frames, but required for getting good quality,
> > > > - actually mapping legacy controls into the above metadata,
> > >
> > > I'm not sure what 3A is. If you mean hardware histograms and friends,
> > > yes, it would be nice to support that, but, again, statistics can be
> > > computed in software.
> >
> > Auto-exposure, auto-white-balance, auto-focus. In complex camera
> > subsystems these need to be done in software. On most hardware
> > platforms, ISP provides necessary input data (statistics) and software
> > calculates required processing parameters.
>
> Ok, so... statistics support would be nice, but that is really
> separate problem.
>
> v4l2 already contains auto-exposure and auto-white-balance. I have
> patches for auto-focus. But hardware statistics are not used.
Feel free to submit the auto-focus patches anytime. With all 3A
algos there (even on a non-optimal way using hw stats), it will
make easier for us when designing a solution that would work for
both IMAP3 and ISP (and likely be generic enough for other hardware).
For the full complex hardware solution, though, it is probably better
to fork v4l-utils into a separate project, in order to do the development
without affecting current users of it, merging it back only after we'll
be sure that existing apps will keep working with v4l2_foo() functions
and LD_PRELOAD.
Anyway, this is something that it makes sense to discuss during the
Complex Camera Workshop.
> > > Yes, we'll need something more advanced.
> > >
> > > But.. we also need something to run the devices today, so that kernel
> > > drivers can be tested and do not bitrot. That's why I'm doing this
> > > work.
> >
> > I guess the most important bit I missed then is what is the intended
> > use case for this. It seems to be related to my earlier, unanswered
> > question about who would be calliing v4l2_open_complex(), though.
> >
> > What userspace applications would be used for this testing?
>
> Main use case is kernel testing.
>
> Secondary use case is taking .jpg photos using sdlcam.
If a v4l2_complex_open() will, for now, be something that we don't
export publicly, using it only for the tools already at libv4l2,
I don't see much troubles on adding it, but I would hate to have to
stick with this ABI. Otherwise, we should analyze it after having
a bigger picture. So, better to wait for the Complex Camera
Workshop before adding this.
Btw, would you be able to join us there (either locally or
remotely via Google Hangouts)?
> Test apps such as qv4l2 would be nice to have, and maybe I'll
> experiment with capturing video somehow one day. I'm pretty sure it
> will not be easy.
Capture video is a must have for PCs. The final solution should
take it into account.
>
> Oh and I guess a link to how well it works? See
> https://www.youtube.com/watch?v=fH6zuK2OOVU .
>
> Best regards,
> Pavel
Thanks,
Mauro
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline
2018-06-06 16:57 ` Mauro Carvalho Chehab
@ 2018-06-07 12:22 ` Pavel Machek
0 siblings, 0 replies; 9+ messages in thread
From: Pavel Machek @ 2018-06-07 12:22 UTC (permalink / raw)
To: Mauro Carvalho Chehab
Cc: Tomasz Figa, mchehab, Hans Verkuil, pali.rohar, sre, Sakari Ailus,
Linux Media Mailing List, Hans Verkuil
[-- Attachment #1: Type: text/plain, Size: 12697 bytes --]
Hi!
> > We may do some magic to do v4l2_open_complex() in v4l2_open(), but I
> > believe that should be separate step.
>
> In order to avoid breaking the ABI for existing apps, v4l2_open() should
> internally call v4l2_open_complex() (or whatever we call it at the new
> API design).
Ok. Here's updated patch. open_complex() now takes fd. Any other
issues?
Best regards,
Pavel
diff --git a/lib/include/libv4l2.h b/lib/include/libv4l2.h
index ea1870d..a0ec0a9 100644
--- a/lib/include/libv4l2.h
+++ b/lib/include/libv4l2.h
@@ -58,6 +58,10 @@ LIBV4L_PUBLIC extern FILE *v4l2_log_file;
invalid memory address will not lead to failure with errno being EFAULT,
as it would with a real ioctl, but will cause libv4l2 to break, and you
get to keep both pieces.
+
+ You can open complex pipelines by passing ".cv" file with pipeline
+ description to v4l2_open(). libv4l2 will open all the required
+ devices automatically in that case.
*/
LIBV4L_PUBLIC int v4l2_open(const char *file, int oflag, ...);
diff --git a/lib/libv4l2/libv4l2-priv.h b/lib/libv4l2/libv4l2-priv.h
index 1924c91..1ee697a 100644
--- a/lib/libv4l2/libv4l2-priv.h
+++ b/lib/libv4l2/libv4l2-priv.h
@@ -104,6 +104,7 @@ struct v4l2_dev_info {
void *plugin_library;
void *dev_ops_priv;
const struct libv4l_dev_ops *dev_ops;
+ struct v4l2_controls_map *map;
};
/* From v4l2-plugin.c */
@@ -130,4 +131,20 @@ static inline void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
extern const char *v4l2_ioctls[];
void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
+
+struct v4l2_control_map {
+ unsigned long control;
+ int fd;
+};
+
+struct v4l2_controls_map {
+ int main_fd;
+ int num_fds;
+ int num_controls;
+ struct v4l2_control_map map[];
+};
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags);
+LIBV4L_PUBLIC int v4l2_get_fd_for_control(int fd, unsigned long control);
+
#endif
diff --git a/lib/libv4l2/libv4l2.c b/lib/libv4l2/libv4l2.c
index 2db25d1..ac430f0 100644
--- a/lib/libv4l2/libv4l2.c
+++ b/lib/libv4l2/libv4l2.c
@@ -70,6 +70,8 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include <dirent.h>
+
#include "libv4l2.h"
#include "libv4l2-priv.h"
#include "libv4l-plugin.h"
@@ -618,6 +620,8 @@ static void v4l2_update_fps(int index, struct v4l2_streamparm *parm)
devices[index].fps = 0;
}
+static int v4l2_open_complex(int fd, int v4l2_flags);
+
int v4l2_open(const char *file, int oflag, ...)
{
int fd;
@@ -641,6 +645,21 @@ int v4l2_open(const char *file, int oflag, ...)
if (fd == -1)
return fd;
+ int len = strlen(file);
+ char *end = ".cv";
+ int len2 = strlen(end);
+ if ((len > len2) && (!strcmp(file + len - len2, end))) {
+ /* .cv extension */
+ struct stat sb;
+
+ if (fstat(fd, &sb) == 0) {
+ if ((sb.st_mode & S_IFMT) == S_IFREG) {
+ return v4l2_open_complex(fd, 0);
+ }
+ }
+
+ }
+
if (v4l2_fd_open(fd, 0) == -1) {
int saved_err = errno;
@@ -787,6 +806,8 @@ no_capture:
if (index >= devices_used)
devices_used = index + 1;
+ devices[index].map = NULL;
+
/* Note we always tell v4lconvert to optimize src fmt selection for
our default fps, the only exception is the app explicitly selecting
a frame rate using the S_PARM ioctl after a S_FMT */
@@ -1056,12 +1077,47 @@ static int v4l2_s_fmt(int index, struct v4l2_format *dest_fmt)
return 0;
}
+int v4l2_get_fd_for_control(int fd, unsigned long control)
+{
+ int index = v4l2_get_index(fd);
+ struct v4l2_controls_map *map;
+ int lo = 0;
+ int hi;
+
+ if (index < 0)
+ return fd;
+
+ map = devices[index].map;
+ if (!map)
+ return fd;
+ hi = map->num_controls;
+
+ while (lo < hi) {
+ int i = (lo + hi) / 2;
+ if (map->map[i].control == control) {
+ return map->map[i].fd;
+ }
+ if (map->map[i].control > control) {
+ hi = i;
+ continue;
+ }
+ if (map->map[i].control < control) {
+ lo = i+1;
+ continue;
+ }
+ printf("Bad: impossible condition in binary search\n");
+ exit(1);
+ }
+ return fd;
+}
+
int v4l2_ioctl(int fd, unsigned long int request, ...)
{
void *arg;
va_list ap;
int result, index, saved_err;
- int is_capture_request = 0, stream_needs_locking = 0;
+ int is_capture_request = 0, stream_needs_locking = 0,
+ is_subdev_request = 0;
va_start(ap, request);
arg = va_arg(ap, void *);
@@ -1076,18 +1132,20 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
ioctl, causing it to get sign extended, depending upon this behavior */
request = (unsigned int)request;
+ /* FIXME */
if (devices[index].convert == NULL)
goto no_capture_request;
/* Is this a capture request and do we need to take the stream lock? */
switch (request) {
- case VIDIOC_QUERYCAP:
case VIDIOC_QUERYCTRL:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
case VIDIOC_G_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_S_EXT_CTRLS:
+ is_subdev_request = 1;
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_ENUM_FRAMESIZES:
case VIDIOC_ENUM_FRAMEINTERVALS:
is_capture_request = 1;
@@ -1151,10 +1209,15 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
}
if (!is_capture_request) {
+ int sub_fd;
no_capture_request:
+ sub_fd = fd;
+ if (is_subdev_request) {
+ sub_fd = v4l2_get_fd_for_control(index, ((struct v4l2_queryctrl *) arg)->id);
+ }
result = devices[index].dev_ops->ioctl(
devices[index].dev_ops_priv,
- fd, request, arg);
+ sub_fd, request, arg);
saved_err = errno;
v4l2_log_ioctl(request, arg, result);
errno = saved_err;
@@ -1782,3 +1845,194 @@ int v4l2_get_control(int fd, int cid)
(qctrl.maximum - qctrl.minimum) / 2) /
(qctrl.maximum - qctrl.minimum);
}
+
+int v4l2_open_pipeline(struct v4l2_controls_map *map, int v4l2_flags)
+{
+ int index;
+ int i;
+
+ for (i=0; i<map->num_controls; i++) {
+ if (map->map[i].fd <= 0) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Bad fd in map.\n");
+ return -1;
+ }
+ if (i>=1 && map->map[i].control <= map->map[i-1].control) {
+ V4L2_LOG_ERR("v4l2_open_pipeline: Controls not sorted.\n");
+ return -1;
+ }
+ }
+
+ i = v4l2_fd_open(map->main_fd, v4l2_flags);
+ index = v4l2_get_index(map->main_fd);
+ devices[index].map = map;
+ return i;
+}
+
+static void scan_devices(char **device_names, int *device_fds, int num)
+{
+ struct dirent **namelist;
+ int n;
+ char *class_v4l = "/sys/class/video4linux";
+
+ n = scandir(class_v4l, &namelist, NULL, alphasort);
+ if (n < 0) {
+ perror("scandir");
+ return;
+ }
+
+ while (n--) {
+ if (namelist[n]->d_name[0] != '.') {
+ char filename[1024], content[1024];
+ sprintf(filename, "%s/%s/name", class_v4l, namelist[n]->d_name);
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+ printf("Strange, can't open %s", filename);
+ } else {
+ fgets(content, 1024, f);
+ fclose(f);
+
+ int i;
+ for (i = num-1; i >=0; i--) {
+ if (!strcmp(content, device_names[i])) {
+ sprintf(filename, "/dev/%s", namelist[n]->d_name);
+ device_fds[i] = open(filename, O_RDWR);
+ if (device_fds[i] < 0) {
+ V4L2_LOG_ERR("Error opening %s: %m\n", filename);
+ }
+ }
+ }
+ }
+ }
+ free(namelist[n]);
+ }
+ free(namelist);
+
+}
+
+static int v4l2_open_complex(int fd, int v4l2_flags)
+{
+#define perr(s) V4L2_LOG_ERR("open_complex: " s "\n")
+#define BUF 256
+ FILE *f = fdopen(fd, "r");
+
+ int res = -1;
+ char buf[BUF];
+ int version, num_modes, num_devices, num_controls;
+ int dev, control;
+
+ if (!f) {
+ perr("open of .cv file failed: %m");
+ goto err;
+ }
+
+ if (fscanf(f, "Complex Video: %d\n", &version) != 1) {
+ perr(".cv file does not have required header");
+ goto close;
+ }
+
+ if (version != 0) {
+ perr(".cv file has unknown version");
+ goto close;
+ }
+
+ if (fscanf(f, "#modes: %d\n", &num_modes) != 1) {
+ perr("could not parse modes");
+ goto close;
+ }
+
+ if (num_modes != 1) {
+ perr("only single mode is supported for now");
+ goto close;
+ }
+
+ if (fscanf(f, "Mode: %s\n", buf) != 1) {
+ perr("could not parse mode name");
+ goto close;
+ }
+
+ if (fscanf(f, " #devices: %d\n", &num_devices) != 1) {
+ perr("could not parse number of devices");
+ goto close;
+ }
+#define MAX_DEVICES 16
+ char *device_names[MAX_DEVICES] = { NULL, };
+ int device_fds[MAX_DEVICES];
+ if (num_devices > MAX_DEVICES) {
+ perr("too many devices");
+ goto close;
+ }
+
+ for (dev = 0; dev < num_devices; dev++) {
+ int tmp;
+ if (fscanf(f, "%d: ", &tmp) != 1) {
+ perr("could not parse device");
+ goto free_devices;
+ }
+ if (tmp != dev) {
+ perr("bad device number");
+ goto free_devices;
+ }
+ fgets(buf, BUF, f);
+ device_names[dev] = strdup(buf);
+ device_fds[dev] = -1;
+ }
+
+ scan_devices(device_names, device_fds, num_devices);
+
+ for (dev = 0; dev < num_devices; dev++) {
+ if (device_fds[dev] == -1) {
+ perr("Could not open all required devices");
+ goto close_devices;
+ }
+ }
+
+ if (fscanf(f, " #controls: %d\n", &num_controls) != 1) {
+ perr("can not parse number of controls");
+ goto close_devices;
+ }
+
+ struct v4l2_controls_map *map = malloc(sizeof(struct v4l2_controls_map) +
+ num_controls*sizeof(struct v4l2_control_map));
+
+ map->num_controls = num_controls;
+ map->num_fds = num_devices;
+ map->main_fd = device_fds[0];
+
+ for (control = 0; control < num_controls; control++) {
+ unsigned long num;
+ int dev;
+ if (fscanf(f, "0x%lx: %d\n", &num, &dev) != 2) {
+ perr("could not parse control");
+ goto free_map;
+ }
+ if ((dev < 0) || (dev >= num_devices)) {
+ perr("device out of range");
+ goto free_map;
+ }
+ map->map[control].control = num;
+ map->map[control].fd = device_fds[dev];
+ }
+ if (fscanf(f, "%s", buf) > 0) {
+ perr("junk at end of file");
+ goto free_map;
+ }
+
+ res = v4l2_open_pipeline(map, v4l2_flags);
+
+ if (res < 0) {
+free_map:
+ free(map);
+close_devices:
+ for (dev = 0; dev < num_devices; dev++)
+ close(device_fds[dev]);
+ }
+free_devices:
+ for (dev = 0; dev < num_devices; dev++) {
+ free(device_names[dev]);
+ }
+close:
+ fclose(f);
+err:
+ return res;
+}
+
diff --git a/lib/libv4lconvert/control/libv4lcontrol.c b/lib/libv4lconvert/control/libv4lcontrol.c
index 59f28b1..c1e6f93 100644
--- a/lib/libv4lconvert/control/libv4lcontrol.c
+++ b/lib/libv4lconvert/control/libv4lcontrol.c
@@ -863,6 +863,7 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
struct v4l2_queryctrl *ctrl = arg;
int retval;
uint32_t orig_id = ctrl->id;
+ int fd;
/* if we have an exact match return it */
for (i = 0; i < V4LCONTROL_COUNT; i++)
@@ -872,8 +873,9 @@ int v4lcontrol_vidioc_queryctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
/* find out what the kernel driver would respond. */
- retval = data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ retval = data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_QUERYCTRL, arg);
if ((data->priv_flags & V4LCONTROL_SUPPORTS_NEXT_CTRL) &&
@@ -903,6 +905,7 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -911,7 +914,8 @@ int v4lcontrol_vidioc_g_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_G_CTRL, arg);
}
@@ -994,6 +998,7 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
{
int i;
struct v4l2_control *ctrl = arg;
+ int fd;
for (i = 0; i < V4LCONTROL_COUNT; i++)
if ((data->controls & (1 << i)) &&
@@ -1008,7 +1013,8 @@ int v4lcontrol_vidioc_s_ctrl(struct v4lcontrol_data *data, void *arg)
return 0;
}
- return data->dev_ops->ioctl(data->dev_ops_priv, data->fd,
+ fd = v4l2_get_fd_for_control(data->fd, ctrl->id);
+ return data->dev_ops->ioctl(data->dev_ops_priv, fd,
VIDIOC_S_CTRL, arg);
}
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]
^ permalink raw reply related [flat|nested] 9+ messages in thread
end of thread, other threads:[~2018-07-30 11:05 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-07-08 21:32 [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Pavel Machek
2018-07-19 20:53 ` Pavel Machek
2018-07-23 18:36 ` Mauro Carvalho Chehab
2018-07-28 19:36 ` Pavel Machek
2018-07-28 21:11 ` new libv4l2 (was Re: [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline) Pavel Machek
2018-07-30 9:31 ` Mauro Carvalho Chehab
2018-07-27 12:47 ` [PATCH, libv4l]: Make libv4l2 usable on devices with complex pipeline Mauro Carvalho Chehab
2018-07-28 21:02 ` Pavel Machek
-- strict thread matches above, loose matches on Subject: below --
2018-03-19 12:15 [RFC, " Hans Verkuil
2018-03-19 13:26 ` Mauro Carvalho Chehab
2018-05-15 20:01 ` Pavel Machek
2018-05-15 22:03 ` Mauro Carvalho Chehab
2018-06-02 21:01 ` Pavel Machek
2018-06-06 6:18 ` Tomasz Figa
2018-06-06 8:46 ` Pavel Machek
2018-06-06 8:53 ` Tomasz Figa
2018-06-06 10:01 ` Pavel Machek
2018-06-06 16:57 ` Mauro Carvalho Chehab
2018-06-07 12:22 ` [PATCH, " Pavel Machek
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).