v4l2-compliance: add tests for multiplanar capture.
authorHans Verkuil <hans.verkuil@cisco.com>
Mon, 17 Feb 2014 21:43:30 +0000 (22:43 +0100)
committerHans Verkuil <hans.verkuil@cisco.com>
Mon, 17 Feb 2014 21:43:30 +0000 (22:43 +0100)
Note that the multiplanar dmabuf test code and multiplanar expbuf have
not been tested.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
utils/v4l2-compliance/v4l2-test-buffers.cpp

index 6d61740..c00e9f0 100644 (file)
@@ -89,6 +89,16 @@ static std::string field2s(unsigned val)
        }
 }
 
+static unsigned process_buf(const v4l2_buffer &buf, v4l2_plane *planes)
+{
+       if (V4L2_TYPE_IS_MULTIPLANAR(buf.type))
+               return buf.length;
+       planes->bytesused = buf.bytesused;
+       planes->length = buf.length;
+       planes->m.userptr = buf.m.userptr;
+       return 1;
+}
+
 static int checkQueryBuf(struct node *node, const struct v4l2_buffer &buf,
                __u32 type, __u32 memory, unsigned index, enum QueryBufMode mode)
 {
@@ -137,7 +147,7 @@ static int checkQueryBuf(struct node *node, const struct v4l2_buffer &buf,
 
        if (mode == Dequeued || mode == Prepared) {
                if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
-                       fail_on_test(buf.length <= VIDEO_MAX_PLANES);
+                       fail_on_test(buf.length > VIDEO_MAX_PLANES);
                        for (unsigned p = 0; p < buf.length; p++) {
                                struct v4l2_plane *vp = buf.m.planes + p;
 
@@ -156,8 +166,18 @@ static int checkQueryBuf(struct node *node, const struct v4l2_buffer &buf,
        }
 
        if (mode == Dequeued) {
-               fail_on_test(!buf.bytesused);
-               fail_on_test(buf.bytesused > buf.length);
+               if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
+                       fail_on_test(buf.length > VIDEO_MAX_PLANES);
+                       for (unsigned p = 0; p < buf.length; p++) {
+                               struct v4l2_plane *vp = buf.m.planes + p;
+
+                               fail_on_test(!vp->bytesused);
+                               fail_on_test(vp->bytesused > vp->length);
+                       }
+               } else {
+                       fail_on_test(!buf.bytesused);
+                       fail_on_test(buf.bytesused > buf.length);
+               }
                fail_on_test(!buf.timestamp.tv_sec && !buf.timestamp.tv_usec);
                fail_on_test(buf.field == V4L2_FIELD_ALTERNATE);
                fail_on_test(buf.field == V4L2_FIELD_ANY);
@@ -350,6 +370,7 @@ int testReqBufs(struct node *node)
                        warn("VIDIOC_CREATE_BUFS not supported\n");
                        continue;
                }
+               fail_on_test(ret);
                fail_on_test(cbufs.count == 0);
                fail_on_test(cbufs.memory != bufs.memory);
                fail_on_test(cbufs.format.type != i);
@@ -406,6 +427,7 @@ static int setupMmap(struct node *node, struct v4l2_requestbuffers &bufs)
                struct v4l2_buffer buf;
                int ret;
 
+               memset(planes, 0, sizeof(planes));
                memset(&buf, 0, sizeof(buf));
                buf.type = bufs.type;
                buf.memory = bufs.memory;
@@ -416,17 +438,19 @@ static int setupMmap(struct node *node, struct v4l2_requestbuffers &bufs)
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
                fail_on_test(checkQueryBuf(node, buf, bufs.type, bufs.memory, i, Unqueued));
-
-               // Try a random offset
-               ptrs[i][0] = test_mmap(NULL, buf.length,
-                                 PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, buf.m.offset + 0xdeadbeef);
-               fail_on_test(ptrs[i][0] != MAP_FAILED);
-
-               // Now with the proper offset
-               ptrs[i][0] = test_mmap(NULL, buf.length,
-                                 PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, buf.m.offset);
-
-               fail_on_test(ptrs[i][0] == MAP_FAILED);
+               unsigned num_planes = process_buf(buf, planes);
+
+               for (unsigned p = 0; p < num_planes; p++) {
+                       // Try a random offset
+                       ptrs[i][p] = test_mmap(NULL, planes[p].length,
+                                       PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, planes[p].m.mem_offset + 0xdeadbeef);
+                       fail_on_test(ptrs[i][p] != MAP_FAILED);
+
+                       // Now with the proper offset
+                       ptrs[i][p] = test_mmap(NULL, planes[p].length,
+                                       PROT_READ | PROT_WRITE, MAP_SHARED, node->fd, planes[p].m.mem_offset);
+                       fail_on_test(ptrs[i][p] == MAP_FAILED);
+               }
 
                ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                fail_on_test(ret && ret != ENOTTY);
@@ -457,7 +481,10 @@ static int releaseMmap(struct node *node, struct v4l2_requestbuffers &bufs)
                        buf.length = VIDEO_MAX_PLANES;
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
-               munmap(ptrs[i][0], buf.length);
+               unsigned num_planes = process_buf(buf, planes);
+
+               for (unsigned p = 0; p < num_planes; p++)
+                       munmap(ptrs[i][p], planes[p].length);
        }
        return 0;
 }
@@ -466,10 +493,13 @@ static int captureBufs(struct node *node, const struct v4l2_requestbuffers &bufs
                       unsigned frame_count, bool use_poll)
 {
        int fd_flags = fcntl(node->fd, F_GETFL);
+       struct v4l2_plane planes[VIDEO_MAX_PLANES];
        struct v4l2_buffer buf;
        unsigned count = frame_count;
        int ret;
 
+       memset(planes, 0, sizeof(planes));
+       memset(&buf, 0, sizeof(buf));
        if (use_poll)
                fcntl(node->fd, F_SETFL, fd_flags | O_NONBLOCK);
        for (;;) {
@@ -486,6 +516,10 @@ static int captureBufs(struct node *node, const struct v4l2_requestbuffers &bufs
 
                buf.type = bufs.type;
                buf.memory = bufs.memory;
+               if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
+                       buf.m.planes = planes;
+                       buf.length = VIDEO_MAX_PLANES;
+               }
 
                ret = doioctl(node, VIDIOC_DQBUF, &buf);
                if (ret == EAGAIN)
@@ -520,7 +554,7 @@ int testMmap(struct node *node, unsigned frame_count)
        bool have_createbufs = true;
        int ret;
        
-       if (!(node->caps & V4L2_CAP_VIDEO_CAPTURE))
+       if (!(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
                return 0;
 
        memset(&input, 0, sizeof(input));
@@ -543,7 +577,9 @@ int testMmap(struct node *node, unsigned frame_count)
        }
 
        memset(&bufs, 0, sizeof(bufs));
-       bufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       bufs.type = (node->caps & V4L2_CAP_VIDEO_CAPTURE) ?
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE :
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        bufs.memory = V4L2_MEMORY_MMAP;
        ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
        if (ret) {
@@ -562,11 +598,18 @@ int testMmap(struct node *node, unsigned frame_count)
        fail_on_test(doioctl(node, VIDIOC_STREAMOFF, &bufs.type));
        last_seq = -1;
        field_nr = 1;
-       last_field = cur_fmt.fmt.pix.field;
 
        cbufs.format = cur_fmt;
-       cbufs.format.fmt.pix.height /= 2;
-       cbufs.format.fmt.pix.sizeimage /= 2;
+       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+               last_field = cur_fmt.fmt.pix_mp.field;
+               cbufs.format.fmt.pix_mp.height /= 2;
+               for (unsigned p = 0; p < cbufs.format.fmt.pix_mp.num_planes; p++)
+                       cbufs.format.fmt.pix_mp.plane_fmt[p].sizeimage /= 2;
+       } else {
+               last_field = cur_fmt.fmt.pix.field;
+               cbufs.format.fmt.pix.height /= 2;
+               cbufs.format.fmt.pix.sizeimage /= 2;
+       }
        cbufs.count = 1;
        cbufs.memory = bufs.memory;
        ret = doioctl(node, VIDIOC_CREATE_BUFS, &cbufs);
@@ -577,7 +620,12 @@ int testMmap(struct node *node, unsigned frame_count)
        fail_on_test(testQueryBuf(node, cur_fmt.type, bufs.count));
        if (have_createbufs) {
                cbufs.format = cur_fmt;
-               cbufs.format.fmt.pix.sizeimage *= 2;
+               if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                       for (unsigned p = 0; p < cbufs.format.fmt.pix_mp.num_planes; p++)
+                               cbufs.format.fmt.pix_mp.plane_fmt[p].sizeimage *= 2;
+               } else {
+                       cbufs.format.fmt.pix.sizeimage *= 2;
+               }
                cbufs.count = 1;
                cbufs.memory = bufs.memory;
                fail_on_test(doioctl(node, VIDIOC_CREATE_BUFS, &cbufs));
@@ -603,6 +651,7 @@ static int setupUserPtr(struct node *node, struct v4l2_requestbuffers &bufs)
                struct v4l2_buffer buf;
                int ret;
 
+               memset(planes, 0, sizeof(planes));
                memset(&buf, 0, sizeof(buf));
                buf.type = bufs.type;
                buf.memory = bufs.memory;
@@ -613,21 +662,41 @@ static int setupUserPtr(struct node *node, struct v4l2_requestbuffers &bufs)
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
                fail_on_test(checkQueryBuf(node, buf, bufs.type, bufs.memory, i, Unqueued));
-               ptrs[i][0] = malloc(buf.length);
-               fail_on_test(ptrs[i][0] == NULL);
+               unsigned num_planes = process_buf(buf, planes);
+
+               for (unsigned p = 0; p < num_planes; p++) {
+                       ptrs[i][p] = malloc(planes[p].length);
+                       fail_on_test(ptrs[i][p] == NULL);
+               }
 
                ret = ENOTTY;
                // Try to use VIDIOC_PREPARE_BUF for every other buffer
                if ((i & 1) == 0) {
-                       buf.m.userptr = 0;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr = 0;
+                       } else {
+                               buf.m.userptr = 0;
+                       }
                        ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                        fail_on_test(!ret);
 
-                       buf.m.userptr = (unsigned long)ptrs[i][0] + buf.length / 2;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr =
+                                               (unsigned long)ptrs[i][p] + 0xdeadbeef;
+                       } else {
+                               buf.m.userptr = (unsigned long)ptrs[i][0] + 0xdeadbeef;
+                       }
                        ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                        fail_on_test(!ret);
 
-                       buf.m.userptr = (unsigned long)ptrs[i][0];
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr = (unsigned long)ptrs[i][p];
+                       } else {
+                               buf.m.userptr = (unsigned long)ptrs[i][0];
+                       }
                        ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                        fail_on_test(ret && ret != ENOTTY);
 
@@ -637,15 +706,31 @@ static int setupUserPtr(struct node *node, struct v4l2_requestbuffers &bufs)
                        }
                }
                if (ret == ENOTTY) {
-                       buf.m.userptr = 0;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr = 0;
+                       } else {
+                               buf.m.userptr = 0;
+                       }
                        ret = doioctl(node, VIDIOC_QBUF, &buf);
                        fail_on_test(!ret);
 
