@flaty 我的理解中,相机驱动并不涉及到BUFF模式的限制。实际上数据的收取和防止到内存是rk的mipi接收单元的驱动所决定的。
下面是网上插到的信息,希望能有帮助。
从你贴的代码来看,报错 Failed to queue buffer: Invalid argument
(EINVAL)通常意味着结构体成员设置有问题,或者驱动不支持 DMABUF 模式。结合你写的代码,我帮你逐条排查一下:
1. v4l2_buffer
初始化问题
你这里写的是:
struct v4l2_buffer buf={0};
struct v4l2_plane planes[1]={0};
这是对的,但要注意 buf.length
必须和 planes
数组元素数量一致,并且 buf.m.planes
不能为空。
2. buf
关键字段设置
你代码里:
buf.index = 0;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.length = 1;
buf.m.planes = planes;
buf.type
用 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
是对的(说明驱动是 multiplanar 类型)。
buf.memory
设置成 DMABUF
正确。
buf.index
不是 0 就行,它必须是你在 VIDIOC_REQBUFS
时分配的 buffer 数量里的一个合法索引。比如如果你 req.count = 4
,那么只能用 0..3
。
3. plane 字段设置
planes[0].m.fd = frame_buffers[i].dmabuf_fd;
planes[0].length = buffer_size;
问题可能出在这里:
planes[0].m.fd
:必须是 dma-buf
的有效 fd
。
planes[0].length
:应该是该 plane 的大小,但 通常驱动并不依赖这个值。有些驱动要求设置 bytesused
,即:
planes[0].bytesused = buffer_size;
如果 bytesused
没设,驱动可能直接返回 EINVAL
。
4. 建议的正确写法
试着改成这样:
struct v4l2_buffer buf;
struct v4l2_plane planes[VIDEO_MAX_PLANES]; // 通常 >= 1
memset(&buf, 0, sizeof(buf));
memset(planes, 0, sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_DMABUF;
buf.index = i; // 循环里的 buffer 索引
buf.length = 1; // plane 数量
buf.m.planes = planes;
planes[0].m.fd = frame_buffers[i].dmabuf_fd;
planes[0].length = buffer_size; // plane 总大小
planes[0].bytesused = buffer_size; // 必须加上
5. 确认驱动是否支持 DMABUF
不是所有 V4L2 驱动都支持 V4L2_MEMORY_DMABUF
。你可以用下面的方法确认:
v4l2-ctl -d /dev/video0 --querycap
如果 ioctl
里不支持 DMABUF
,就算代码写对了也会 EINVAL
。
有些驱动只支持 MMAP
,那就得用 V4L2_MEMORY_MMAP
。
建议:先在 QBUF
前打印出 buf
和 planes[0]
的值,确认 index
、fd
、bytesused
都合理。