From f024f5bcee3531942c1d0cc306736dff865f4baf 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 2/6] 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 2f685a7..b30840a 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 
 |