}
}
+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)
{
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;
}
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);
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);
struct v4l2_buffer buf;
int ret;
+ memset(planes, 0, sizeof(planes));
memset(&buf, 0, sizeof(buf));
buf.type = bufs.type;
buf.memory = bufs.memory;
}
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);
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;
}
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 (;;) {
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)
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));
}
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) {
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);
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));
struct v4l2_buffer buf;
int ret;
+ memset(planes, 0, sizeof(planes));
memset(&buf, 0, sizeof(buf));
buf.type = bufs.type;
buf.memory = bufs.memory;
}
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);
}
}
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));
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;
}
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) {
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));
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));
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]);
}
}
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;
struct v4l2_exportbuffer expbuf;
int ret;
+ memset(planes, 0, sizeof(planes));
memset(&buf, 0, sizeof(buf));
buf.type = bufs.type;
buf.memory = bufs.memory;
}
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));
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;
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;
}
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) {
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));