4、配置复用概念:什么是Session配置复用?为什么需要复用?减少重建开销的原理
4.1 什么是Session配置复用
在Android Camera2框架中,Session配置复用(Session Configuration Reuse)是指在不销毁当前CameraCaptureSession的前提下,通过复用已有的底层流配置(Surface组合、分辨率、格式、帧率等),直接创建或切换新的Capture请求流水线。传统模式下,每次改变输出流配置(例如从拍照切换到录像)都必须先关闭当前Session,再重新创建,而配置复用允许在Session存活期内动态调整内部流水线。
核心定义:配置复用是CameraDevice.createCaptureSession()与CameraCaptureSession.setRepeatingRequest()之间的一种优化策略,它利用底层ISP(图像信号处理器)和HAL(硬件抽象层)的流表缓存机制,避免重复进行流配置协商、内存分配和硬件管线的重新初始化。
4.2 为什么需要配置复用
在Android相机开发中,Session创建是一个重量级操作。每次创建新Session,Camera HAL都需要重新解析流配置、分配GraphicBuffer、初始化ISP管线、同步Sensor参数。对于需要频繁切换场景的应用(如同时进行预览、拍照、录像、分析),传统重建模式会引入明显的延迟和功耗开销。
| 对比维度 | 传统重建Session | 配置复用Session |
|---|---|---|
| 创建延迟 | 30~120ms(取决于流数量) | 0.5~5ms(仅增量更新) |
| 内存开销 | 每次重新分配GraphicBuffer池 | 复用已有Buffer池,按需扩展 |
| 功耗影响 | ISP重新初始化,峰值电流增加 | 流水线保持热状态,功耗平稳 |
| 帧率稳定性 | 重建期间丢帧(通常3~8帧) | 无丢帧,流切换平滑 |
| 适用场景 | 应用启动、配置彻底变更 | 预览↔拍照↔录像频繁切换 |
性能数据参考:在Qualcomm SM8550平台上,从1080p预览切换到4K录像,传统重建需要约85ms,而配置复用仅需约3ms,延迟降低96%以上。对于需要60fps连续流的应用,这直接决定了是否会出现卡顿。
4.3 减少重建开销的原理
配置复用减少重建开销的核心原理可以归纳为以下三个层面:
- 流配置表缓存(Stream Configuration Cache):Camera HAL内部维护一张流配置哈希表,当新请求的流组合与缓存中的某条记录匹配时,直接复用对应的ISP管线配置,跳过协商阶段。
- Buffer池零拷贝复用(Buffer Pool Zero-Copy):Session持有的GraphicBuffer池在复用模式下不会被销毁,新流可以直接从池中获取已分配的Buffer,避免mmap/munmap系统调用。
- 硬件管线热保持(Pipeline Hot-Standby):ISP、CSID、DPE等硬件模块在复用期间保持上电和时钟稳定,仅更新路由和参数寄存器,无需重新加载固件。
4.4 配置复用的适用条件与限制
并非所有场景都适合配置复用。以下条件必须同时满足,HAL才会启用复用路径:
- 流数量不变或减少:新增流数量不能超过Session创建时声明的最大流数。
- 分辨率与格式兼容:新流的尺寸和格式必须在已有硬件管线支持的范围内。
- 帧率不超限:复用后所有流的总帧率需求不能超过ISP的处理能力。
- Surface类型匹配:新Surface必须与已有BufferQueue的分配策略兼容。
注意:配置复用不是万能的。当需要变更Sensor输出尺寸(例如从4K切换到VGA)或切换不同CameraId时,必须重建Session。此外,部分OEM HAL实现存在复用bug,建议在复用前调用
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL确认设备级别为FULL或LEVEL_3。
4.5 代码示例:配置复用的基本流程
// 配置复用的典型实现模式
CameraDevice cameraDevice = ...;
List<Surface> outputSurfaces = new ArrayList<>();
// 第一次创建Session时声明所有可能用到的流
outputSurfaces.add(previewSurface); // 预览流
outputSurfaces.add(imageReader.getSurface()); // 拍照流
outputSurfaces.add(recorderSurface); // 录像流
cameraDevice.createCaptureSession(outputSurfaces,
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(CameraCaptureSession session) {
// Session创建成功,后续可以复用
// 例如:从预览切换到拍照
List<Surface> activeSurfaces = new ArrayList<>();
activeSurfaces.add(previewSurface);
activeSurfaces.add(imageReader.getSurface());
// 直接提交Capture请求,无需重建Session
session.setRepeatingRequest(previewRequest,
callback, handler);
}
}, handler);
// 切换流时:仅更新CaptureRequest中的TargetSurface
// 不调用createCaptureSession(),实现配置复用
关键点:配置复用的前提是
createCaptureSession()时传入的outputSurfaces列表已经包含了所有未来可能使用的Surface。后续通过CaptureRequest.Builder.addTarget()动态选择当前激活的流,而不是重新配置Session。