-                       buf.m.userptr = (unsigned long)ptrs[i][0] + buf.length / 2;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr =
+                                               (unsigned long)ptrs[i][p] + 0xdeadbeef;
+                       } else {
+                               buf.m.userptr = (unsigned long)ptrs[i][0] + 0xdeadbeef;
+                       }
                        ret = doioctl(node, VIDIOC_QBUF, &buf);
                        fail_on_test(!ret);
 
-                       buf.m.userptr = (unsigned long)ptrs[i][0];
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.userptr = (unsigned long)ptrs[i][p];
+                       } else {
+                               buf.m.userptr = (unsigned long)ptrs[i][0];
+                       }
                }
 
                fail_on_test(doioctl(node, VIDIOC_QBUF, &buf));
@@ -658,7 +743,10 @@ static int setupUserPtr(struct node *node, struct v4l2_requestbuffers &bufs)
 static int releaseUserPtr(struct node *node, struct v4l2_requestbuffers &bufs)
 {
        for (unsigned i = 0; i < bufs.count; i++)
-               free(ptrs[i][0]);
+               for (unsigned p = 0; p < VIDEO_MAX_PLANES; p++) {
+                       free(ptrs[i][p]);
+                       ptrs[i][p] = NULL;
+               }
        return 0;
 }
 
