基于Camera2多摄像头API开启后置超广角摄像头问题求助
双后置摄像头录制应用问题解决思路
核心问题分析
你的代码存在几个关键问题导致超广角摄像头无法打开:
- 硬编码摄像头ID:直接取
getCameraIdList()[2]不可靠,不同设备的摄像头ID分配逻辑不同,必须通过CameraCharacteristics识别摄像头类型。 - 重复获取CameraManager:无需创建两个
CameraManager实例,一个即可管理所有摄像头。 - 权限检查逻辑错误:用
&&会导致只要有一个权限授权就跳过请求,应该用||,确保所有必要权限都已获取。 - 并发摄像头访问限制:部分设备不支持同时打开两个独立的物理摄像头,建议优先使用逻辑多摄像头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
相关产品推荐
相关产品推荐

