V4L2 中 mmap 与 dma-buf 的关系

2 阅读2分钟

核心认知:三个角色,两种地址

CPU (你的代码)  →  只能用虚拟地址  →  需要 mmap 建立映射
DMA 硬件        →  只能用物理地址  →  不需要 mmap,直接访问
内核驱动        →  管理物理地址    →  创建 dma-buf 让硬件共享内存

硬件永远不需要 mmap。mmap 是给 CPU 用的。

dma-buf:硬件之间的"通行证"

dma_buf fd = 42  (你拿到的整数)
     │
     ▼
┌───────────────────────┐
│ 物理地址: 0x80000000  │ ← DMA 引擎直接用
│ 大小: 3MB             │
└───────────────────────┘

用途:把一块物理内存的"访问权"在不同硬件模块(V4L2/RGA/MPP/DRM)之间传递,全程硬件直接读写,CPU 不碰数据。

V4L2 两种内存模式

模式一:MMAP(内存由 V4L2 分配)

初始化:
  REQBUFS  →  内核分配4块物理内存
  QUERYBUF × 4  →  查询每块信息
  mmap × 4  →  ← 必须做!API 强制要求(即使你不用 CPU 读)
  QBUF × 4  →  空buf入队
  STREAMON

取帧:
  DQBUF  →  拿到一帧
  EXPBUF  →  导出 dma-buf fd ← 这时才创建 dma_buf,拿到 fd
  把 fd 给 DRM/RGA 做零拷贝

为什么必须 mmap?  V4L2 API 历史设计(1999年,早于 dma-buf 的 2012年),驱动状态机要求 STREAMON 前每个 buf 必须已 mmap。

EXPBUF 做了什么?  不是分配新内存,是为已有的物理内存"补办"一个 dma-buf 对象并返回 fd。好比酒店前台补办一张访客卡。

模式二:DMABUF(内存由你分配)

初始化:
  DMA_HEAP_ALLOC  →  你自己分配 dma-buf fd
  REQBUFS(memory=DMABUF)  →  告诉V4L2用外部内存
  QBUF(你的fd)  →  把你的 fd 入队
  STREAMON

取帧:
  DQBUF  →  拿到一帧
  直接用你自己的 fd 给 DRM/RGA  ← 不需要 EXPBUF!fd 本来就是你的

全程不需要 mmap,不需要 EXPBUF。  因为内存是你分配的,fd 生来就是你的。

为什么 GStreamer 解码器不需要 mmap?

GStreamer 解码器:
  MPP 驱动内部分配内存 → 创建 dma_buf → 返回 fd 给 GstBuffer
  你拿到的是"成品 fd",直接能用

V4L2 MMAP 模式:
  V4L2 驱动分配内存 → 你必须 mmap 初始化 → 然后 EXPBUF 借出 fd
  你是"内存的管理者",必须走完流程

区别:一个是接收者(GStreamer),一个是管理者(V4L2 MMAP)。

总结

MMAP 模式DMABUF 模式GStreamer 解码
内存主人V4L2 驱动MPP 驱动
需要 mmap✅ 强制
需要 EXPBUF
fd 来源EXPBUF 导出你自己创建的驱动直接给

一句话:  dma-buf 是硬件之间的零拷贝通道,mmap 是给 CPU 看的翻译通道。V4L2 MMAP 模式强制 mmap 是 API 历史包袱,不是技术必需。用 DMABUF 模式可跳过。