ARCORE与Camera2 API共享相机拍照报未配置Surface错误如何解决?
问题根因
该异常核心是拍照用的ImageReader的Surface未被正确纳入CameraCaptureSession的输出配置,结合ARCore共享相机场景,代码存在三处典型错误:
- 拍照用ImageReader在
shotPhoto触发时才动态创建,此时预览对应的CameraCaptureSession已完成初始化,会话未包含该新增Surface,直接作为捕获请求目标就会触发未配置异常 - 调用
sharedCamera.setAppSurfaces时仅传入拍照用Surface,会覆盖之前已配置的预览用Surface,且调用后未等待ARCore完成配置、未重建捕获会话就直接发起请求 - 获取输出尺寸时使用
SurfaceTexture.class对应的配置,但ImageReader实际使用ImageFormat.JPEG格式,两者尺寸规则不匹配可能导致Surface本身无效
修复方案
1. 提前初始化拍照ImageReader
在相机初始化阶段(和预览ImageReader创建同阶段)就完成拍照ImageReader的创建,获取尺寸时匹配JPEG格式:
// 相机初始化阶段执行,不要放在shotPhoto方法内 CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(this.cameraId); StreamConfigurationMap streamConfigurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); // 取JPEG格式对应的输出尺寸,不要用SurfaceTexture.class Size[] jpegSizes = streamConfigurationMap.getOutputSizes(ImageFormat.JPEG); // 按需选择分辨率,示例取第一个最大分辨率 Size captureSize = jpegSizes[0]; // 全局持有captureReader实例 captureReader = ImageReader.newInstance( captureSize.getWidth(), captureSize.getHeight(), ImageFormat.JPEG, 2 ); captureReader.setOnImageAvailableListener(this, backgroundHandler);
2. 全量传入Surface给ARCore和捕获会话
调用setAppSurfaces时一次性传入所有需要用到的Surface(预览+拍照),同时创建CameraCaptureSession时也将两个Surface都作为输出参数传入:
// ARCore共享相机配置阶段执行 sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(previewReader.getSurface(), captureReader.getSurface())); // 创建CameraCaptureSession时传入所有输出Surface cameraDevice.createCaptureSession(Arrays.asList(previewReader.getSurface(), captureReader.getSurface()), sessionStateCallback, backgroundHandler);
3. 简化拍照逻辑
拍照时直接使用提前初始化好的captureReader的Surface作为捕获目标即可:
public void shotPhoto() { try { CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(cameraDevice.TEMPLATE_STILL_CAPTURE); captureRequestBuilder.addTarget(captureReader.getSurface()); captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, SensorOrientation); CaptureRequest captureRequest = captureRequestBuilder.build(); captureSession.capture(captureRequest, cameraCaptureCallback, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }
补充说明
如果业务必须动态添加拍照Surface,调用setAppSurfaces后必须等待ARCore共享相机的配置完成回调,再重建CameraCaptureSession加入新的Surface,之后才能发起捕获请求。
内容的提问来源于stack exchange,提问作者Rui Fernandes
相关产品推荐
相关产品推荐

