diff options
| author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-22 11:43:37 +0300 | 
|---|---|---|
| committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-22 11:43:37 +0300 | 
| commit | ab0c87921e03742df93e94a800fe0fcf80e5047b (patch) | |
| tree | 52a73ed00ac90163196ecc6822cfe2a89d1c61a7 | |
| parent | 117cd47e08db4e31d2f966cb4b22987d3e5d6bb7 (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.c | 111 | ||||
| -rw-r--r-- | v4l2.h | 54 | 
2 files changed, 147 insertions, 18 deletions
| @@ -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; @@ -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 | 
