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

基于Camera2多摄像头API开启后置超广角摄像头问题求助

双后置摄像头录制应用问题解决思路

核心问题分析

你的代码存在几个关键问题导致超广角摄像头无法打开:

  1. 硬编码摄像头ID:直接取getCameraIdList()[2]不可靠,不同设备的摄像头ID分配逻辑不同,必须通过CameraCharacteristics识别摄像头类型。
  2. 重复获取CameraManager:无需创建两个CameraManager实例,一个即可管理所有摄像头。
  3. 权限检查逻辑错误:用&&会导致只要有一个权限授权就跳过请求,应该用||,确保所有必要权限都已获取。
  4. 并发摄像头访问限制:部分设备不支持同时打开两个独立的物理摄像头,建议优先使用逻辑多摄像头API,或者先确认设备是否支持并发访问。

修正后的代码实现

1. 正确识别摄像头类型

先编写工具方法,通过CameraCharacteristics区分主摄像头和超广角摄像头:

private String findCameraId(int lensFacing, float minFocalLength) {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String id : manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
            Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
            Float focalLength = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0];
            
            // 匹配后置摄像头,且焦距小于阈值(超广角焦距通常在0.5-0.8左右)
            if (facing != null && facing == lensFacing 
                && focalLength != null && focalLength <= minFocalLength) {
                return id;
            }
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
    return null;
}

调用方式:

// 主后置摄像头(通常焦距1.0左右)
String mainCameraId = findCameraId(CameraCharacteristics.LENS_FACING_BACK, 1.1f);
// 超广角后置摄像头(焦距<=0.8)
String ultraWideCameraId = findCameraId(CameraCharacteristics.LENS_FACING_BACK, 0.8f);

2. 修正权限检查逻辑

if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED 
    || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(MainActivity.this, 
        new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 
        REQUEST_CAMERA_PERMISSION);
    return;
}

3. 处理并发摄像头访问

方案A:使用逻辑多摄像头(推荐)

逻辑多摄像头会将主摄像头和超广角封装为一个逻辑设备,通过切换焦距实现双镜头录制,兼容性更好:

// 找到支持逻辑多摄像头的设备
private String findLogicalMultiCameraId() {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        for (String id : manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
            Boolean isLogical = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES).contains(
                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA);
            Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
            
            if (isLogical != null && isLogical && facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
                return id;
            }
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
    return null;
}

使用时,打开逻辑摄像头后,通过CaptureRequest.CONTROL_ZOOM_RATIO切换焦距实现超广角录制。

方案B:并发打开物理摄像头(仅部分设备支持)

如果设备支持并发访问,修正后的打开代码:

private void openCamera() {
    CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    Log.e(TAG, "is camera open");

    try {
        String mainCameraId = findCameraId(CameraCharacteristics.LENS_FACING_BACK, 1.1f);
        String ultraWideCameraId = findCameraId(CameraCharacteristics.LENS_FACING_BACK, 0.8f);

        if (mainCameraId == null || ultraWideCameraId == null) {
            Log.e(TAG, "无法找到指定摄像头");
            return;
        }

        // 权限检查
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED 
            || ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, 
                new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 
                REQUEST_CAMERA_PERMISSION);
            return;
        }

        // 打开主摄像头
        manager.openCamera(mainCameraId, stateCallback, null);
        // 打开超广角摄像头(需设备支持并发访问)
        manager.openCamera(ultraWideCameraId, ultraWideCallback, null);

    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
    Log.e(TAG, "openCamera");
}

额外排查点

  • 检查ultraWideCallback的onError方法,打印错误码(如CameraDevice.StateCallback.ERROR_CAMERA_IN_USE表示摄像头被占用),确认具体错误原因。
  • 部分设备需要在AndroidManifest.xml中添加<uses-feature android:name="android.hardware.camera.multiple" android:required="true" />声明,确保应用仅安装在支持多摄像头的设备上。

内容的提问来源于stack exchange,提问作者Mayaank Pillai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 05:13:15