3. Session 配置基础:createCaptureSession 的调用方式、参数详解及常见错误
在 Android Camera2 框架中,createCaptureSession 是连接 CameraDevice 与 Surface 输出目标的桥梁。正确理解其调用方式与参数含义,是构建高性能多路流并发管线的第一步。本节将深入剖析该 API 的完整签名、参数语义、典型调用模式以及开发者最容易踩入的陷阱。
3.1 API 签名与参数详解
createCaptureSession 方法定义在 CameraDevice 类中,自 API 21 起提供,并在后续版本中增加了重载形式。核心签名如下:
// 基础版本 (API 21+)
public abstract void createCaptureSession(
List<Surface> outputs,
CameraCaptureSession.StateCallback callback,
Handler handler
);
// 带 SessionConfiguration 版本 (API 28+)
public abstract void createCaptureSession(
SessionConfiguration config
);
下表列出了各参数的类型、用途及版本要求:
| 参数 | 类型 | 说明 | 最低 API |
|---|---|---|---|
outputs |
List<Surface> |
Session 输出目标列表,每个 Surface 对应一路输出流(预览、拍照、录像等) | 21 |
callback |
CameraCaptureSession.StateCallback |
Session 状态回调,通知配置成功、失败或断开连接 | 21 |
handler |
Handler |
回调执行的 Handler,若为 null 则使用主线程 Looper | 21 |
config |
SessionConfiguration |
封装 outputs、callback、executor、sessionType 及参数配置的容器 | 28 |
最佳实践:API 28 及以上应优先使用
SessionConfiguration 版本。它支持设置 SessionType(普通/高速)、Executor(避免主线程阻塞)以及 InputConfiguration(用于 reprocess 场景),扩展性远优于基础版本。
3.2 调用方式与典型流程
一个标准的 Session 创建流程包含以下步骤:
- 准备 Surface 列表:从
SurfaceView、ImageReader、MediaRecorder等目标获取 Surface。 - 创建 StateCallback:实现
onConfigured、onConfigureFailed等回调方法。 - 调用 createCaptureSession:传入 Surface 列表与回调。
- 等待回调:在
onConfigured中获取CameraCaptureSession实例,开始发送请求。
以下是一个典型的调用代码示例:
// 1. 准备输出 Surface
Surface previewSurface = surfaceView.getHolder().getSurface();
ImageReader imageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 2);
Surface captureSurface = imageReader.getSurface();
List<Surface> outputSurfaces = new ArrayList<>();
outputSurfaces.add(previewSurface);
outputSurfaces.add(captureSurface);
// 2. 创建回调
CameraCaptureSession.StateCallback sessionCallback =
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
// Session 就绪,可以开始重复请求或单次捕获
captureSession = session;
startPreview(session);
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.e(TAG, "Session 配置失败");
}
};
// 3. 调用 API
cameraDevice.createCaptureSession(outputSurfaces, sessionCallback, backgroundHandler);
常见陷阱:Surface 列表的顺序不影响功能,但 不能包含重复的 Surface 对象。如果同一 Surface 需要被多路复用(例如预览和拍照共用),必须通过
createCaptureRequest 的 addTarget 方法分别添加,而非在 outputs 列表中重复添加。
3.3 Session 配置状态机与回调时序
Session 的创建过程是一个异步状态机。下图展示了从调用 API 到 Session 就绪的完整状态流转:
回调方法触发时机与含义:
| 回调方法 | 触发时机 | 开发者应执行的操作 |
|---|---|---|
onConfigured |
Camera HAL 确认配置有效,Session 就绪 | 保存 Session 引用,开始发送 CaptureRequest |
onConfigureFailed |
HAL 拒绝配置(如输出组合不合法) | 释放资源,尝试降级配置或提示用户 |
onDisconnected |
CameraDevice 意外断开 | 关闭 Session,重新打开 Camera |
onReady |
Session 空闲,无正在处理的请求 | 可用于触发低延迟操作(如快速拍照) |
onActive |
Session 开始处理请求 | 更新 UI 状态(如显示录制指示器) |
onClosed |
Session 完全关闭 | 置空 Session 引用,避免内存泄漏 |
3.4 常见错误与排查方法
根据实际项目经验,以下是最常遇到的 createCaptureSession 错误及其根因:
错误 1:IllegalArgumentException — Surface 已被释放
原因:传入的 Surface 对应的 BufferQueue 已被销毁(如 SurfaceView 已 detach)。
解决:在调用 createCaptureSession 前检查 Surface.isValid(),并确保 Surface 持有者生命周期与 Session 对齐。
原因:传入的 Surface 对应的 BufferQueue 已被销毁(如 SurfaceView 已 detach)。
解决:在调用 createCaptureSession 前检查 Surface.isValid(),并确保 Surface 持有者生命周期与 Session 对齐。
错误 2:CameraAccessException — 最大并发流数超限
原因:outputs 列表中的 Surface 数量超过 Camera 设备支持的 MAXIMUM_OUTPUT_COUNT。
解决:通过
原因:outputs 列表中的 Surface 数量超过 Camera 设备支持的 MAXIMUM_OUTPUT_COUNT。
解决:通过
CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_STREAMS 查询上限,按优先级裁剪流数量。
错误 3:onConfigureFailed — 输出组合不被 HAL 支持
原因:某些分辨率、格式或流类型的组合在特定设备上不被允许(如同时使用 YUV_420_888 和 JPEG 流时尺寸不匹配)。
解决:使用
原因:某些分辨率、格式或流类型的组合在特定设备上不被允许(如同时使用 YUV_420_888 和 JPEG 流时尺寸不匹配)。
解决:使用
StreamConfigurationMap.getOutputSizes() 和 getHighSpeedVideoFpsRange() 验证组合合法性。
错误 4:Session 创建后立即报错 — 重复创建未关闭旧 Session
原因:在未关闭旧 Session 的情况下再次调用 createCaptureSession,导致 HAL 资源冲突。
解决:调用
原因:在未关闭旧 Session 的情况下再次调用 createCaptureSession,导致 HAL 资源冲突。
解决:调用
session.close() 并等待 onClosed 回调后再创建新 Session。
3.5 多路流并发配置的 Surface 组合规则
当配置多路输出流时,Surface 的组合必须遵循 Camera HAL 的约束。下图展示了典型的多路流配置架构:
配置多路流时必须遵守以下规则:
- 分辨率匹配:所有输出流的分辨率必须来自
StreamConfigurationMap.getOutputSizes()中针对该格式的合法列表。 - 格式兼容:同一 Session 中不能同时包含
RAW_SENSOR和YUV_420_888流(部分设备限制)。 - 帧率一致:高速录像模式下,所有流必须使用相同的帧率范围(通过
getHighSpeedVideoFpsRange()查询)。 - 最大流数:普通模式通常支持 3-4 路输出流,高速模式通常限制为 2 路。
调试技巧:当遇到
onConfigureFailed 时,使用 adb shell dumpsys media.camera 查看 HAL 日志,其中会明确输出拒绝配置的原因,如 "Stream configuration not supported" 或 "Too many streams"。