@@ -668,11 +756,13 @@ int testUserPtr(struct node *node, unsigned frame_count)
        bool can_stream = node->caps & V4L2_CAP_STREAMING;
        int ret;
        
-       if (!(node->caps & V4L2_CAP_VIDEO_CAPTURE))
+       if (!(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
                return 0;
 
        memset(&bufs, 0, sizeof(bufs));
-       bufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       bufs.type = (node->caps & V4L2_CAP_VIDEO_CAPTURE) ?
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE :
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        bufs.memory = V4L2_MEMORY_USERPTR;
        ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
        if (ret) {
@@ -686,7 +776,10 @@ int testUserPtr(struct node *node, unsigned frame_count)
        fail_on_test(doioctl(node, VIDIOC_STREAMOFF, &bufs.type));
        last_seq = -1;
        field_nr = 1;
-       last_field = cur_fmt.fmt.pix.field;
+       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type))
+               last_field = cur_fmt.fmt.pix_mp.field;
+       else
+               last_field = cur_fmt.fmt.pix.field;
 
        fail_on_test(setupUserPtr(node, bufs));
 
@@ -709,15 +802,18 @@ int testExpBuf(struct node *node)
        struct v4l2_buffer buf;
        int err = 0;
 
-       if (!(node->caps & V4L2_CAP_VIDEO_CAPTURE))
+       if (!(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
                return 0;
        if (!(node->valid_memorytype & (1 << V4L2_MEMORY_MMAP)))
                return ENOTTY;
 
+       memset(planes, 0, sizeof(planes));
        memset(&bufs, 0, sizeof(bufs));
        bufs.count = 1;
        bufs.memory = V4L2_MEMORY_MMAP;
-       bufs.type = V4L2_CAP_VIDEO_CAPTURE;
+       bufs.type = (node->caps & V4L2_CAP_VIDEO_CAPTURE) ?
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE :
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        fail_on_test(doioctl(node, VIDIOC_REQBUFS, &bufs));
 
        memset(ptrs, 0, sizeof(ptrs));
@@ -734,35 +830,36 @@ int testExpBuf(struct node *node)
                        buf.length = VIDEO_MAX_PLANES;
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
-
-               memset(&expbuf, 0, sizeof(expbuf));
-               expbuf.type = bufs.type;
-               expbuf.index = i;
-               expbuf.flags = O_RDWR;
-               err = doioctl(node, VIDIOC_EXPBUF, &expbuf);
-               if (err == ENOTTY)
-                       break;
-       
-               dmabufs[i][0] = buf.m.fd = expbuf.fd;
-
-               ptrs[i][0] = mmap(NULL, buf.length,
-                                 PROT_READ | PROT_WRITE, MAP_SHARED, expbuf.fd, 0);
-               if (ptrs[i][0] == MAP_FAILED) {
-                       close(dmabufs[i][0]);
-                       ptrs[i][0] = NULL;
-                       fail("mmap on DMABUF file descriptor failed\n");
-                       err = ENOMEM;
-                       break;
+               unsigned num_planes = process_buf(buf, planes);
+
+               for (unsigned p = 0; p < num_planes; p++) {
+                       memset(&expbuf, 0, sizeof(expbuf));
+                       expbuf.type = bufs.type;
+                       expbuf.index = i;
+                       expbuf.plane = p;
+                       expbuf.flags = O_RDWR;
+                       err = doioctl(node, VIDIOC_EXPBUF, &expbuf);
+                       if (err == ENOTTY)
+                               break;
+
+                       dmabufs[i][p] = expbuf.fd;
+                       ptrs[i][p] = mmap(NULL, planes[p].length,
+                                       PROT_READ | PROT_WRITE, MAP_SHARED, expbuf.fd, 0);
+                       if (ptrs[i][p] == MAP_FAILED) {
+                               close(dmabufs[i][p]);
+                               ptrs[i][p] = NULL;
+                               fail("mmap on DMABUF file descriptor failed\n");
+                               err = ENOMEM;
+                               break;
+                       }
                }
        }
 
        for (unsigned i = 0; i < bufs.count; i++) {
                for (unsigned p = 0; p < VIDEO_MAX_PLANES; p++) {
                        if (ptrs[i][p]) {
-                               if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type))
-                                       munmap(ptrs[i][p], planes[p].length);
-                               else
-                                       munmap(ptrs[i][p], buf.length);
+                               munmap(ptrs[i][p], planes[p].length);
                                close(dmabufs[i][p]);
                        }
                }
@@ -780,6 +877,7 @@ static int setupDmaBuf(struct node *expbuf_node, struct node *node,
        struct v4l2_plane expbuf_planes[VIDEO_MAX_PLANES];
        struct v4l2_buffer expbuf_buf;
 
+       memset(expbuf_planes, 0, sizeof(expbuf_planes));
        memset(&expbuf_bufs, 0, sizeof(expbuf_bufs));
        expbuf_bufs.count = bufs.count;
        expbuf_bufs.memory = V4L2_MEMORY_MMAP;
@@ -802,6 +900,7 @@ static int setupDmaBuf(struct node *expbuf_node, struct node *node,
                struct v4l2_exportbuffer expbuf;
                int ret;
 
+               memset(planes, 0, sizeof(planes));
                memset(&buf, 0, sizeof(buf));
                buf.type = bufs.type;
                buf.memory = bufs.memory;
@@ -812,35 +911,54 @@ static int setupDmaBuf(struct node *expbuf_node, struct node *node,
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
                fail_on_test(checkQueryBuf(node, buf, bufs.type, bufs.memory, i, Unqueued));
+               unsigned num_planes = process_buf(buf, planes);
                fail_on_test(expbuf_buf.length < buf.length);
                if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type))
                        for (unsigned p = 0; p < buf.length; p++)
                                fail_on_test(expbuf_planes[p].length < planes[p].length);
 
-               memset(&expbuf, 0, sizeof(expbuf));
-               expbuf.type = bufs.type;
-               expbuf.index = i;
-               expbuf.flags = O_RDWR;
-               fail_on_test(doioctl(expbuf_node, VIDIOC_EXPBUF, &expbuf));
-       
-               dmabufs[i][0] = expbuf.fd;
+               for (unsigned p = 0; p < num_planes; p++) {
+                       memset(&expbuf, 0, sizeof(expbuf));
+                       expbuf.type = bufs.type;
+                       expbuf.index = i;
+                       expbuf.plane = p;
+                       expbuf.flags = O_RDWR;
+                       fail_on_test(doioctl(expbuf_node, VIDIOC_EXPBUF, &expbuf));
 
-               ptrs[i][0] = mmap(NULL, buf.length,
-                                 PROT_READ | PROT_WRITE, MAP_SHARED, expbuf.fd, 0);
-               fail_on_test(ptrs[i][0] == MAP_FAILED);
+                       dmabufs[i][p] = expbuf.fd;
+
+                       ptrs[i][p] = mmap(NULL, planes[p].length,
+                                       PROT_READ | PROT_WRITE, MAP_SHARED, expbuf.fd, 0);
+                       fail_on_test(ptrs[i][p] == MAP_FAILED);
+               }
 
-               buf.m.fd = 0xdeadbeef + expbuf.fd;
+               if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                       for (unsigned p = 0; p < buf.length; p++)
+                               planes[p].m.fd = 0xdeadbeef + dmabufs[i][p];
+               } else {
+                       buf.m.fd = 0xdeadbeef + dmabufs[i][0];
+               }
                ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                fail_on_test(!ret);
                if (ret != ENOTTY) {
-                       buf.m.fd = expbuf.fd;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.fd = dmabufs[i][p];
+                       } else {
+                               buf.m.fd = dmabufs[i][0];
+                       }
                        ret = doioctl(node, VIDIOC_PREPARE_BUF, &buf);
                        fail_on_test(ret);
                        fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
                        fail_on_test(checkQueryBuf(node, buf, bufs.type, bufs.memory, i, Prepared));
                } else {
                        fail_on_test(!doioctl(node, VIDIOC_QBUF, &buf));
-                       buf.m.fd = expbuf.fd;
+                       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type)) {
+                               for (unsigned p = 0; p < buf.length; p++)
+                                       planes[p].m.fd = dmabufs[i][p];
+                       } else {
+                               buf.m.fd = dmabufs[i][0];
+                       }
                }
 
                fail_on_test(doioctl(node, VIDIOC_QBUF, &buf));
