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

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

被折叠的 条评论
为什么被折叠?



