You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 10:33:03