4. HAL层虚化数据流:从Sensor到虚化输出的完整数据流、Stream配置、Buffer管理

4.1 双摄虚化数据流全景

双摄虚化在HAL层的数据流涉及两条独立的Sensor输入流、ISP预处理、深度计算引擎以及最终虚化合成输出。整个流程必须保证主摄与副摄帧同步、Buffer生命周期对齐,并在Stream配置阶段明确各路流的格式、分辨率和使用场景。

核心要点: 双摄虚化数据流的关键在于“同步”与“对齐”——帧同步保证两路Sensor曝光时间一致,Buffer对齐保证深度引擎输入的是同一时刻的主副帧。
双摄虚化HAL层完整数据流 主摄Sensor 副摄Sensor 主摄ISP 副摄ISP 帧同步 / 时间戳对齐 深度计算引擎 虚化合成 (Bokeh) 输出Buffer (YUV/JPEG) 说明:主副摄数据流独立经过ISP后,在帧同步模块完成时间戳对齐,再送入深度计算引擎生成深度图,最终由虚化合成模块输出带虚化效果的图像。

4.2 Stream配置策略

双摄虚化场景下,HAL层需要为每个物理Camera配置多个Stream,包括预览流、拍照流、深度专用流等。Stream配置的核心是保证主副摄的Stream参数匹配,同时为深度引擎预留专用Buffer通道。

Stream类型 主摄配置 副摄配置 用途说明
预览流 1920x1080, YUV420 1920x1080, YUV420 实时预览显示,需低延迟
拍照流 4032x3024, YUV420 4032x3024, YUV420 全分辨率输出,用于虚化合成
深度专用流 640x480, YUV420 640x480, YUV420 低分辨率快速深度计算
虚化输出流 4032x3024, YUV420 — 最终虚化结果输出
工程建议: 深度专用流建议使用较低分辨率(如640x480),可大幅降低深度计算引擎的算力消耗,同时不影响最终虚化效果。主副摄的深度流分辨率必须一致,否则立体匹配会失败。

4.3 Buffer管理与生命周期

Buffer管理是双摄虚化HAL层适配中最容易出问题的环节。每个Stream都需要独立的Buffer队列,且主副摄的Buffer必须在帧同步点完成配对。Buffer生命周期包括分配、填充、排队、消费和回收五个阶段。

Buffer生命周期与配对管理 主摄Buffer队列 副摄Buffer队列 分配 分配 填充 填充 帧同步配对 时间戳差值 < 1ms 深度引擎消费 Buffer回收 / 归还队列

4.4 帧同步机制

帧同步是双摄虚化数据流中最关键的环节。主副摄的帧到达时间可能因硬件差异、驱动延迟或ISP处理时间不同而产生偏移。HAL层必须实现帧同步逻辑,确保送入深度引擎的两帧属于同一时刻。

常见问题: 如果帧同步不严格,主副摄时间戳偏差超过2ms,深度图会出现明显的边缘错位和虚化伪影。在运动场景下,偏差容忍度更低,需控制在0.5ms以内。

帧同步的典型实现步骤:

  1. 时间戳采集: 在Sensor驱动层记录每帧的SOF(Start of Frame)时间戳。
  2. 队列缓冲: 主副摄各自维护一个环形Buffer队列,缓存最近N帧。
  3. 配对算法: 遍历主摄队列,在副摄队列中查找时间戳差值最小的帧,若差值小于阈值则配对成功。
  4. 丢弃策略: 若某一摄出现丢帧,则丢弃另一摄的对应帧,保持配对完整性。

4.5 深度引擎Buffer交互

深度计算引擎通常以专用硬件或DSP形式存在,HAL层需要将配对后的主副摄Buffer通过ION/DMA-BUF机制传递给深度引擎。Buffer的格式、对齐方式和缓存一致性是交互的关键。

参数项 要求 说明
Buffer格式 NV12 / NV21 深度引擎通常只支持YUV420半平面格式
对齐要求 16字节行对齐 硬件DMA访问需要行对齐,否则会触发异常
缓存一致性 DMA_BUF_SYNC_START/END CPU与DSP共享Buffer时需显式同步cache
Buffer数量 至少4对 保证流水线不阻塞,深度引擎可异步处理
// 深度引擎Buffer交互伪代码示例
// 主摄Buffer与副摄Buffer配对后送入深度引擎

struct depth_input {
    int buffer_fd_main;   // 主摄Buffer的DMA-BUF fd
    int buffer_fd_sub;    // 副摄Buffer的DMA-BUF fd
    uint64_t timestamp;   // 配对帧的时间戳
    int width;
    int height;
};

// 同步cache,确保CPU写入对DSP可见
struct dma_buf_sync sync_start = {
    .flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_WRITE
};
ioctl(buffer_fd_main, DMA_BUF_IOCTL_SYNC, &sync_start);

// 将配对Buffer提交给深度引擎
struct depth_input input = {
    .buffer_fd_main = main_fd,
    .buffer_fd_sub  = sub_fd,
    .timestamp      = matched_ts,
    .width          = 640,
    .height         = 480
};
ioctl(depth_engine_fd, DEPTH_IOCTL_SUBMIT, &input);

// 等待深度图完成
struct depth_output output;
ioctl(depth_engine_fd, DEPTH_IOCTL_GET_RESULT, &output);

// 同步cache,确保DSP写入对CPU可见
struct dma_buf_sync sync_end = {
    .flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_READ
};
ioctl(output.depth_buffer_fd, DMA_BUF_IOCTL_SYNC, &sync_end);

4.6 虚化合成输出流

深度图生成后,虚化合成模块将主摄全分辨率图像与深度图进行融合。合成过程需要额外的Buffer作为输出通道,通常使用GPU或专用ISP管线完成。输出流的配置必须与拍照流分辨率一致,且支持YUV420和JPEG两种格式。

性能指标: 在主流平台上,从Sensor输出到虚化结果完成,端到端延迟应控制在150ms以内(含深度计算80ms + 虚化合成50ms + Buffer传输20ms)。超过200ms会导致拍照体验明显卡顿。

虚化合成输出流的Buffer管理要点:

  • 输出Buffer池: 预分配至少3个输出Buffer,避免合成模块等待分配。
  • 格式转换: 若深度引擎输出为RAW深度图,需先转换为浮点或8位深度图,再送入合成管线。
  • JPEG编码: 虚化结果通常需要编码为JPEG保存,编码过程可复用拍照流的JPEG硬件编码器。
  • 预览回显: 虚化结果可降采样后送入预览流,实现“所见即所得”的虚化预览效果。
虚化合成输出流Buffer管理 主摄全分辨率帧 深度图 虚化合成引擎 GPU / ISP管线 输出Buf 0 输出Buf 1 输出Buf 2 JPEG编码 硬件编码器

4.7 常见数据流问题与调优

问题现象 根因分析 解决方案
虚化边缘锯齿严重 深度图分辨率过低或主副摄未严格对齐 提高深度流分辨率至1280x720;加强帧同步时间戳校验
拍照卡顿,延迟超过200ms Buffer数量不足,流水线阻塞 增加深度引擎输入Buffer对至6对;启用异步深度计算
预览虚化闪烁 预览流与拍照流Buffer竞争,帧率不稳定 预览流使用独立Buffer池;降低预览流分辨率
深度图全黑或全白 主副摄Buffer内容未正确同步cache 在深度引擎提交前和结果获取后强制调用DMA_BUF_SYNC
调优口诀: 帧同步看时间戳,Buffer管理看数量,深度质量看对齐,性能瓶颈看流水。双摄虚化HAL层适配的核心就是把这四个环节的工程细节做到极致。