CaptureSession配置复用与多路流并发性能调优 - 第2节
2.1 CaptureRequest 的构建与参数体系
CaptureRequest 是 Camera2 中一次拍照或预览的“指令单”,它封装了所有控制参数和目标输出 Surface。理解其构建过程是复用配置和并发调优的基础。
2.1.1 构建流程
- 从 CameraDevice 创建模板:调用
cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)获得一个初始化的 CaptureRequest.Builder。 - 设置输出 Surface:通过
builder.addTarget(surface)将 Surface 绑定到请求中。每个请求可以绑定多个 Surface,但必须与 OutputConfiguration 中声明的 Surface 一致。 - 注入控制参数:使用
builder.set(CaptureRequest.CONTROL_AE_MODE, ...)等 API 设置曝光、白平衡、对焦等参数。 - 构建请求:调用
builder.build()生成不可变的 CaptureRequest 对象。
关键约束:一个 CaptureRequest 中所有 Surface 必须来自同一个 CameraDevice,且必须与当前 CaptureSession 的 OutputConfiguration 列表匹配。否则会抛出
IllegalArgumentException。
2.1.2 核心参数分类
| 参数类别 | 示例 Key | 作用 |
|---|---|---|
| 3A 控制 | CONTROL_AE_MODE, CONTROL_AF_MODE, CONTROL_AWB_MODE |
自动曝光、对焦、白平衡模式 |
| 传感器 | SENSOR_EXPOSURE_TIME, SENSOR_SENSITIVITY |
曝光时间、ISO 值 |
| 图像处理 | TONEMAP_MODE, EDGE_MODE, NOISE_REDUCTION_MODE |
色调映射、边缘增强、降噪 |
| 输出格式 | JPEG_QUALITY, JPEG_ORIENTATION |
JPEG 压缩质量、旋转方向 |
| 统计信息 | STATISTICS_FACE_DETECT_MODE |
人脸检测、镜头阴影校正等 |
性能提示:在多路流并发场景下,尽量复用同一个 CaptureRequest.Builder 实例,通过
builder.set() 增量修改参数,避免频繁创建 Builder 带来的内存开销。
2.2 OutputConfiguration:Surface 的“配置契约”
OutputConfiguration 是 Camera2 中描述输出 Surface 的配置对象,它定义了 Surface 的格式、大小、旋转、镜像等属性,是 CaptureSession 配置复用的核心单元。
2.2.1 与 Surface 的关系
Surface 是 Android 图形系统的生产者端,而 OutputConfiguration 是对 Surface 的“包装”和“约束”。一个 OutputConfiguration 可以包含一个或多个 Surface(通过 addSurface()),但所有 Surface 必须共享相同的格式和尺寸。
// 创建 OutputConfiguration 的典型方式
Surface previewSurface = surfaceView.getHolder().getSurface();
OutputConfiguration outputConfig = new OutputConfiguration(previewSurface);
// 或者指定格式和尺寸
OutputConfiguration outputConfig2 = new OutputConfiguration(
new Size(1920, 1080), ImageFormat.YUV_420_888);
outputConfig2.setSurface(surface);
2.2.2 关键属性
| 属性 | 类型 | 说明 |
|---|---|---|
| Surface | Surface | 实际的生产者端 Surface |
| SurfaceGroup | SurfaceGroup | 用于共享同一 BufferQueue 的 Surface 组 |
| PhysicalCameraId | String | 多摄像头场景下指定物理摄像头 ID |
| Rotation | int | 输出旋转角度(0/90/180/270) |
| Mirror | boolean | 是否镜像翻转 |
常见错误:在创建 OutputConfiguration 后,如果 Surface 被销毁或重新创建(如 SurfaceView 生命周期变化),必须重新创建 OutputConfiguration 并更新 CaptureSession。复用旧的 OutputConfiguration 会导致
SessionConfiguration 创建失败。
2.3 CaptureRequest 与 OutputConfiguration 的协作流程
下图展示了从 OutputConfiguration 配置到 CaptureRequest 提交的完整数据流:
2.4 多路流并发中的配置复用策略
在多路流场景(如同时预览、拍照、视频录制)中,复用 OutputConfiguration 和 CaptureRequest 可以显著减少配置开销:
2.4.1 OutputConfiguration 复用模式
- 共享 SurfaceGroup:将多个 Surface 放入同一个 SurfaceGroup,共享 BufferQueue,减少内存占用。
- 预创建配置池:在应用启动时创建所有可能用到的 OutputConfiguration 对象,避免运行时动态创建。
- 增量更新:只修改需要变更的 OutputConfiguration 属性(如旋转角度),而不是重新创建整个配置。
2.4.2 CaptureRequest 复用模式
| 模式 | 适用场景 | 实现方式 |
|---|---|---|
| Builder 复用 | 连续预览帧 | 保留 Builder 实例,每次调用 set() 修改参数后 build() |
| 请求缓存 | 固定参数拍照 | 预构建多个 CaptureRequest 对象,按需选择 |
| 参数模板 | 场景切换 | 定义多个参数模板(如夜景、人像),快速切换 |
性能收益:在 30fps 预览 + 1080p 视频录制 + 1200 万像素拍照的三路流场景中,复用 OutputConfiguration 和 CaptureRequest 可以减少约 40% 的配置时间,降低帧率抖动风险。
2.5 常见问题与避坑指南
- Surface 生命周期管理:SurfaceView 的 Surface 在 onPause 后可能被销毁,必须重新创建 OutputConfiguration 并更新 Session。
- 格式不匹配:OutputConfiguration 的格式必须与 Surface 的格式一致,否则
createCaptureSession会失败。 - 多路流 Surface 冲突:同一个 Surface 不能同时出现在两个不同的 OutputConfiguration 中,除非使用 SurfaceGroup。
- 参数覆盖:CaptureRequest 中的参数会覆盖 OutputConfiguration 中的默认设置,但 OutputConfiguration 的旋转和镜像属性优先级更高。
调试建议:使用
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP 查询设备支持的输出配置组合,避免配置不支持的流组合导致性能下降或崩溃。