v4l2 use dma buffer mode

这篇博客详细介绍了在Linux内核中,用户空间如何通过V4L2接口使用DMA缓冲区进行视频捕获。内容涉及到`VIDIOC_QBUF`操作的使用,以及内核内部`__qbuf_dmabuf`函数的流程,包括DMA缓冲区的获取、验证、映射等步骤。关键操作如`dma_buf_get`、`vb2_dma_sg_map_dmabuf`确保了DMA缓冲区的有效使用,并在错误处理中进行了资源释放。此外,还讨论了多个模块共享DMA缓冲区时的映射注意事项。

user space
参考 https://www.kernel.org/doc/html/v4.9/media/uapi/v4l/dmabuf.html

		struct v4l2_buffer buf;
		memset(&buf, 0, sizeof buf);
		buf.index = 0;
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_DMABUF;
		buf.m.fd = dma_buf_fd;
		ret = ioctl(v4lfd, VIDIOC_QBUF, &buf);

kernel

/**
 * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer
 */
static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
{
	struct vb2_plane planes[VB2_MAX_PLANES];
	struct vb2_queue *q = vb->vb2_queue;
	void *mem_priv;
	unsigned int plane;
	int ret = 0;
	enum dma_data_direction dma_dir =
		q->is_output ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
	bool reacquired = vb->planes[0].mem_priv == NULL;

	memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
	/* Copy relevant information provided by the userspace */
	if (pb)
		ret = call_bufop(vb->vb2_queue, fill_vb2_buffer,
				 vb, pb, planes);
	if (ret)
		return ret;

	for (plane = 0; plane < vb->num_planes; ++plane) {
		struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);

		if (IS_ERR_OR_NULL(dbuf)) {
			dprintk(1, "invalid dmabuf fd for plane %d\n",
				plane);
			ret = -EINVAL;
			goto err;
		}

		/* use DMABUF size if length is not provided */
		if (planes[plane].length == 0)
			planes[plane].length = dbuf->size;

		if (planes[plane].length < vb->planes[plane].min_length) {
			dprintk(1, "invalid dmabuf length %u for plane %d, minimum length %u\n",
				planes[plane].length, plane,
				vb->planes[plane].min_length);
			dma_buf_put(dbuf);
			ret = -EINVAL;
			goto 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值