与内存有关的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 读取图像。