@@ -857,6 +975,7 @@ static int releaseDmaBuf(struct node *expbuf_node, struct node *node,
                struct v4l2_plane planes[VIDEO_MAX_PLANES];
                struct v4l2_buffer buf;
 
+               memset(planes, 0, sizeof(planes));
                memset(&buf, 0, sizeof(buf));
                buf.type = bufs.type;
                buf.memory = bufs.memory;
@@ -866,8 +985,12 @@ static int releaseDmaBuf(struct node *expbuf_node, struct node *node,
                        buf.length = VIDEO_MAX_PLANES;
                }
                fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf));
-               munmap(ptrs[i][0], buf.length);
-               close(dmabufs[i][0]);
+               unsigned num_planes = process_buf(buf, planes);
+
+               for (unsigned p = 0; p < num_planes; p++) {
+                       munmap(ptrs[i][p], planes[p].length);
+                       close(dmabufs[i][p]);
+               }
        }
        return 0;
 }
@@ -878,11 +1001,13 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count
        bool can_stream = node->caps & V4L2_CAP_STREAMING;
        int ret;
        
-       if (!(node->caps & V4L2_CAP_VIDEO_CAPTURE))
+       if (!(node->caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
                return 0;
 
        memset(&bufs, 0, sizeof(bufs));
-       bufs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       bufs.type = (node->caps & V4L2_CAP_VIDEO_CAPTURE) ?
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE :
+                   V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        bufs.memory = V4L2_MEMORY_DMABUF;
        ret = doioctl(node, VIDIOC_REQBUFS, &bufs);
        if (ret) {
@@ -896,7 +1021,10 @@ int testDmaBuf(struct node *expbuf_node, struct node *node, unsigned frame_count
        fail_on_test(doioctl(node, VIDIOC_STREAMOFF, &bufs.type));
        last_seq = -1;
        field_nr = 1;
-       last_field = cur_fmt.fmt.pix.field;
+       if (V4L2_TYPE_IS_MULTIPLANAR(bufs.type))
+               last_field = cur_fmt.fmt.pix_mp.field;
+       else
+               last_field = cur_fmt.fmt.pix.field;
 
        fail_on_test(setupDmaBuf(expbuf_node, node, bufs));