4. 逻辑 Camera 与物理 Camera

在 Android 多摄像头架构中,逻辑 Camera(Logical Camera) 与 物理 Camera(Physical Camera) 的抽象是 HAL 层实现多摄协同的核心设计。逻辑 Camera 对上层应用呈现为一个统一的摄像头设备,而底层则由多个物理 Camera 协同工作,实现变焦、虚化、超广角等功能。

4.1 逻辑 Camera 的组成

逻辑 Camera 是一个虚拟的 Camera 设备,它不直接对应硬件传感器,而是由一组物理 Camera 组合而成。其核心组成要素包括:

  • 物理 Camera 集合:逻辑 Camera 内部维护一个或多个物理 Camera 的引用,通常包括主摄(Wide)、超广角(Ultra-wide)、长焦(Telephoto)等。
  • 同步元数据(Synchronized Metadata):逻辑 Camera 负责合并或选择来自不同物理 Camera 的元数据,如传感器时间戳、AE/AWB 状态等。
  • 流合并策略(Stream Combination Policy):定义如何将应用请求的流(如预览、拍照)映射到具体的物理 Camera 流上。
  • 物理 Camera 切换逻辑:根据变焦系数、光照条件等动态决定使用哪个物理 Camera 作为主输出源。
关键概念: 逻辑 Camera 的 cameraId 在 HAL 层通过 ICameraProvider::getCameraIdList() 返回,其设备接口(ICameraDevice)与物理 Camera 的设备接口在结构上一致,但内部实现包含多路分发逻辑。
实现提示: 在 HAL 配置文件中,逻辑 Camera 通过 标签定义,并列出其包含的物理 Camera ID。例如:
<logicalCamera id="0">
    <physicalCamera id="1"/>  <!-- 主摄 -->
    <physicalCamera id="2"/>  <!-- 超广角 -->
    <physicalCamera id="3"/>  <!-- 长焦 -->
</logicalCamera>

4.2 物理 Camera 的同步与独立

物理 Camera 在逻辑 Camera 框架下,既需要保持同步以支持多摄融合,又需要保持独立以支持单摄独占场景。这种矛盾关系通过 HAL 层的同步机制和流控制来解决。

特性 同步模式 独立模式
触发方式 应用通过逻辑 Camera 下发 capture request,HAL 内部同步分发到多个物理 Camera 应用直接打开物理 Camera(需支持 CAMERA_DEVICE_API_VERSION_3_5 及以上)
时间戳 要求物理 Camera 的帧时间戳严格对齐,通常通过硬件同步信号(如 VSYNC)实现 各物理 Camera 独立产生时间戳,无需对齐
3A 同步 AE/AWB/AF 状态需要同步,避免融合画面出现亮度/色温不一致 3A 独立运行,互不干扰
流生命周期 物理 Camera 的流由逻辑 Camera 统一管理,应用不可见 物理 Camera 拥有独立的流生命周期,应用可直接配置
典型场景 多摄变焦、双摄虚化、多帧融合 单摄高帧率、专用传感器(如 ToF)
调试陷阱: 在同步模式下,如果物理 Camera 的帧率不一致(例如主摄 30fps,超广角 24fps),会导致逻辑 Camera 输出帧率下降或丢帧。此时需要检查 HAL 层的帧率同步策略,必要时对慢速传感器进行帧率降采样。

4.3 HAL 中逻辑 Camera 的实现

HAL 层实现逻辑 Camera 的核心在于 CameraDevice 类的设计。以下是一个典型的实现架构:

// 逻辑 Camera 设备接口示例
class LogicalCameraDevice : public camera3_device_t {
public:
    // 物理 Camera 设备列表
    std::vector<std::unique_ptr<PhysicalCameraDevice>> physical_devices_;

    // 流映射表:应用流 -> 物理 Camera 流
    std::map<camera3_stream_t*, PhysicalStreamInfo> stream_map_;

    // 同步管理器
    std::unique_ptr<SynchronizationManager> sync_manager_;

    // 处理 capture request
    int process_capture_request(camera3_capture_request_t* request) override {
        // 1. 解析请求中的物理 Camera ID(如果有)
        // 2. 根据变焦系数选择主物理 Camera
        // 3. 将 request 分发到选中的物理 Camera
        // 4. 同步等待所有物理 Camera 的 result
        // 5. 合并或选择最终的 result 返回给框架
    }
};

