如何使用camera2 API获取设备支持的视频录制精确分辨率列表
安卓Camera2获取真实支持的视频录制分辨率解决方案
安卓不同厂商的硬件抽象层(HAL)实现参差不齐,单独使用任何一种系统API都会存在兼容性问题,推荐采用「交叉过滤+补充校验」的三步走方案:
第一步:交叉过滤候选分辨率列表
分别从StreamConfigurationMap和CamcorderProfile取两个分辨率集合,取交集作为初始候选列表,过滤掉大部分明显不支持的尺寸:
- 从
StreamConfigurationMap取MediaRecorder类对应的输出尺寸,记为集合A - 遍历所有系统标准/厂商自定义的
CamcorderProfile质量等级,取出所有可用的分辨率,记为集合B - 取A和B的交集作为初步过滤后的候选列表
示例代码:
// 取集合A:StreamConfigurationMap返回的MediaRecorder支持尺寸 val characteristics = cameraManager.getCameraCharacteristics(cameraId) val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) val setA = configMap?.getOutputSizes(MediaRecorder::class.java)?.toSet() ?: emptySet() // 取集合B:CamcorderProfile返回的支持尺寸 val standardQualities = listOf( CamcorderProfile.QUALITY_2160P, CamcorderProfile.QUALITY_1080P, CamcorderProfile.QUALITY_720P, CamcorderProfile.QUALITY_480P, CamcorderProfile.QUALITY_HIGH, CamcorderProfile.QUALITY_LOW ) val setB = mutableSetOf<Size>() // 先遍历标准质量等级 for (quality in standardQualities) { if (CamcorderProfile.hasProfile(cameraId, quality)) { val profile = CamcorderProfile.get(cameraId, quality) setB.add(Size(profile.videoFrameWidth, profile.videoFrameHeight)) } } // 补充遍历厂商自定义质量等级(部分厂商会把4K/8K配置放在2000-3000的自定义区间) for (customQuality in 2000..3000) { runCatching { if (CamcorderProfile.hasProfile(cameraId, customQuality)) { val profile = CamcorderProfile.get(cameraId, customQuality) setB.add(Size(profile.videoFrameWidth, profile.videoFrameHeight)) } } } // API 31及以上可以直接调用 getAll 方法获取所有支持的配置,无需手动遍历 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { val allProfiles = CamcorderProfile.getAll(cameraId) allProfiles.forEach { profile -> setB.add(Size(profile.videoFrameWidth, profile.videoFrameHeight)) } } // 取交集按分辨率从高到低排序 val candidateSizes = setA.intersect(setB).sortedByDescending { it.width * it.height }
第二步:补充漏检的4K分辨率
针对CamcorderProfile返回false但实际支持4K的设备,额外增加判断逻辑:
如果StreamConfigurationMap返回的尺寸里包含3840x2160/4096x2160这两种标准4K尺寸,且设备的CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES参数里包含REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR标识,就把对应4K尺寸加入候选列表。
第三步:实际可用性校验(必加)
不管前面怎么过滤,最终都要对候选尺寸做一次实际运行校验,避免厂商HAL返回虚假支持的参数:
对每个候选尺寸,尝试配置MediaRecorder的最小参数,调用prepare()方法没有抛出异常就说明是真实支持的。
示例代码:
fun isSizeSupported(context: Context, cameraId: String, size: Size): Boolean { return runCatching { val recorder = MediaRecorder() recorder.setAudioSource(MediaRecorder.AudioSource.MIC) recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE) // 复用基础编码配置 val baseProfile = CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_1080P) recorder.setOutputFormat(baseProfile.fileFormat) recorder.setVideoEncoder(baseProfile.videoCodec) recorder.setAudioEncoder(baseProfile.audioCodec) // 注意:MediaRecorder.setVideoSize 第一个参数是宽,第二个是高,你之前代码写的setVideoSize(height,width)是错误的,传反会导致本来支持的分辨率报错 recorder.setVideoSize(size.width, size.height) recorder.setVideoFrameRate(30) recorder.setVideoEncodingBitRate(baseProfile.videoBitRate) recorder.setAudioEncodingBitRate(baseProfile.audioBitRate) recorder.setAudioSamplingRate(baseProfile.audioSampleRate) recorder.setOutputFile(File(context.cacheDir, "temp_check.mp4").absolutePath) recorder.prepare() recorder.release() // 校验完成删除临时文件 File(context.cacheDir, "temp_check.mp4").delete() }.isSuccess }
额外优化建议
- 前后置摄像头支持的分辨率差异极大,要分别针对不同摄像头ID做检测
- 校验逻辑不要放在主线程执行,避免页面卡顿
- 对校验通过的分辨率列表做本地缓存,下次启动无需重新检测
内容的提问来源于stack exchange,提问作者mendax01
相关产品推荐
相关产品推荐

