必须先通过VIDIOC_QUERYCAP确认V4L2_CAP_STREAMING和V4L2_CAP_VIDEO_CAPTURE能力位,再验证驱动是否真正支持V4L2_MEMORY_MMAP模式;req.count需合理设置(推荐4),mmap长度须PAGE_ALIGN对齐,且QBUF/DQBUF须严格配对复用缓冲区。

VIDIOC_REQBUFS 之前必须确认 V4L2_CAP_STREAMING 和 V4L2_MEMORY_MMAP 支持
很多程序在 ioctl(fd, VIDIOC_REQBUFS, &req) 失败,直接报 EINVAL 或 EINVAL,根本原因不是参数写错,而是设备压根不支持 mmap 流式采集。调用 VIDIOC_QUERYCAP 后务必检查返回的 capabilities 字段:
- 必须包含
V4L2_CAP_STREAMING—— 否则无法启动流式传输 - 必须包含
V4L2_CAP_VIDEO_CAPTURE—— 否则不是捕获类设备 -
V4L2_MEMORY_MMAP不是 capability,但驱动是否真正实现 mmap 模式,得看VIDIOC_ENUM_FMT后再试VIDIOC_TRY_FMT是否接受.memory = V4L2_MEMORY_MMAP
UVC 设备一般都支持;但某些 MIPI 摄像头(如瑞芯微平台部分型号)默认只启用 USERPTR,需在驱动层显式启用 mmap 回调(vb2_ops.mmap)。
缓冲区数量设为 4 还是 6?取决于延迟与丢帧容忍度
req.count 不是越大越好,也不是越小越省内存。它本质是“飞行中帧数”上限,直接影响三件事:
- 设为 2:容易因处理慢导致
VIDIOC_DQBUF阻塞或超时,尤其在高帧率(60fps+)下几乎必丢帧 - 设为 4:通用推荐值,兼顾响应性与稳定性,适合大多数 USB 摄像头和嵌入式平台
- 设为 6 或 8:仅当后端处理(如编码、AI 推理)耗时波动大、且能接受 100ms+ 端到端延迟时使用;注意内核会按需分配连续物理页,过大会触发内存碎片告警(
dmesg可见vb2_dc_alloc失败)
别硬编码 req.count = 4。应在 VIDIOC_REQBUFS 返回后读取 req.count 实际值——驱动可能向下取整(如请求 6,实际只给 4)。
立即学习“C++免费学习笔记(深入)”;
mmap 映射长度必须用 PAGE_ALIGN,否则图像错位或 segfault
从 VIDIOC_QUERYBUF 拿到的 buf.length 是内核预估的单帧最大长度(含 padding),但 mmap 要求 offset 和 length 均按页对齐。常见错误是直接传 buf.length 给 mmap():
// ❌ 错误:未对齐,可能导致映射区域截断 addr = mmap(NULL, buf.length, PROT_READ, MAP_SHARED, fd, buf.m.offset); <p>// ✅ 正确:用 getpagesize() 对齐长度 size_t page_size = getpagesize(); size_t map_len = (buf.length + page_size - 1) & ~(page_size - 1); addr = mmap(NULL, map_len, PROT_READ, MAP_SHARED, fd, buf.m.offset);</p>
漏掉这步,在 ARM64 或某些 x86 内核上可能表现为 YUYV 图像每行偏移 2 字节、MJPEG 解码失败,或 mmap 返回 MAP_FAILED 且 errno == EINVAL。
VIDIOC_QBUF / VIDIOC_DQBUF 必须严格配对,且 DQBUF 后立即 QBUF 回队列
MMAP 模式下缓冲区是循环复用的,不是“用完即弃”。典型陷阱:
- 某帧处理耗时过长,没来得及
VIDIOC_QBUF回队列 → 下次VIDIOC_DQBUF等待超时,队列空转 - 异常退出前忘了
munmap→ 内存泄漏,ls /proc/$(pid)/maps可见大量v4l2匿名映射残留 - 多线程中一个线程
DQBUF后,另一个线程误调QBUF同一 index → 内核报EAGAIN或静默丢帧
最稳妥的做法是封装 RAII 类(如 MMapGuard),并在 DQBUF 成功后立刻 QBUF,不要跨函数或跨线程持有 buffer index。
真正难调试的从来不是 mmap 调用本身,而是缓冲区生命周期管理——index 复用顺序、映射地址有效性、以及内核与用户空间对“已入队/已出队”状态的认知同步。这些细节一旦错位,现象就是随机丢帧、卡顿、或 VIDIOC_DQBUF 永远阻塞。


















