v4l2-compliance: add VIDIOC_ENUM_FRAMESIZES and VIDIOC_ENUM_FRAMEINTERVALS tests.
authorHans Verkuil <hans.verkuil@cisco.com>
Fri, 24 Jun 2011 10:34:28 +0000 (12:34 +0200)
committerHans Verkuil <hans.verkuil@cisco.com>
Fri, 24 Jun 2011 10:34:28 +0000 (12:34 +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

index dc55597..c06844e 100644 (file)
@@ -550,12 +550,11 @@ int main(int argc, char **argv)
        /* Format ioctls */
 
        printf("Format ioctls:\n");
-       printf("\ttest VIDIOC_ENUM_FMT: %s\n", ok(testEnumFormats(&node)));
+       printf("\ttest VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: %s\n", ok(testEnumFormats(&node)));
 
        /* TODO:
 
           VIDIOC_CROPCAP, VIDIOC_G/S_CROP
-          VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS
           VIDIOC_G/S_FBUF/OVERLAY
           VIDIOC_G/S/TRY_FMT
           VIDIOC_G/S_PARM
index b159bc2..e17bcc1 100644 (file)
@@ -91,6 +91,18 @@ static inline int test_ioctl(int fd, int cmd, void *arg)
        return wrapper ? v4l2_ioctl(fd, cmd, arg) : ioctl(fd, cmd, arg);
 }
 
+static inline int check_fract(const struct v4l2_fract *f)
+{
+       if (f->numerator && f->denominator)
+               return 0;
+       return 1;
+}
+
+static inline double fract2f(const struct v4l2_fract *f)
+{
+       return (double)f->numerator / (double)f->denominator;
+}
+
 int doioctl_name(struct node *node, unsigned long int request, void *parm, const char *name);
 #define doioctl(n, r, p) doioctl_name(n, r, p, #r)
 
index a25b6a8..852a097 100644 (file)
 #include "v4l2-compliance.h"
 
 
-int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
+static int testEnumFrameIntervals(struct node *node, __u32 pixfmt, __u32 w, __u32 h, bool valid)
+{
+       struct v4l2_frmivalenum frmival;
+       struct v4l2_frmival_stepwise *sw = &frmival.stepwise;
+       bool found_stepwise = false;
+       unsigned f = 0;
+       int ret;
+
+       for (;;) {
+               memset(&frmival, 0xff, sizeof(frmival));
+               frmival.index = f;
+               frmival.pixel_format = pixfmt;
+               frmival.width = w;
+               frmival.height = h;
+
+               ret = doioctl(node, VIDIOC_ENUM_FRAMEINTERVALS, &frmival);
+               if (f == 0 && ret == EINVAL) {
+                       if (valid)
+                               warn("found framesize %dx%d, but no frame intervals\n", w, h);
+                       return -ENOSYS;
+               }
+               if (ret == EINVAL)
+                       break;
+               if (ret)
+                       return fail("expected EINVAL, but got %d when enumerating frameinterval %d\n", ret, f);
+               ret = check_0(frmival.reserved, sizeof(frmival.reserved));
+               if (ret)
+                       return fail("frmival.reserved not zeroed\n");
+               if (frmival.pixel_format != pixfmt || frmival.index != f ||
+                               frmival.width != w || frmival.height != h)
+                       return fail("frmival.pixel_format, index, width or height changed\n");
+               switch (frmival.type) {
+               case V4L2_FRMIVAL_TYPE_DISCRETE:
+                       ret = check_fract(&frmival.discrete);
+                       if (found_stepwise)
+                               return fail("mixing discrete and stepwise is not allowed\n");
+                       break;
+               case V4L2_FRMIVAL_TYPE_CONTINUOUS:
+                       if (sw->step.numerator != 1 || sw->step.denominator != 1)
+                               return fail("invalid step for continuous frameinterval\n");
+                       /* fallthrough */
+               case V4L2_FRMIVAL_TYPE_STEPWISE:
+                       if (frmival.index)
+                               return fail("index must be 0 for stepwise/continuous frameintervals\n");
+                       found_stepwise = true;
+                       ret = check_fract(&sw->min);
+                       if (ret == 0)
+                               ret = check_fract(&sw->max);
+                       if (ret == 0)
+                               ret = check_fract(&sw->step);
+                       if (ret)
+                               return fail("invalid min, max or step for frameinterval %d\n", f);
+                       if (fract2f(&sw->min) > fract2f(&sw->max))
+                               return fail("min > max\n");
+                       if (fract2f(&sw->step) > fract2f(&sw->max) - fract2f(&sw->min))
+                               return fail("step > (max - min)\n");
+                       break;
+               default:
+                       return fail("frmival.type is invalid\n");
+               }
+               
+               f++;
+       }
+       if (!valid)
+               return fail("found frame intervals for invalid size %dx%d\n", w, h);
+       info("found %d frameintervals for pixel format %08x and size %dx%d\n", f, pixfmt, w, h);
+       return 0;
+}
+
+static int testEnumFrameSizes(struct node *node, __u32 pixfmt)
+{
+       struct v4l2_frmsizeenum frmsize;
+       struct v4l2_frmsize_stepwise *sw = &frmsize.stepwise;
+       bool found_stepwise = false;
+       unsigned f = 0;
+       int ret;
+
+       for (;;) {
+               memset(&frmsize, 0xff, sizeof(frmsize));
+               frmsize.index = f;
+               frmsize.pixel_format = pixfmt;
+
+               ret = doioctl(node, VIDIOC_ENUM_FRAMESIZES, &frmsize);
+               if (f == 0 && ret == EINVAL)
+                       return -ENOSYS;
+               if (ret == EINVAL)
+                       break;
+               if (ret)
+                       return fail("expected EINVAL, but got %d when enumerating framesize %d\n", ret, f);
+               ret = check_0(frmsize.reserved, sizeof(frmsize.reserved));
+               if (ret)
+                       return fail("frmsize.reserved not zeroed\n");
+               if (frmsize.pixel_format != pixfmt || frmsize.index != f)
+                       return fail("frmsize.pixel_format or index changed\n");
+               switch (frmsize.type) {
+               case V4L2_FRMSIZE_TYPE_DISCRETE:
+                       if (frmsize.discrete.width == 0 || frmsize.discrete.height == 0)
+                               return fail("invalid width/height for discrete framesize\n");
+                       if (found_stepwise)
+                               return fail("mixing discrete and stepwise is not allowed\n");
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       frmsize.discrete.width, frmsize.discrete.height, true);
+                       if (ret > 0)
+                               return ret;
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       frmsize.discrete.width + 1, frmsize.discrete.height, false);
+                       if (ret > 0)
+                               return ret;
+                       break;
+               case V4L2_FRMSIZE_TYPE_CONTINUOUS:
+                       if (frmsize.stepwise.step_width != 1 || frmsize.stepwise.step_height != 1)
+                               return fail("invalid step_width/height for continuous framesize\n");
+                       /* fallthrough */
+               case V4L2_FRMSIZE_TYPE_STEPWISE:
+                       if (frmsize.index)
+                               return fail("index must be 0 for stepwise/continuous framesizes\n");
+                       found_stepwise = true;
+                       if (!sw->min_width || !sw->min_height || !sw->step_width || !sw->step_height)
+                               return fail("0 for min_width/height or step_width/height\n");
+                       if (sw->min_width > sw->max_width || sw->min_height > sw->max_height)
+                               return fail("min_width/height > max_width/height\n");
+                       if (sw->step_width > sw->max_width - sw->min_width ||
+                           sw->step_height > sw->max_height - sw->min_height)
+                               return fail("step > max - min for width or height\n");
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       sw->min_width, sw->min_height, true);
+                       if (ret > 0)
+                               return ret;
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       sw->max_width, sw->max_height, true);
+                       if (ret > 0)
+                               return ret;
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       sw->min_width - 1, sw->min_height, false);
+                       if (ret > 0)
+                               return ret;
+                       ret = testEnumFrameIntervals(node, pixfmt,
+                                       sw->max_width, sw->max_height + 1, false);
+                       if (ret > 0)
+                               return ret;
+                       break;
+               default:
+                       return fail("frmsize.type is invalid\n");
+               }
+               
+               f++;
+       }
+       info("found %d framesizes for pixel format %08x\n", f, pixfmt);
+       return 0;
+}
+
+static int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
 {
        struct v4l2_fmtdesc fmtdesc;
-       int f = 0;
+       unsigned f = 0;
        int ret;
 
        for (;;) {
@@ -53,6 +204,8 @@ int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
                ret = check_0(fmtdesc.reserved, sizeof(fmtdesc.reserved));
                if (ret)
                        return fail("fmtdesc.reserved not zeroed\n");
+               if (fmtdesc.index != f)
+                       return fail("fmtdesc.index was modified\n");
                ret = check_ustring(fmtdesc.description, sizeof(fmtdesc.description));
                if (ret)
                        return fail("fmtdesc.description not set\n");
@@ -62,6 +215,11 @@ int testEnumFormatsType(struct node *node, enum v4l2_buf_type type)
                        return fail("drivers must never set the emulated flag\n");
                if (fmtdesc.flags & ~(V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_EMULATED))
                        return fail("unknown flag %08x returned\n", fmtdesc.flags);
+               ret = testEnumFrameSizes(node, fmtdesc.pixelformat);
+               if (ret > 0)
+                       return ret;
+               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++;
        }
        info("found %d formats for buftype %d\n", f, type);
@@ -151,5 +309,12 @@ int testEnumFormats(struct node *node)
                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;
 }