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 返回给框架
}
};
实现中的关键步骤包括:
- 物理 Camera 的初始化:在
open()时,根据配置文件初始化所有关联的物理 Camera 设备。 - 流配置分发:在
configure_streams()中,将应用的流需求映射到物理 Camera 的流上,并建立stream_map_。 - 请求分发与结果合并:在
process_capture_request()中,根据当前场景选择主物理 Camera,并将请求分发。结果返回时,需要合并元数据或选择最优结果。 - 同步信号处理:通过硬件或软件同步机制,确保多个物理 Camera 的帧输出在时间上对齐。
实现要点: 逻辑 Camera 的
flush() 方法需要同时 flush 所有物理 Camera,并等待所有未完成的 request 返回。如果某个物理 Camera 卡死,逻辑 Camera 应能超时并返回错误,避免整个系统阻塞。
4.4 逻辑 Camera 架构图
下图展示了逻辑 Camera 与物理 Camera 在 HAL 层的关系,以及请求/数据流的走向:
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 的透明管理,既保证了上层应用的兼容性,又充分发挥了多摄硬件的协同能力。