v4l2-compliance: add VIDIOC_G_FMT compliance tests.
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 27 Jun 2011 09:36:09 +0000 (11:36 +0200)
committerHans Verkuil <hans.verkuil@cisco.com>
Mon, 27 Jun 2011 09:36:09 +0000 (11:36 +0200)
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
utils/v4l2-compliance/v4l2-compliance.cpp
utils/v4l2-compliance/v4l2-compliance.h
utils/v4l2-compliance/v4l2-test-formats.cpp
utils/v4l2-ctl/v4l2-ctl.cpp

index c06844e64d2df0bc779d0060346fc1af96aee9b5..b711635971e7b35001ab5943fe33c4cdadfe87c4 100644 (file)
@@ -159,6 +159,36 @@ std::string cap2s(unsigned cap)
        return s;
 }
 
+std::string buftype2s(int type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return "Video Capture";
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               return "Video Capture Multiplanar";
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return "Video Output";
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               return "Video Output Multiplanar";
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               return "Video Overlay";
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+               return "VBI Capture";
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               return "VBI Output";
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+               return "Sliced VBI Capture";
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               return "Sliced VBI Output";
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               return "Video Output Overlay";
+       case V4L2_BUF_TYPE_PRIVATE:
+               return "Private";
+       default:
+               return std::string("Unknown");
+       }
+}
+
 const char *ok(int res)
 {
        static char buf[100];
@@ -417,6 +447,7 @@ int main(int argc, char **argv)
                node.fd = radio_node.fd;
                device = radio_device;
                node.is_radio = true;
+               printf("is radio\n");
        } else if (vbi_node.fd >= 0) {
                node.fd = vbi_node.fd;
                device = vbi_device;
@@ -551,12 +582,13 @@ int main(int argc, char **argv)
 
        printf("Format ioctls:\n");
        printf("\ttest VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: %s\n", ok(testEnumFormats(&node)));
+       printf("\ttest VIDIOC_G_FMT: %s\n", ok(testFormats(&node)));
 
        /* TODO:
 
           VIDIOC_CROPCAP, VIDIOC_G/S_CROP
           VIDIOC_G/S_FBUF/OVERLAY
-          VIDIOC_G/S/TRY_FMT
+          VIDIOC_S/TRY_FMT
           VIDIOC_G/S_PARM
           VIDIOC_G/S_JPEGCOMP
           VIDIOC_SLICED_VBI_CAP
index e17bcc17d67f6134ef93c110904332dfe02599f2..dcd0aec8fae02cf588ded18c282e3f439a90f2c4 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <string>
 #include <list>
+#include <set>
 #include <linux/videodev2.h>
 #include <libv4l2.h>
 
@@ -37,6 +38,7 @@ struct test_queryctrl: v4l2_queryctrl {
 };
 
 typedef std::list<test_queryctrl> qctrl_list;
+typedef std::set<__u32> pixfmt_set;
 
 struct node {
        int fd;
@@ -55,6 +57,7 @@ struct node {
        unsigned std_controls;
        unsigned priv_controls;
        qctrl_list controls;
+       pixfmt_set buftype_pixfmts[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE + 1];
 };
 
 #define info(fmt, args...)                                     \
@@ -76,6 +79,12 @@ struct node {
        1;                                      \
 })
 
+#define fail_on_test(test)                                     \
+       do {                                                    \
+               if (test)                                       \
+               return fail("%s(%d): %s\n", __FILE__, __LINE__, #test); \
+       } while (0)
+
 static inline int test_open(const char *file, int oflag)
 {
        return wrapper ? v4l2_open(file, oflag) : open(file, oflag);
@@ -107,6 +116,12 @@ int doioctl_name(struct node *node, unsigned long int request, void *parm, const
 #define doioctl(n, r, p) doioctl_name(n, r, p, #r)
 
 std::string cap2s(unsigned cap);
+std::string buftype2s(int type);
+static inline std::string buftype2s(enum v4l2_buf_type type)
+{
+       return buftype2s((int)type);
+}
+
 const char *ok(int res);
 int check_string(const char *s, size_t len);
 int check_ustring(const __u8 *s, int len);
@@ -143,5 +158,6 @@ int testCustomTimings(struct node *node);
 
 // Format ioctl tests
 int testEnumFormats(struct node *node);
+int testFormats(struct node *node);
 
 #endif
index 852a09726fc5040d5a60f3b3eecf096b5ce771b2..6fc23e2baeddff0360ad4def5528187b99c14835 100644 (file)
 #include <ctype.h>
 #include <errno.h>
 #include <sys/ioctl.h>
+#include <assert.h>
 #include "v4l2-compliance.h"
 
+static const __u32 buftype2cap[] = {
+       0,
+       V4L2_CAP_VIDEO_CAPTURE,
+       V4L2_CAP_VIDEO_OUTPUT,
+       V4L2_CAP_VIDEO_OVERLAY,
+       V4L2_CAP_VBI_CAPTURE,
+       V4L2_CAP_VBI_OUTPUT,
+       V4L2_CAP_SLICED_VBI_CAPTURE,
+       V4L2_CAP_SLICED_VBI_OUTPUT,
+       V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
+       // To be discussed
+       V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_CAPTURE,
+       V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_OUTPUT,
+};
 
 static int testEnumFrameIntervals(struct node *node, __u32 pixfmt, __u32 w, __u32 h, bool valid)
 {
@@ -185,6 +200,7 @@ static int testEnumFrameSizes(struct node *node, __u32 pixfmt)
 
 static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
 {
+       pixfmt_set &set = node->buftype_pixfmts[type];
        struct v4l2_fmtdesc fmtdesc;
        unsigned f = 0;
        int ret;
@@ -206,6 +222,8 @@ static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
                        return fail("fmtdesc.reserved not zeroed\n");
                if (fmtdesc.index != f)
                        return fail("fmtdesc.index was modified\n");
+               if (fmtdesc.type != type)
+                       return fail("fmtdesc.type was modified\n");
                ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
                if (ret)
                        return fail("fmtdesc.description not set\n");
@@ -221,6 +239,13 @@ static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
                if (ret == 0 && !(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)))
                        return fail("found framesizes when no video capture is supported\n");
                f++;
+               if (type == V4L2_BUF_TYPE_PRIVATE)
+                       continue;
+               // Update array in v4l2-compliance.h if new buffer types are added
+               assert(type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+               if (set.find(fmtdesc.pixelformat) != set.end())
+                       return fail("duplicate format %08x\n", fmtdesc.pixelformat);
+               set.insert(fmtdesc.pixelformat);
        }
        info("found %d formats for buftype %d\n", f, type);
        return 0;
@@ -228,93 +253,190 @@ static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
 
 int testEnumFormats(struct node *node)
 {
+       static const __u32 buftype2cap[] = {
+               0,
+               V4L2_CAP_VIDEO_CAPTURE,
+               V4L2_CAP_VIDEO_OUTPUT,
+               V4L2_CAP_VIDEO_OVERLAY,
+               V4L2_CAP_VBI_CAPTURE,
+               V4L2_CAP_VBI_OUTPUT,
+               V4L2_CAP_SLICED_VBI_CAPTURE,
+               V4L2_CAP_SLICED_VBI_OUTPUT,
+               V4L2_CAP_VIDEO_OUTPUT_OVERLAY,
+               V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+               V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+       };
+       int type;
        int ret;
 
-       ret = testEnumFormatsType(node, (enum v4l2_buf_type)0);
-       if (ret != -ENOSYS)
-               return fail("Buffer type 0 accepted!\n");
-
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       if (ret > 0)
-               return ret;
-       if (ret && (node->caps & V4L2_CAP_VIDEO_CAPTURE))
-               return fail("Video capture cap set, but no capture formats defined\n");
-       if (!ret && !(node->caps & V4L2_CAP_VIDEO_CAPTURE))
-               return fail("Video capture cap not set, but capture formats defined\n");
-
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
-       if (ret > 0)
-               return ret;
-       if (ret && (node->caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE))
-               return fail("MPlane Video capture cap set, but no multiplanar capture formats defined\n");
-       if (!ret && !(node->caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE))
-               return fail("MPlane Video capture cap not set, but multiplanar capture formats defined\n");
-
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_OVERLAY);
-       if (ret > 0)
-               return ret;
-       if (ret && (node->caps & V4L2_CAP_VIDEO_OVERLAY))
-               return fail("Video overlay cap set, but no overlay formats defined\n");
-       if (!ret && !(node->caps & V4L2_CAP_VIDEO_OVERLAY))
-               return fail("Video overlay cap not set, but overlay formats defined\n");
-
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VBI_CAPTURE);
-       if (ret > 0)
-               return ret;
-       if (!ret)
-               return fail("Buffer type VBI_CAPTURE allowed!\n");
+       for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
+               ret = testEnumFormatsType(node, (enum v4l2_buf_type)type);
+               if (ret > 0)
+                       return ret;
+               switch (type) {
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+               case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+               case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+                       if (ret < 0 && (node->caps & buftype2cap[type]))
+                               return fail("%s cap set, but no %s formats defined\n",
+                                               buftype2s(type).c_str(), buftype2s(type).c_str());
+                       if (!ret && !(node->caps & buftype2cap[type]))
+                               return fail("%s cap not set, but %s formats defined\n",
+                                               buftype2s(type).c_str(), buftype2s(type).c_str());
+                       break;
+               default:
+                       if (!ret)
+                               return fail("Buffer type %s not allowed!\n", buftype2s(type).c_str());
+                       break;
+               }
+       }
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE);
+       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
        if (ret > 0)
                return ret;
        if (!ret)
-               return fail("Buffer type SLICED_VBI_CAPTURE allowed!\n");
+               warn("Buffer type PRIVATE allowed!\n");
+               
+       ret = testEnumFrameSizes(node, 0x20202020);
+       if (ret >= 0)
+               return fail("Accepted framesize for invalid format\n");
+       ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false);
+       if (ret >= 0)
+               return fail("Accepted frameinterval for invalid format\n");
+       return 0;
+}
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_OUTPUT);
-       if (ret > 0)
-               return ret;
-       if (ret && (node->caps & V4L2_CAP_VIDEO_OUTPUT))
-               return fail("Video output cap set, but no output formats defined\n");
-       if (!ret && !(node->caps & V4L2_CAP_VIDEO_OUTPUT))
-               return fail("Video output cap not set, but output formats defined\n");
+static int testFormatsType(struct node *node, enum v4l2_buf_type type)
+{
+       pixfmt_set &set = node->buftype_pixfmts[type];
+       pixfmt_set *set_splane;
+       struct v4l2_format fmt;
+       struct v4l2_pix_format &pix = fmt.fmt.pix;
+       struct v4l2_pix_format_mplane &pix_mp = fmt.fmt.pix_mp;
+       struct v4l2_window &win = fmt.fmt.win;
+       struct v4l2_vbi_format &vbi = fmt.fmt.vbi;
+       struct v4l2_sliced_vbi_format &sliced = fmt.fmt.sliced;
+       __u32 service_set = 0;
+       unsigned cnt = 0;
+       int ret;
+       
+       memset(&fmt, 0xff, sizeof(fmt));
+       fmt.type = type;
+       ret = doioctl(node, VIDIOC_G_FMT, &fmt);
+       if (ret == EINVAL)
+               return -ENOSYS;
+       if (ret)
+               return fail("expected EINVAL, but got %d when getting format for buftype %d\n", ret, type);
+       fail_on_test(fmt.type != type);
+       
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               fail_on_test(!pix.width || !pix.height);
+               if (set.find(pix.pixelformat) == set.end())
+                       return fail("unknown pixelformat %08x for buftype %d\n",
+                                       pix.pixelformat, type);
+               fail_on_test(pix.bytesperline && pix.bytesperline < pix.width);
+               fail_on_test(!pix.sizeimage);
+               fail_on_test(!pix.colorspace);
+               if (pix.priv)
+                       warn("priv is non-zero!\n");
+               break;
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+               fail_on_test(!pix_mp.width || !pix_mp.height);
+               set_splane = &node->buftype_pixfmts[type - 8];
+               if (set.find(pix_mp.pixelformat) == set.end() &&
+                   set_splane->find(pix_mp.pixelformat) == set_splane->end())
+                       return fail("unknown pixelformat %08x for buftype %d\n",
+                                       pix_mp.pixelformat, type);
+               fail_on_test(!pix_mp.colorspace);
+               ret = check_0(pix_mp.reserved, sizeof(pix_mp.reserved));
+               if (ret)
+                       return fail("pix_mp.reserved not zeroed\n");
+               fail_on_test(pix_mp.num_planes == 0 || pix_mp.num_planes >= VIDEO_MAX_PLANES);
+               for (int i = 0; i < pix_mp.num_planes; i++) {
+                       struct v4l2_plane_pix_format &pfmt = pix_mp.plane_fmt[i];
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-       if (ret > 0)
-               return ret;
-       if (ret && (node->caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE))
-               return fail("MPlane Video output cap set, but no multiplanar output formats defined\n");
-       if (!ret && !(node->caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE))
-               return fail("MPlane Video output cap not set, but multiplanar output formats defined\n");
+                       ret = check_0(pfmt.reserved, sizeof(pfmt.reserved));
+                       if (ret)
+                               return fail("pix_mp.plane_fmt[%d].reserved not zeroed\n", i);
+                       fail_on_test(!pfmt.sizeimage);
+                       fail_on_test(pfmt.bytesperline && pfmt.bytesperline < pix_mp.width);
+               }
+               break;
+       case V4L2_BUF_TYPE_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_VBI_OUTPUT:
+               fail_on_test(!vbi.sampling_rate);
+               fail_on_test(!vbi.samples_per_line);
+               fail_on_test(vbi.sample_format != V4L2_PIX_FMT_GREY);
+               fail_on_test(vbi.offset > vbi.samples_per_line);
+               ret = check_0(vbi.reserved, sizeof(vbi.reserved));
+               if (ret)
+                       return fail("vbi.reserved not zeroed\n");
+               fail_on_test(!vbi.count[0] || !vbi.count[1]);
+               fail_on_test(vbi.flags & ~(V4L2_VBI_UNSYNC | V4L2_VBI_INTERLACED));
+               if (vbi.flags & V4L2_VBI_INTERLACED)
+                       fail_on_test(vbi.count[0] != vbi.count[1]);
+               break;
+       case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+       case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+               ret = check_0(sliced.reserved, sizeof(sliced.reserved));
+               if (ret)
+                       return fail("sliced.reserved not zeroed\n");
+               fail_on_test(sliced.service_lines[0][0] || sliced.service_lines[1][0]);
+               for (int f = 0; f < 2; f++) {
+                       for (int i = 0; i < 24; i++) {
+                               if (sliced.service_lines[f][i])
+                                       cnt++;
+                               service_set |= sliced.service_lines[f][i];
+                       }
+               }
+               fail_on_test(sliced.io_size < sizeof(struct v4l2_sliced_vbi_data) * cnt);
+               fail_on_test(sliced.service_set != service_set);
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
+               fail_on_test(win.field != V4L2_FIELD_ANY &&
+                            win.field != V4L2_FIELD_TOP &&
+                            win.field != V4L2_FIELD_BOTTOM &&
+                            win.field != V4L2_FIELD_INTERLACED);
+               for (struct v4l2_clip *clip = win.clips; clip; win.clipcount--) {
+                       fail_on_test(clip == NULL);
+                       clip = clip->next;
+               }
+               fail_on_test(win.clipcount);
+               break;
+       case V4L2_BUF_TYPE_PRIVATE:
+               break;
+       }
+       return 0;
+}
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY);
-       if (ret > 0)
-               return ret;
-       if (!ret)
-               return fail("Buffer type VIDEO_OUTPUT_OVERLAY allowed!\n");
+int testFormats(struct node *node)
+{
+       int type;
+       int ret;
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_VBI_OUTPUT);
-       if (ret > 0)
-               return ret;
-       if (!ret)
-               return fail("Buffer type VBI_OUTPUT allowed!\n");
+       for (type = 0; type <= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; type++) {
+               ret = testFormatsType(node, (enum v4l2_buf_type)type);
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT);
-       if (ret > 0)
-               return ret;
-       if (!ret)
-               return fail("Buffer type SLICED_VBI_OUTPUT allowed!\n");
+               if (ret > 0)
+                       return ret;
+               if (ret && (node->caps & buftype2cap[type]))
+                       return fail("%s cap set, but no %s formats defined\n",
+                                       buftype2s(type).c_str(), buftype2s(type).c_str());
+               if (!ret && !(node->caps & buftype2cap[type]))
+                       return fail("%s cap not set, but %s formats defined\n",
+                                       buftype2s(type).c_str(), buftype2s(type).c_str());
+       }
 
-       ret = testEnumFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
+       ret = testFormatsType(node, V4L2_BUF_TYPE_PRIVATE);
        if (ret > 0)
                return ret;
        if (!ret)
                warn("Buffer type PRIVATE allowed!\n");
-               
-       ret = testEnumFrameSizes(node, 0x20202020);
-       if (ret >= 0)
-               return fail("Accepted framesize for invalid format\n");
-       ret = testEnumFrameIntervals(node, 0x20202020, 640, 480, false);
-       if (ret >= 0)
-               return fail("Accepted frameinterval for invalid format\n");
        return 0;
 }
index 227ce1a6a683b2a407adae4edaa1cc73b78ea78d..44cb1533143359211335b84b37979af24f8399e0 100644 (file)
@@ -584,6 +584,8 @@ static std::string num2s(unsigned num)
 static std::string buftype2s(int type)
 {
        switch (type) {
+       case 0:
+               return "Invalid";
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                return "Video Capture";
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: