与内存有关的api

mmap

​ mmap将文件或设备内存映射到进程地址空间的系统调用,常用于高效 I/O(如视频采集、文件读写)或进程间共享内存。在 V4L2(Video4Linux2)驱动中,它用来将内核的摄像头缓冲区映射到用户空间,以便直接访问图像数据,避免数据拷贝。

函数原型:

#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

参数说明

  • addr:建议的映射起始地址(通常传 NULL,由内核选择)。
  • length:映射的字节数。
  • prot:内存保护模式(PROT_READ 可读,PROT_WRITE 可写,PROT_EXEC 可执行,PROT_NONE 不可访问)。
  • flags:映射类型和其他行为。
    • MAP_SHARED:映射内容对其它进程可见,且写回底层文件(或设备)。
    • MAP_PRIVATE:写时复制,修改不写回。
    • 还可组合 MAP_FIXED、MAP_LOCKED 等。
  • fd:要映射的文件描述符(设备或文件)。
  • offset:文件偏移量(必须按系统页大小对齐,通常为 0 或设备指定的偏移)。

返回值

  • 成功:返回映射区的起始地址(void*)。
  • 失败:返回 MAP_FAILED(即 (void*)-1),并设置 errno。

例子

for (uint32_t i = 0; i < kCamBufCount; i++) {
    // 1. 准备 v4l2_buffer 结构,查询缓冲区的内存信息
    v4l2_plane planes[1];
    memset(planes, 0, sizeof(planes));
    v4l2_buffer buf;
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    buf.m.planes = planes;
    buf.length = 1;
    if (Xioctl(cam->fd, VIDIOC_QUERYBUF, &buf) < 0) {
        perror("VIDIOC_QUERYBUF");
        return false;
    }

    // 2. 核心 mmap 调用
    void *ptr = mmap(nullptr,                     // 由内核选择映射地址
                   planes[0].length,            // 缓冲区大小(字节)
                   PROT_READ | PROT_WRITE,      // 可读可写(驱动需要写图像数据)
                   MAP_SHARED,                  // 共享映射,驱动和用户空间共享同一块物理内存
                   cam->fd,                     // 摄像头设备文件描述符
                   planes[0].m.mem_offset);    // 缓冲区在设备内存中的偏移量
    if (ptr == MAP_FAILED) {
        perror("mmap camera buffer");
        return false;
    }
    cam->bufs[i].start = ptr;
    cam->bufs[i].length = planes[0].length;

    // 3. 入队缓冲区,等待驱动填充数据
    if (Xioctl(cam->fd, VIDIOC_QBUF, &buf) < 0) {
        perror("VIDIOC_QBUF (initial)");
        return false;
    }
}

映射成功后,ptr 指向用户空间可直接访问的地址,之后调用 VIDIOC_QBUF 将缓冲区交给驱动,驱动填充数据后,应用程序就能直接从 ptr 读取图像。