实现中的关键步骤包括:

  1. 物理 Camera 的初始化:在 open() 时,根据配置文件初始化所有关联的物理 Camera 设备。
  2. 流配置分发:在 configure_streams() 中,将应用的流需求映射到物理 Camera 的流上,并建立 stream_map_。
  3. 请求分发与结果合并:在 process_capture_request() 中,根据当前场景选择主物理 Camera,并将请求分发。结果返回时,需要合并元数据或选择最优结果。
  4. 同步信号处理:通过硬件或软件同步机制,确保多个物理 Camera 的帧输出在时间上对齐。
实现要点: 逻辑 Camera 的 flush() 方法需要同时 flush 所有物理 Camera,并等待所有未完成的 request 返回。如果某个物理 Camera 卡死,逻辑 Camera 应能超时并返回错误,避免整个系统阻塞。

4.4 逻辑 Camera 架构图

下图展示了逻辑 Camera 与物理 Camera 在 HAL 层的关系,以及请求/数据流的走向:

逻辑 Camera 与物理 Camera 架构图 逻辑 Camera 与物理 Camera HAL 架构 Android 应用 / 框架 逻辑 Camera (Logical Camera) cameraId=0 | 流映射 | 同步管理 | 物理 Camera 选择 流映射表 同步管理器 选择策略 物理 Camera 1 主摄 (Wide) 物理 Camera 2 超广角 (Ultra-wide) 物理 Camera 3 长焦 (Telephoto) Camera 硬件传感器 (Sensor / ISP) 硬件同步信号 (VSYNC / Frame Sync) 说明:逻辑 Camera 通过流映射和同步管理器,将应用请求分发到合适的物理 Camera,并确保多路数据在时间上对齐。

4.5 物理 Camera 独立访问与同步访问的对比

在 Android 11 及以上版本,HAL 支持应用直接打开物理 Camera(通过 camera3_stream_configuration_t.physical_camera_id)。下表对比了两种访问模式:

对比维度 通过逻辑 Camera 访问 直接访问物理 Camera
API 调用 CameraManager.openCamera(logicalId) CameraManager.openCamera(physicalId) + 设置 SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED
流配置 应用配置逻辑流,HAL 内部映射 应用直接配置物理流,HAL 不做映射
元数据 逻辑 Camera 合并/选择元数据 物理 Camera 返回原始元数据
同步需求 需要硬件/软件同步 无需同步,独立运行
典型用例 多摄变焦、虚化、夜景 专用传感器(ToF、红外)、高帧率单摄
调试建议: 当逻辑 Camera 出现画面不同步或融合异常时,可以先尝试直接打开物理 Camera 进行独立测试,以排除物理 Camera 本身的问题。如果物理 Camera 独立工作正常,则问题大概率出在逻辑 Camera 的同步或流映射逻辑上。

4.6 逻辑 Camera 的流映射策略

流映射是逻辑 Camera 实现中最复杂的部分之一。常见的映射策略包括:

  • 主从模式(Master-Slave):选择一个物理 Camera 作为主输出(如预览流),其他物理 Camera 作为辅助(如虚化深度流)。主流的输出直接返回给应用,辅助流仅用于内部计算。
  • 动态切换模式(Dynamic Switch):根据变焦系数动态切换主物理 Camera。例如,1x 时使用主摄,2x 时切换到长焦。切换时需要平滑过渡,避免画面跳变。
  • 融合模式(Fusion):多个物理 Camera 同时输出,HAL 或应用层进行像素级融合(如多帧合成、超分辨率)。
实现示例: 动态切换模式下的流映射伪代码:
// 根据变焦系数选择主物理 Camera
int select_physical_camera(float zoom_ratio) {
    if (zoom_ratio < 1.5f) return PHYSICAL_CAMERA_WIDE;      // 主摄
    else if (zoom_ratio < 3.0f) return PHYSICAL_CAMERA_ULTRA_WIDE; // 超广角
    else return PHYSICAL_CAMERA_TELE;                        // 长焦
}

// 在 configure_streams 中建立映射
void configure_streams(camera3_stream_configuration_t* config) {
    for (auto& stream : config->streams) {
        // 为每个应用流创建对应的物理流
        int physical_id = select_physical_camera(current_zoom_);
        PhysicalStreamInfo info;
        info.physical_id = physical_id;
        info.physical_stream = create_physical_stream(stream, physical_id);
        stream_map_[stream] = info;
    }
}

通过以上设计,逻辑 Camera 在 HAL 层实现了对多物理 Camera 的透明管理,既保证了上层应用的兼容性,又充分发挥了多摄硬件的协同能力。