在 macOS 的摄像头采集、屏幕录制、视频滤镜与硬件解码流程中,Core Video 提供的 CVPixelBuffer 是无压缩像素帧的主要容器。它封装了图像宽度、高度、像素格式、行字节数以及实际数据地址。与普通 malloc 出来的内存不同,CVPixelBuffer 的底层缓冲区可能由 IOSurface、显存或其他系统组件托管,CPU 并不能保证随时都能安全地解引用其基地址。许多崩溃和花屏问题,正是由于开发者绕过锁定机制,直接使用 CVPixelBufferGetBaseAddress 获得了指针之后,在不安全的时机读写像素造成的。要正确从 CPU 侧处理视频帧,就必须理解 CVPixelBufferLockBaseAddress 提供的锁与解锁语义。

CVPixelBuffer 并不是一块普通的连续内存,它可能由 Core Video 框架根据使用场景选择不同的存储后端。在 Mac 上,视频帧经常通过 IOSurface 在进程、GPU 和显示服务之间共享。这种情况下,CPU 访问前必须建立有效的地址映射,否则得到的指针可能指向未映射区域或者读到一半的数据。锁定操作不仅仅是加锁,它还会触发必要的内存映射和同步准备。
为什么需要锁定:CVPixelBuffer 的共享内存与并发访问风险
CVPixelBuffer 的底层缓冲区常常被多个硬件单元和线程同时访问。例如,摄像头采集到的帧可能先由 GPU 写入,再交给 CPU 进行人脸检测或图像分析,同时显示服务可能还在读取上一帧。如果 CPU 在 GPU 尚未完成写入时就通过基地址访问像素,就会看到撕裂、色块错位甚至触发内存访问异常。CVPixelBufferLockBaseAddress 的作用就是在 CPU 访问之前建立一段互斥临界区,阻止其他写入者同时修改数据。
从实现角度看,锁定可以理解为一个轻量级互斥锁。当某个线程成功锁定缓冲区后,其他尝试锁定同一个缓冲区的线程会被阻塞,直到前者调用解锁。这种互斥保证了像素数据在锁定期间不会被同时写入。对于只读访问场景,开发者可以传入只读标志,让系统有机会进行只读优化,同时仍然保证不存在并发写入。需要强调的是,锁定并不等同于完全同步 GPU 命令队列,它主要面向 CPU 侧直接内存访问,如果数据仍由 GPU 管线异步写入,还需要配合 Metal 或 OpenGL 的同步机制。
如果绕过锁定直接获取基地址,CVPixelBufferGetBaseAddress 的返回值可能是 NULL,也可能返回一个暂时有效的地址,但该地址在下一帧到来时就会失效。特别是在 IOSurface 共享内存中,底层内存可能被重新映射或回收,陈旧的指针会直接导致 EXC_BAD_ACCESS。因此,任何基于 CPU 的像素读写,第一件事都应该是锁定缓冲区,而不是先取得指针再判断是否为空。
锁定与解锁 API 的核心用法与参数选择
CVPixelBufferLockBaseAddressCVPixelBuffer线程安全修改时间:2026-08-13 04:41:30