Android Camera API 介绍
一 StreamConfigurationMap
1. StreamConfigurationMap 的作用
StreamConfigurationMap
是 Android Camera2 API 中的一个核心类,用于描述相机设备支持的输出流配置,包含以下信息:
- 支持的格式与分辨率:例如
YUV_420_888
、JPEG
、RAW
等格式及其对应的分辨率列表。 - 输入/输出流组合规则:例如哪些格式可以同时用于
预览
、拍照
或录像
。 - 硬件能力限制:例如是否支持
硬件级图像处理
(如YUV 重处理
)、动态范围模式
(HDR)等。 - 帧率与时长限制:如某些分辨率下支持的最小/最大帧率,或视频录制的最大时长。
应用通过 CameraCharacteristics
获取 StreamConfigurationMap
,并基于此配置合理的 CaptureSession
(例如选择预览和拍照的兼容分辨率)。
2. 与 cameraprovider 交互关系
(1) 数据来源
- CameraProvider 提供原始数据:
Camera HAL 实现(如android.hardware.camera.provider@2.4
)通过getCameraCharacteristics()
方法向框架上报硬件能力,包括支持的流配置(格式、分辨率、动态范围等)。 - 框架封装为 StreamConfigurationMap:
框架层(如CameraService
)解析 HAL 返回的元数据,将其转换为应用可直接使用的StreamConfigurationMap
。
(2) 配置流程示例
- 应用请求相机能力:
应用调用CameraManager.getCameraCharacteristics(cameraId)
。 - 框架查询 HAL:
CameraService
通过CameraProvider
的 HAL 接口获取该相机的元数据。 - HAL 返回底层配置:
CameraProvider
从硬件或板级配置文件(如cam_board.xml
)中读取支持的流配置,传递给框架。 - 构建 StreamConfigurationMap:
框架将原始数据(如SCALER_AVAILABLE_STREAM_CONFIGURATIONS
)封装为StreamConfigurationMap
对象。 - 应用使用配置:
应用根据StreamConfigurationMap
选择兼容的流组合(例如同时支持1080p@30fps
预览和12MP
拍照)。
(3) 关键数据结构对应
HAL 元数据字段(如 android.scaler ) | StreamConfigurationMap 方法 | 作用 |
---|---|---|
SCALER_AVAILABLE_STREAM_CONFIGURATIONS | getOutputSizes(int format) | 获取某格式支持的分辨率列表 |
SCALER_AVAILABLE_MIN_FRAME_DURATIONS | getOutputMinFrameDuration(int format) | 获取某分辨率下最小帧间隔(决定最大帧率) |
REQUEST_AVAILABLE_CAPABILITIES | isOutputSupportedFor(int useCase) | 检查是否支持特定用例(如 ZSL) |
3. 实际示例
假设一个相机设备支持以下配置(通过 CameraProvider
上报):
- YUV_420_888: 1920x1080@30fps, 1280x720@60fps
- JPEG: 4000x3000@10fps
则 StreamConfigurationMap
会生成如下信息:
// 获取 YUV 格式支持的分辨率
Size[] yuvSizes = streamConfigMap.getOutputSizes(ImageFormat.YUV_420_888);
// 结果: [1920x1080, 1280x720]
// 检查是否支持硬件级 YUV 重处理
boolean isReprocessSupported = streamConfigMap.isOutputSupportedFor(
CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
StreamConfigurationMap
是应用层获取相机输出能力的接口,而 CameraProvider
是底层硬件能力的提供者。前者依赖后者上报的元数据,二者共同实现 硬件能力到应用接口的透明映射,是 Android Camera 系统分层架构的核心设计之一。
在 Android 相机系统(Camera2 API)中,OutputConfiguration
和 StreamConfigurationMap
是与相机输出流配置相关的两个关键类,它们在相机工作流程中扮演不同角色。以下是它们的详细介绍及关系分析:
二. OutputConfiguration
1 作用
作用:
OutputConfiguration
是 Android 5.0(API 21)引入的类,用于定义单个相机输出流的配置。它的核心功能包括:
-
封装输出目标(如
Surface
或SurfaceView
)。 -
配置物理相机(在多摄像头设备中指定物理传感器)。
-
管理共享输出流(允许多个
Surface
共享同一输出流)。 -
使用场景:
当创建CameraCaptureSession
时,需传入一组OutputConfiguration
对象,描述所有输出流。 -
关键方法:
addSurface(Surface surface)
:添加共享的Surface
。setPhysicalCameraId(String id)
:指定物理相机(用于双摄/多摄设备)。getSurfaces()
:获取关联的Surface
列表。
-
示例:
// 创建 ImageReader 并获取 Surface ImageReader imageReader = ImageReader.newInstance(width, height, format, maxImages); Surface imageSurface = imageReader.getSurface(); // 创建 OutputConfiguration OutputConfiguration outputConfig = new OutputConfiguration(imageSurface); // 可选:配置共享 Surface 或物理相机 // outputConfig.addSurface(anotherSurface); // outputConfig.setPhysicalCameraId("2"); // 创建 CameraCaptureSession List<OutputConfiguration> outputConfigs = new ArrayList<>(); outputConfigs.add(outputConfig); cameraDevice.createCaptureSessionByOutputConfigurations(outputConfigs, callback, handler);
2. 与 StreamConfigurationMap 关系
-
协作流程:
- Step 1:通过
StreamConfigurationMap
查询设备支持的输出参数(格式、分辨率等)。 - Step 2:根据合法参数创建输出目标(如
ImageReader
或SurfaceView
)。 - Step 3:将输出目标封装到
OutputConfiguration
,用于创建CameraCaptureSession
。
- Step 1:通过
-
依赖关系:
OutputConfiguration
的参数(如格式、分辨率)必须符合StreamConfigurationMap
的约束,否则会话创建会失败。StreamConfigurationMap
提供理论支持,OutputConfiguration
负责实际配置。
-
扩展功能:
OutputConfiguration
支持高级功能(如多摄像头共享输出流),而StreamConfigurationMap
仅描述硬件能力。- 在 Android 10(API 29)后,
OutputConfiguration
新增对动态分辨率、物理摄像头绑定的支持。
3. 常见问题
-
Q1: 为什么需要同时使用两者?
A:是相机设备的“能力说明书”,告诉开发者硬件支持哪些输出配置。
OutputConfiguration是实际构建输出流的“施工图”,将合法的参数绑定到具体的
Surface`。 -
二者配合确保相机输出流的正确性和高效性
-
Q2: 如何避免
InvalidSurfaceException
?
A: 确保OutputConfiguration
的Surface
参数(格式、分辨率)在StreamConfigurationMap
的合法范围内。 -
Q3: 多摄像头场景如何处理?
A: 使用OutputConfiguration.setPhysicalCameraId()
指定物理摄像头,并通过StreamConfigurationMap
检查该摄像头是否支持目标参数。
总结
StreamConfigurationMap
是相机设备的“能力说明书”,告诉开发者硬件支持哪些输出配置。OutputConfiguration
是实际构建输出流的“施工图”,将合法的参数绑定到具体的Surface
。- 二者配合确保相机输出流的正确性和高效性,是 Camera2 API 中不可或缺的组件。
在 Android Camera2 API 中,CameraCaptureSession
是管理相机数据流和捕获请求的核心组件。它与 OutputConfiguration
密切相关,共同决定了相机的输出目标(如预览、拍照、录像等)的配置和运行机制。以下是详细解释及其与 OutputConfiguration
的关系:
三 CameraCaptureSession
1. 作用
CameraCaptureSession
是相机设备(CameraDevice
)与输出目标(Surface
)之间的桥梁,负责:
- 管理输出流:绑定多个
Surface
(如预览的SurfaceView
、拍照的ImageReader
),并确保数据正确传输到这些目标。 - 提交捕获请求:通过
capture()
或setRepeatingRequest()
发送请求(CaptureRequest
),控制相机的行为(如自动对焦、曝光、帧率等)。 - 处理异步事件:监听相机状态(如对焦完成、帧捕获完成)并回调给应用。
2 生命周期
- 创建:通过
CameraDevice.createCaptureSession()
或createCaptureSessionByOutputConfigurations()
创建。 - 活动状态:可提交捕获请求,相机数据流向绑定的
Surface
。 - 关闭:调用
close()
释放资源,不可再发送请求。
3.创建 CameraCaptureSession
创建会话时,需要指定一组输出目标(Surface
或 OutputConfiguration
)。两种方法:
-
传统方式(基于
Surface
列表):cameraDevice.createCaptureSession( List<Surface> outputs, // 直接传递 Surface 列表 CameraCaptureSession.StateCallback callback, Handler handler );
- 适用于简单场景,但灵活性有限(例如不支持多摄像头或动态分辨率)。
-
基于
OutputConfiguration
的方式(API 21+,扩展功能在后续版本增强):cameraDevice.createCaptureSessionByOutputConfigurations( List<OutputConfiguration> outputConfigurations, // 封装了 Surface 的高级配置 CameraCaptureSession.StateCallback callback, Handler handler );
- 支持更复杂的配置(如共享流、物理摄像头绑定、动态分辨率等)。
4. 与 OutputConfiguration 的关系
(1) OutputConfiguration 是会话的输入
-
功能:
OutputConfiguration
封装了一个或多个Surface
的配置信息,用于定义输出流的特性:- 单个或共享的
Surface
:通过addSurface()
添加多个Surface
,共享同一数据流(例如预览和录像共享同一帧数据)。 - 物理摄像头绑定:在双摄/多摄设备中,通过
setPhysicalCameraId()
指定输出流来自哪个物理摄像头。 - 动态分辨率(API 23+):允许在会话运行时动态调整分辨率(需硬件支持)。
- 单个或共享的
-
优势:相比直接传递
Surface
列表,OutputConfiguration
提供了更细粒度的控制能力。
(2) 创建会话的流程
- 查询设备支持:通过
StreamConfigurationMap
确认相机支持的格式和分辨率。 - 创建输出目标:根据合法参数创建
Surface
(如ImageReader
、SurfaceView
)。 - 封装为 OutputConfiguration:将
Surface
及其附加配置(如物理摄像头)封装到OutputConfiguration
。 - 创建会话:调用
createCaptureSessionByOutputConfigurations()
,传入OutputConfiguration
列表。
(3) 关键约束
- 不可变性:一旦
CameraCaptureSession
创建成功,其绑定的OutputConfiguration
不可修改(如新增或移除Surface
)。若需更改,必须关闭当前会话并重新创建。 - 硬件限制:
OutputConfiguration
的配置(如分辨率、格式)必须符合StreamConfigurationMap
的支持范围。
4. 示例:使用 OutputConfiguration 创建会话
// 创建两个输出目标:预览 Surface 和拍照 ImageReader
SurfaceView surfaceView = ... // 预览的 SurfaceView
ImageReader imageReader = ImageReader.newInstance(4032, 3024, ImageFormat.JPEG, 3);
// 封装为 OutputConfiguration
OutputConfiguration previewConfig = new OutputConfiguration(surfaceView.getHolder().getSurface());
OutputConfiguration captureConfig = new OutputConfiguration(imageReader.getSurface());
// 可选:配置共享流或物理摄像头
// previewConfig.addSurface(anotherSurface); // 共享同一个流
// captureConfig.setPhysicalCameraId("1"); // 指定物理摄像头
List<OutputConfiguration> outputConfigs = new ArrayList<>();
outputConfigs.add(previewConfig);
outputConfigs.add(captureConfig);
// 创建 CameraCaptureSession
cameraDevice.createCaptureSessionByOutputConfigurations(outputConfigs,
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
// 会话就绪,可提交 CaptureRequest
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
// 配置失败(参数不合法或硬件问题)
}
},
null // 可选 Handler
);
5. 高级功能与兼容性
-
共享流(Shared Surfaces):
- 多个
Surface
共享同一输出流(例如预览和 AI 分析共享数据),减少内存和功耗。 - 实现方式:通过
OutputConfiguration.addSurface()
添加多个Surface
。
- 多个
-
动态分辨率(Dynamic Resolution)(API 23+):
- 允许在会话运行时动态调整输出分辨率(需设备支持)。
- 通过
OutputConfiguration.setDynamicRangeProfile()
配置。
-
多摄像头支持(API 28+):
- 在双摄设备中,通过
OutputConfiguration.setPhysicalCameraId()
指定输出流来源。
- 在双摄设备中,通过
6. 常见问题与解决方案
-
问题1:
createCaptureSession
失败,错误为IllegalArgumentException
。
原因:OutputConfiguration
参数不合法(如分辨率超出支持范围)。
解决:检查StreamConfigurationMap
的合法参数。 -
问题2:无法在运行时修改输出流。
原因:CameraCaptureSession
的配置不可变。
解决:关闭当前会话,重新创建新的会话。 -
问题3:多摄像头场景下数据流混乱。
原因:未正确指定setPhysicalCameraId()
。
解决:确保每个OutputConfiguration
绑定到正确的物理摄像头。
总结
CameraCaptureSession
:是相机数据流的核心控制器,负责管理输出目标和捕获请求。- 与
OutputConfiguration
的关系:OutputConfiguration
是会话的输入,定义了每个输出流的具体配置(如Surface
、物理摄像头)。CameraCaptureSession
通过OutputConfiguration
的配置,确保数据流符合硬件能力(由StreamConfigurationMap
定义)。- 使用
OutputConfiguration
可以启用高级功能(如共享流、多摄像头),而传统Surface
列表方式功能受限。
通过合理使用 OutputConfiguration
,开发者可以更灵活地配置相机输出流,满足复杂场景的需求(如多摄、动态分辨率、低功耗共享流)。