From d1ae1546cb879c42245b358ff72797cdd0018c42 Mon Sep 17 00:00:00 2001
|
From: Jeffy Chen <jeffy.chen@rock-chips.com>
|
Date: Fri, 27 Sep 2019 18:52:24 +0800
|
Subject: [PATCH 3/8] libv4l: mplane: Filter out multiplane formats
|
|
The multiplane formats are not supported here, reporting them to the
|
userspace might cause unexpected results.
|
|
Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
|
---
|
lib/libv4l-mplane/libv4l-mplane.c | 149 ++++++++++++++++++++++++++++--
|
1 file changed, 141 insertions(+), 8 deletions(-)
|
|
diff --git a/lib/libv4l-mplane/libv4l-mplane.c b/lib/libv4l-mplane/libv4l-mplane.c
|
index 2f685a73..b30840a3 100644
|
--- a/lib/libv4l-mplane/libv4l-mplane.c
|
+++ b/lib/libv4l-mplane/libv4l-mplane.c
|
@@ -49,6 +49,15 @@
|
#define PLUGIN_PUBLIC
|
#endif
|
|
+#define MPLANE_MAX_FORMATS 32
|
+
|
+struct mplane_formats {
|
+ struct v4l2_format formats[MPLANE_MAX_FORMATS];
|
+ int index_map[MPLANE_MAX_FORMATS];
|
+ unsigned int num_formats;
|
+ int def_format;
|
+};
|
+
|
struct mplane_plugin {
|
union {
|
struct {
|
@@ -57,6 +66,9 @@ struct mplane_plugin {
|
};
|
unsigned int mplane;
|
};
|
+
|
+ struct mplane_formats capture_formats;
|
+ struct mplane_formats output_formats;
|
};
|
|
#define SIMPLE_CONVERT_IOCTL(fd, cmd, arg, __struc) ({ \
|
@@ -75,6 +87,55 @@ struct mplane_plugin {
|
__ret; \
|
})
|
|
+/* Setup supported(single plane) formats */
|
+static void mplane_setup_formats(int fd, struct mplane_formats *formats,
|
+ enum v4l2_buf_type type)
|
+{
|
+ int ret, n;
|
+
|
+ formats->num_formats = 0;
|
+ formats->def_format = -1;
|
+
|
+ for (n = 0; formats->num_formats < MPLANE_MAX_FORMATS; n++) {
|
+ struct v4l2_fmtdesc fmtdesc = { 0 };
|
+ struct v4l2_format format = { 0 };
|
+
|
+ fmtdesc.type = type;
|
+ fmtdesc.index = n;
|
+
|
+ ret = SYS_IOCTL(fd, VIDIOC_ENUM_FMT, &fmtdesc);
|
+ if (ret < 0)
|
+ break;
|
+
|
+ //TODO: Is there any better way to detect it?
|
+
|
+ format.type = type;
|
+ format.fmt.pix.pixelformat = fmtdesc.pixelformat;
|
+
|
+ /* Allow error since not all the drivers support try_fmt */
|
+ SYS_IOCTL(fd, VIDIOC_TRY_FMT, &format);
|
+
|
+ switch (format.fmt.pix_mp.num_planes) {
|
+ case 1:
|
+ if (formats->def_format < 0)
|
+ formats->def_format = formats->num_formats;
|
+
|
+ /* fall-through */
|
+ case 0:
|
+ /**
|
+ * Allow 0 planes since not all the drivers would set
|
+ * num_planes in try_fmt.
|
+ */
|
+ formats->formats[formats->num_formats] = format;
|
+ formats->index_map[formats->num_formats] = n;
|
+ formats->num_formats++;
|
+ break;
|
+ default:
|
+ break;
|
+ }
|
+ }
|
+}
|
+
|
static void *plugin_init(int fd)
|
{
|
struct v4l2_capability cap;
|
@@ -92,13 +153,21 @@ static void *plugin_init(int fd)
|
}
|
|
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) &&
|
- (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE))
|
+ (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE)) {
|
plugin.mplane_capture = 1;
|
|
+ mplane_setup_formats(fd, &plugin.capture_formats,
|
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
|
+ }
|
+
|
if (!(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) &&
|
- (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE))
|
+ (cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE)) {
|
plugin.mplane_output = 1;
|
|
+ mplane_setup_formats(fd, &plugin.output_formats,
|
+ V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
|
+ }
|
+
|
/* Device doesn't need it. return NULL to disable the plugin */
|
if (!plugin.mplane)
|
return NULL;
|
@@ -175,6 +244,39 @@ static int convert_type(int type)
|
}
|
}
|
|
+static int enum_fmt_ioctl(struct mplane_plugin *plugin, int fd,
|
+ unsigned long int cmd,
|
+ struct v4l2_fmtdesc *arg)
|
+{
|
+ struct mplane_formats *formats;
|
+ int ret, index;
|
+
|
+ switch (arg->type) {
|
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
+ formats = &plugin->capture_formats;
|
+ break;
|
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
+ formats = &plugin->output_formats;
|
+ break;
|
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
+ errno = EINVAL;
|
+ return -1;
|
+ default:
|
+ return SYS_IOCTL(fd, cmd, arg);
|
+ }
|
+
|
+ if (arg->index >= formats->num_formats)
|
+ return -EINVAL;
|
+
|
+ index = arg->index;
|
+ arg->index = formats->index_map[index];
|
+ ret = SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_fmtdesc);
|
+ arg->index = index;
|
+
|
+ return ret;
|
+}
|
+
|
static void sanitize_format(struct v4l2_format *fmt)
|
{
|
unsigned int offset;
|
@@ -201,19 +303,23 @@ static void sanitize_format(struct v4l2_format *fmt)
|
sizeof(fmt->fmt.pix) - offset);
|
}
|
|
-static int try_set_fmt_ioctl(int fd, unsigned long int cmd,
|
+static int try_set_fmt_ioctl(struct mplane_plugin *plugin, int fd,
|
+ unsigned long int cmd,
|
struct v4l2_format *arg)
|
{
|
+ struct mplane_formats *formats;
|
struct v4l2_format fmt = { 0 };
|
struct v4l2_format *org = arg;
|
- int ret;
|
+ int ret, i;
|
|
switch (arg->type) {
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
+ formats = &plugin->capture_formats;
|
break;
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
+ formats = &plugin->output_formats;
|
break;
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
@@ -223,6 +329,15 @@ static int try_set_fmt_ioctl(int fd, unsigned long int cmd,
|
return SYS_IOCTL(fd, cmd, arg);
|
}
|
|
+ /* Filter out unsupported formats */
|
+ for (i = 0; i < formats->num_formats; i++) {
|
+ if (formats->formats[i].fmt.pix_mp.pixelformat ==
|
+ arg->fmt.pix.pixelformat)
|
+ break;
|
+ }
|
+ if (i == formats->num_formats)
|
+ return -EINVAL;
|
+
|
sanitize_format(org);
|
|
fmt.fmt.pix_mp.width = org->fmt.pix.width;
|
@@ -254,6 +369,10 @@ static int try_set_fmt_ioctl(int fd, unsigned long int cmd,
|
org->fmt.pix.sizeimage = fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
|
org->fmt.pix.flags = fmt.fmt.pix_mp.flags;
|
|
+ /* Now we can use the driver's default format */
|
+ if (cmd == VIDIOC_S_FMT)
|
+ formats->def_format = -1;
|
+
|
return 0;
|
}
|
|
@@ -316,8 +435,10 @@ static int create_bufs_ioctl(int fd, unsigned long int cmd,
|
return ret;
|
}
|
|
-static int get_fmt_ioctl(int fd, unsigned long int cmd, struct v4l2_format *arg)
|
+static int get_fmt_ioctl(struct mplane_plugin *plugin, int fd,
|
+ unsigned long int cmd, struct v4l2_format *arg)
|
{
|
+ struct mplane_formats *formats;
|
struct v4l2_format fmt = { 0 };
|
struct v4l2_format *org = arg;
|
int ret;
|
@@ -325,9 +446,11 @@ static int get_fmt_ioctl(int fd, unsigned long int cmd, struct v4l2_format *arg)
|
switch (arg->type) {
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
+ formats = &plugin->capture_formats;
|
break;
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
|
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
+ formats = &plugin->output_formats;
|
break;
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
|
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
|
@@ -337,10 +460,18 @@ static int get_fmt_ioctl(int fd, unsigned long int cmd, struct v4l2_format *arg)
|
return SYS_IOCTL(fd, cmd, arg);
|
}
|
|
+ /* Use default format */
|
+ if (formats->def_format >= 0 &&
|
+ formats->def_format < formats->num_formats) {
|
+ fmt = formats->formats[formats->def_format];
|
+ goto out;
|
+ }
|
+
|
ret = SYS_IOCTL(fd, cmd, &fmt);
|
if (ret)
|
return ret;
|
|
+out:
|
memset(&org->fmt.pix, 0, sizeof(org->fmt.pix));
|
org->fmt.pix.width = fmt.fmt.pix_mp.width;
|
org->fmt.pix.height = fmt.fmt.pix_mp.height;
|
@@ -411,16 +542,18 @@ static int buf_ioctl(int fd, unsigned long int cmd, struct v4l2_buffer *arg)
|
static int plugin_ioctl(void *dev_ops_priv, int fd,
|
unsigned long int cmd, void *arg)
|
{
|
+ struct mplane_plugin *plugin = dev_ops_priv;
|
+
|
switch (cmd) {
|
case VIDIOC_QUERYCAP:
|
return querycap_ioctl(fd, cmd, arg);
|
case VIDIOC_TRY_FMT:
|
case VIDIOC_S_FMT:
|
- return try_set_fmt_ioctl(fd, cmd, arg);
|
+ return try_set_fmt_ioctl(plugin, fd, cmd, arg);
|
case VIDIOC_G_FMT:
|
- return get_fmt_ioctl(fd, cmd, arg);
|
+ return get_fmt_ioctl(plugin, fd, cmd, arg);
|
case VIDIOC_ENUM_FMT:
|
- return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_fmtdesc);
|
+ return enum_fmt_ioctl(plugin, fd, cmd, arg);
|
case VIDIOC_S_PARM:
|
case VIDIOC_G_PARM:
|
return SIMPLE_CONVERT_IOCTL(fd, cmd, arg, v4l2_streamparm);
|
--
|
2.20.1
|