summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2018-05-22 11:43:37 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2018-05-22 11:43:37 +0300
commitab0c87921e03742df93e94a800fe0fcf80e5047b (patch)
tree52a73ed00ac90163196ecc6822cfe2a89d1c61a7
parent117cd47e08db4e31d2f966cb4b22987d3e5d6bb7 (diff)
v4l2: Replace USERPTR support with DMABUF support
V4L2_MEMORY_USERPTR is deprecated, replace it with V4L2_MEMORY_DMABUF support for buffer sharing. Two new functions are added, v4l2_export_buffers() to export previously allocated buffers as dmabuf objects, and v4l2_import_buffers() to import dmabuf objects as backing store for V4L2 buffers. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--v4l2.c111
-rw-r--r--v4l2.h54
2 files changed, 147 insertions, 18 deletions
diff --git a/v4l2.c b/v4l2.c
index 4484acb..a0036fd 100644
--- a/v4l2.c
+++ b/v4l2.c
@@ -512,7 +512,7 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,
if (dev->nbufs != 0)
return -EBUSY;
- if (memtype != V4L2_MEMORY_MMAP && memtype != V4L2_MEMORY_USERPTR)
+ if (memtype != V4L2_MEMORY_MMAP && memtype != V4L2_MEMORY_DMABUF)
return -EINVAL;
/* Request the buffers from the driver. */
@@ -550,8 +550,10 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,
memset(dev->buffers, 0, sizeof *dev->buffers * nbufs);
- for (i = 0; i < dev->nbufs; ++i)
+ for (i = 0; i < dev->nbufs; ++i) {
dev->buffers[i].index = i;
+ dev->buffers[i].dmabuf = -1;
+ }
ret = 0;
@@ -571,13 +573,10 @@ int v4l2_free_buffers(struct v4l2_device *dev)
if (dev->nbufs == 0)
return 0;
- if (dev->memtype == V4L2_MEMORY_MMAP) {
- for (i = 0; i < dev->nbufs; ++i) {
- struct v4l2_video_buffer *buffer = &dev->buffers[i];
-
- if (buffer->mem == NULL)
- continue;
+ for (i = 0; i < dev->nbufs; ++i) {
+ struct v4l2_video_buffer *buffer = &dev->buffers[i];
+ if (buffer->mem) {
ret = munmap(buffer->mem, buffer->size);
if (ret < 0) {
printf("%s: unable to unmap buffer %u (%d)\n",
@@ -586,8 +585,14 @@ int v4l2_free_buffers(struct v4l2_device *dev)
}
buffer->mem = NULL;
- buffer->size = 0;
}
+
+ if (buffer->dmabuf != -1) {
+ close(buffer->dmabuf);
+ buffer->dmabuf = -1;
+ }
+
+ buffer->size = 0;
}
memset(&rb, 0, sizeof rb);
@@ -609,6 +614,88 @@ int v4l2_free_buffers(struct v4l2_device *dev)
return 0;
}
+int v4l2_export_buffers(struct v4l2_device *dev)
+{
+ unsigned int i;
+ int ret;
+
+ if (dev->nbufs == 0)
+ return -EINVAL;
+
+ if (dev->memtype != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ for (i = 0; i < dev->nbufs; ++i) {
+ struct v4l2_exportbuffer expbuf = {
+ .type = dev->type,
+ .index = i,
+ };
+
+ ret = ioctl(dev->fd, VIDIOC_EXPBUF, &expbuf);
+ if (ret < 0) {
+ printf("Failed to export buffer %u.\n", i);
+ return ret;
+ }
+
+ dev->buffers[i].dmabuf = expbuf.fd;
+
+ printf("%s: buffer %u exported with fd %u.\n",
+ dev->name, i, dev->buffers[i].dmabuf);
+ }
+
+ return 0;
+}
+
+int v4l2_import_buffers(struct v4l2_device *dev, unsigned int nbufs,
+ const struct v4l2_video_buffer *buffers)
+{
+ unsigned int i;
+ int ret;
+
+ if (dev->nbufs == 0 || dev->nbufs > nbufs)
+ return -EINVAL;
+
+ if (dev->memtype != V4L2_MEMORY_DMABUF)
+ return -EINVAL;
+
+ for (i = 0; i < dev->nbufs; ++i) {
+ const struct v4l2_video_buffer *buffer = &buffers[i];
+ struct v4l2_buffer buf = {
+ .index = i,
+ .type = dev->type,
+ .memory = dev->memtype,
+ };
+ int fd;
+
+ ret = ioctl(dev->fd, VIDIOC_QUERYBUF, &buf);
+ if (ret < 0) {
+ printf("%s: unable to query buffer %u (%d).\n",
+ dev->name, i, errno);
+ return -errno;
+ }
+
+ if (buffer->size < buf.length) {
+ printf("%s: buffer %u too small (%u bytes required, %u bytes available.\n",
+ dev->name, i, buf.length, buffer->size);
+ return -EINVAL;
+ }
+
+ fd = dup(buffer->dmabuf);
+ if (fd < 0) {
+ printf("%s: failed to duplicate dmabuf fd %d.\n",
+ dev->name, buffer->dmabuf);
+ return ret;
+ }
+
+ printf("%s: buffer %u valid.\n", dev->name, i);
+
+ dev->buffers[i].dmabuf = fd;
+ dev->buffers[i].size = buffer->size;
+ }
+
+ return 0;
+}
+
int v4l2_mmap_buffers(struct v4l2_device *dev)
{
unsigned int i;
@@ -688,10 +775,8 @@ int v4l2_queue_buffer(struct v4l2_device *dev, struct v4l2_video_buffer *buffer)
buf.type = dev->type;
buf.memory = dev->memtype;
- if (dev->memtype == V4L2_MEMORY_USERPTR)
- buf.m.userptr = (unsigned long)dev->buffers[buffer->index].mem;
-
- buf.length = dev->buffers[buffer->index].size;
+ if (dev->memtype == V4L2_MEMORY_DMABUF)
+ buf.m.fd = (unsigned long)dev->buffers[buffer->index].dmabuf;
if (dev->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
buf.bytesused = buffer->bytesused;
diff --git a/v4l2.h b/v4l2.h
index 2dad4c1..f9da5aa 100644
--- a/v4l2.h
+++ b/v4l2.h
@@ -31,7 +31,7 @@
* @error: True if an error occured while capturing video data for the buffer
* @allocated: True if memory for the buffer has been allocated
* @mem: Video data memory
- * @fd: Video data dmabuf handle
+ * @dmabuf: Video data dmabuf handle
*/
struct v4l2_video_buffer
{
@@ -42,7 +42,7 @@ struct v4l2_video_buffer
bool error;
bool allocated;
void *mem;
- int fd;
+ int dmabuf;
};
struct v4l2_device
@@ -148,7 +148,7 @@ int v4l2_set_crop(struct v4l2_device *dev, struct v4l2_rect *rect);
*
* When @memtype is set to V4L2_MEMORY_MMAP the buffers are allocated by the
* driver. They can then be mapped to userspace by calling v4l2_mmap_buffers().
- * When @memtype is set to V4L2_MEMORY_USERPTR the driver only allocates buffer
+ * When @memtype is set to V4L2_MEMORY_DMABUF the driver only allocates buffer
* objects and relies on the application to provide memory storage for video
* frames.
*
@@ -162,7 +162,7 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,
* @dev: Device instance
*
* Free buffers previously allocated by v4l2_alloc_buffers(). If the buffers
- * have been allocated with the V4L2_MEMORY_USERPTR memory type only the buffer
+ * have been allocated with the V4L2_MEMORY_DMABUF memory type only the buffer
* objects are freed, and the caller is responsible for freeing the video frames
* memory if required.
*
@@ -173,6 +173,50 @@ int v4l2_alloc_buffers(struct v4l2_device *dev, enum v4l2_memory memtype,
int v4l2_free_buffers(struct v4l2_device *dev);
/*
+ * v4l2_export_buffers - Export buffers as dmabuf objects
+ * @dev: Device instance
+ *
+ * Export all the buffers previously allocated by v4l2_alloc_buffers() as dmabuf
+ * objects. The dmabuf objects handles can be accessed through the dmabuf field
+ * of each entry in the @dev::buffers array.
+ *
+ * The dmabuf objects handles will be automatically closed when the buffers are
+ * freed with v4l2_free_buffers().
+ *
+ * This function can only be called when buffers have been allocated with the
+ * memory type set to V4L2_MEMORY_MMAP. If the memory type is different, or if
+ * no buffers have been allocated, it will return -EINVAL.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int v4l2_export_buffers(struct v4l2_device *dev);
+
+/*
+ * v4l2_import_buffers - Import buffer backing store as dmabuf objects
+ * @dev: Device instance
+ * @nbufs: Number of buffers in the @buffers array
+ * @buffers: Buffers to be imported
+ *
+ * Import the dmabuf objects from @buffers as backing store for the device
+ * buffers previously allocated by v4l2_alloc_buffers().
+ *
+ * The dmabuf file handles are duplicated and stored in the dmabuf field of the
+ * @dev::buffers array. The handles from the @buffers array can thus be closed
+ * independently without impacting usage of the imported dmabuf objects. The
+ * duplicated file handles will be automatically closed when the buffers are
+ * freed with v4l2_free_buffers().
+ *
+ * This function can only be called when buffers have been allocated with the
+ * memory type set to V4L2_MEMORY_DMABUF. If the memory type is different, if no
+ * buffers have been allocated, or if the number of allocated buffers is larger
+ * than @nbufs, it will return -EINVAL.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+int v4l2_import_buffers(struct v4l2_device *dev, unsigned int nbufs,
+ const struct v4l2_video_buffer *buffers);
+
+/*
* v4l2_mmap_buffers - Map buffers to application memory space
* @dev: Device instance
*
@@ -202,7 +246,7 @@ int v4l2_mmap_buffers(struct v4l2_device *dev);
* buffer to be queued. The index is zero-based and must be lower than the
* number of allocated buffers.
*
- * For V4L2_MEMORY_USERPTR buffers, the caller must initialize the @buffer::mem
+ * For V4L2_MEMORY_DMABUF buffers, the caller must initialize the @buffer::dmabuf
* field with the address of the video frame memory, and the @buffer:length
* field with its size in bytes. For optimal performances the address and length
* should be identical between v4l2_queue_buffer() calls for a given buffer