3. ZSL Pipeline 架构:环形缓冲区、流分离与关键时序
零延迟拍照(ZSL)的核心在于 Pipeline 架构。传统拍照模式下,用户按下快门后 Sensor 才开始曝光,导致明显的快门时滞。ZSL 通过维持一个持续运转的帧流与请求流,配合环形缓冲区,实现“按下即得”的体验。本章深入剖析 ZSL Pipeline 的三个核心设计:环形缓冲区、流分离机制以及关键时序节点。
3.1 ZSL 环形缓冲区设计
环形缓冲区(Ring Buffer)是 ZSL 的“时间机器”。它预分配固定数量的帧缓冲区,在 Sensor 持续输出帧流时,最新的帧不断覆盖最旧的帧。当用户按下快门时,系统直接从缓冲区中取出最近一帧或最佳一帧,无需等待 Sensor 重新曝光。
设计要点: 缓冲区大小直接影响延迟与内存开销。过小容易丢帧,过大会增加内存压力与检索延迟。
3.1.1 缓冲区结构与参数
| 参数 | 典型值 | 说明 |
|---|---|---|
| 缓冲区深度(N) | 4 ~ 8 帧 | 决定可回溯的时间窗口,通常覆盖 100~200ms |
| 帧分辨率 | 全分辨率 / 预览分辨率 | ZSL 通常使用全分辨率帧,避免后期缩放损失细节 |
| 元数据槽 | 与帧槽 1:1 绑定 | 存储每帧的曝光参数、AE/AWB 状态、时间戳 |
| 写入指针(WritePtr) | 循环递增 | 指向当前 Sensor 输出帧的写入位置 |
| 读取指针(ReadPtr) | 由快门事件触发 | 指向被选为“拍照帧”的缓冲区位置 |
3.1.2 环形缓冲区工作流程
- 预填充阶段: 打开 Camera 后,Sensor 开始输出帧流,WritePtr 循环写入缓冲区,直到缓冲区填满。
- 稳态阶段: 缓冲区满后,新帧覆盖最旧帧,WritePtr 持续循环。
- 拍照触发: 用户按下快门,HAL 根据时间戳或 AE 状态选择最佳帧(通常是最近一帧或曝光最稳定的一帧)。
- 帧提取: 从 ReadPtr 位置取出帧数据与元数据,送入 JPEG/HEIC 编码管线。
- 缓冲区复位: 拍照完成后,缓冲区继续循环,WritePtr 不受影响。
性能提示: 缓冲区深度建议根据 Sensor 帧率与预期延迟计算。例如 30fps 下,4 帧缓冲区可覆盖约 133ms,足以应对大部分场景。
3.2 帧流与请求流分离
ZSL 架构中,帧流(Frame Stream) 与 请求流(Request Stream) 是两条独立的异步管道。这种分离设计是降低延迟的关键。
- 帧流: 由 Sensor 硬件驱动,以固定帧率(如 30fps)持续输出原始帧数据,写入环形缓冲区。帧流不受上层应用状态影响,始终保持稳定。
- 请求流: 由应用层(Camera2 / CameraX)发起,包含拍照、预览、对焦等请求。请求流不直接控制 Sensor 曝光,而是从帧流中“选取”或“标记”帧。
3.2.1 分离架构的优势
| 维度 | 传统耦合架构 | ZSL 流分离架构 |
|---|---|---|
| 延迟 | 请求到达后 Sensor 才开始曝光,延迟约 100~300ms | 请求直接取已曝光帧,延迟 < 10ms |
| 帧率稳定性 | 受请求负载影响,帧率波动大 | 帧流独立运行,帧率恒定 |
| 资源开销 | 每次请求重新配置 Sensor | Sensor 持续工作,无重复配置开销 |
| 并发能力 | 单线程阻塞式处理 | 帧流与请求流可并行处理 |
3.2.2 流分离的实现模型
在 Camera HAL 层,帧流与请求流通过 Stream 对象 进行抽象。帧流对应一个 ImageReader 或 Surface,请求流对应 CaptureRequest 队列。HAL 内部维护一个 帧选择器(Frame Selector),负责将请求与帧流中的帧进行匹配。
// 伪代码:帧流与请求流分离的核心逻辑
class ZslPipeline {
RingBuffer<Frame> frameBuffer; // 帧流缓冲区
Queue<CaptureRequest> requestQueue; // 请求流队列
void onFrameAvailable(Frame frame) {
frameBuffer.write(frame); // 帧流持续写入
}
void onCaptureRequest(CaptureRequest request) {
requestQueue.enqueue(request);
// 请求流不阻塞帧流
}
void processRequests() {
while (!requestQueue.isEmpty()) {
CaptureRequest req = requestQueue.dequeue();
Frame bestFrame = frameBuffer.selectBestFrame(req);
// 将最佳帧送入编码管线
encodeFrame(bestFrame, req);
}
}
}
注意: 帧选择器的策略直接影响拍照质量。常见策略包括:选择时间戳最接近请求的帧、选择 AE 状态最稳定的帧、或选择曝光参数与请求最匹配的帧。
3.3 关键时序节点分析
ZSL 的“零延迟”并非绝对零延迟,而是将延迟从“按下快门后”转移到“按下快门前的持续运行中”。理解关键时序节点有助于定位性能瓶颈。
3.3.1 时序节点定义
| 节点 | 符号 | 典型耗时 | 说明 |
|---|---|---|---|
| Sensor 曝光时间 | Texp | 10~33ms | 取决于帧率与 AE 策略,30fps 下约 33ms |
| 帧传输延迟 | Ttx | 5~15ms | Sensor 数据通过 CSI 接口传输到 ISP 的时间 |
| ISP 处理时间 | Tisp | 8~20ms | 包括去马赛克、降噪、色调映射等 |
| 缓冲区写入时间 | Twrite | < 1ms | 帧数据从 ISP 拷贝到环形缓冲区 |
| 帧选择时间 | Tselect | < 0.5ms | 根据元数据匹配最佳帧 |
| 编码时间 | Tencode | 50~200ms | JPEG/HEIC 压缩,与分辨率强相关 |
3.3.2 时序流水线分析
在 ZSL 模式下,关键路径是:用户按下快门 → 帧选择 → 编码输出。Sensor 曝光与 ISP 处理在按下快门之前已经完成。因此,ZSL 的拍照延迟主要由 Tselect + Tencode 决定,而 Texp + Ttx + Tisp 被完全隐藏。
优化焦点: 编码时间 Tencode 是 ZSL 延迟的主要贡献者。优化方向包括:使用硬件编码器、降低 JPEG 质量、或采用 HEIC 格式。