4. 相机采集参数配置
相机采集参数配置是 Android 相机开发中最容易“看起来简单、实际踩坑”的一环。分辨率、帧率、输出格式、裁剪区域(Crop Region)以及设备兼容性,彼此之间存在强耦合关系:提高分辨率往往压缩可用帧率,切换格式可能改变支持的尺寸集合,设置裁剪区域又可能触发传感器模式切换。理解这些参数之间的约束链,是保证预览流畅、拍照清晰、录像稳定的前提。
一、四个核心参数及其相互约束
在 Camera2 体系中,采集参数主要通过 CaptureRequest 与 CameraCharacteristics 协同表达。开发者需要先读取设备能力,再在能力范围内组合参数。
- 分辨率(Size):由
StreamConfigurationMap.getOutputSizes(format)给出。不同格式(JPEG、YUV_420_888、PRIVATE)支持的尺寸集合不同,不能混用。 - 帧率(FPS Range):通过
CONTROL_AE_TARGET_FPS_RANGE设置,常见如 [30,30]、[15,30]、[24,30]。固定帧率利于录像,可变范围利于暗光提亮。 - 输出格式(Format):预览常用 PRIVATE 或 YUV_420_888,拍照用 JPEG,视频编码常用 PRIVATE 直连 MediaCodec。
- 裁剪区域(Crop Region):由
SCALER_CROP_REGION控制,决定传感器有效成像区域,影响视场角与数码变焦。
关键约束在于:高分辨率 + 高帧率 + 大裁剪区域往往无法同时满足。设备通常为每种分辨率提供一组可用帧率范围,超出组合会被底层拒绝或静默降级。因此配置顺序应是:先确定业务目标(预览/拍照/录像),再锁定格式与分辨率,最后在该组合允许的范围内选择帧率与裁剪。
二、设备兼容性适配策略
Android 设备碎片化严重,同一套参数在不同机型上表现差异明显。适配的核心思路是“能力查询优先、降级兜底”。
- 查询能力:通过
StreamConfigurationMap获取各格式支持的尺寸与帧率,通过INFO_SUPPORTED_HARDWARE_LEVEL判断设备等级(LEGACY / LIMITED / FULL / LEVEL_3)。 - 选择尺寸:优先选择与目标宽高比一致的尺寸,避免拉伸变形;预览与拍照尽量使用相同宽高比。
- 帧率协商:若目标帧率不被支持,按 [30,30] → [15,30] → 默认范围逐级降级。
- 裁剪校验:裁剪区域必须落在
SENSOR_INFO_ACTIVE_ARRAY_SIZE范围内,且宽高比与输出流匹配。
三、参数组合与裁剪关系示意
下图展示了从设备能力查询到最终参数组合的适配链路,以及分辨率、帧率、格式、裁剪四者之间的约束关系。图中标注了典型示例值,仅用于说明组合逻辑,实际取值需以设备查询结果为准。
四、实际配置示例与判断依据
以下示例展示如何在代码中查询能力并组合参数。示例中的尺寸与帧率均为常见机型的典型值,实际运行时应以查询结果为准。
// 1. 查询能力
CameraCharacteristics chars = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = chars.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
// 2. 选择预览尺寸(优先 16:9,接近 1080p)
Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);
Size previewSize = chooseSize(previewSizes, 1920, 1080);
// 3. 选择拍照尺寸(JPEG 最大)
Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG);
Size photoSize = Collections.max(Arrays.asList(jpegSizes),
(a, b) -> Long.compare((long)a.getWidth()*a.getHeight(),
(long)b.getWidth()*b.getHeight()));
// 4. 帧率范围协商
Range<Integer>[] fpsRanges = chars.get(
CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
Range<Integer> targetFps = pickFpsRange(fpsRanges, 30);
// 5. 裁剪区域(默认全传感器)
Rect activeArray = chars.get(
CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Rect cropRegion = activeArray; // 需要数码变焦时按比例收缩
// 6. 下发请求
captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFps);
captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, cropRegion);
判断配置是否生效,可从三方面观察:预览画面是否变形(宽高比不匹配)、帧率是否稳定(可通过 CameraCaptureSession.CaptureCallback 统计时间戳间隔)、拍照分辨率是否符合预期。若出现黑屏或 IllegalArgumentException,通常是尺寸与格式不匹配或裁剪区域越界。
五、常见兼容性问题与处理
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| 预览拉伸变形 | 预览与输出宽高比不一致 | 统一使用相同宽高比尺寸 |
| 帧率低于预期 | 分辨率过高或暗光降帧 | 降低分辨率或放宽 FPS 下限 |
| 拍照模糊 | 裁剪区域与对焦区域不匹配 | 同步更新 AF Region 与 Crop Region |
| 部分机型黑屏 | 格式与尺寸组合不支持 | 查询后选择合法组合,增加兜底 |
总结来看,采集参数配置的本质是在设备能力边界内做优先级取舍。建议把“能力查询 → 参数组合 → 降级兜底 → 结果校验”固化为初始化流程,并为不同硬件等级准备差异化策略,这样才能在碎片化设备上保持稳定的采集表现。