Camera2 API仅前5张照片可正常工作问题求助
首先,咱们先梳理下你遇到的核心问题:切换到CameraDevice.TEMPLATE_MANUAL模板后,前5次拍照能正常触发onCaptureCompleted,但之后就没响应,还触发错误码0的框架错误,且序列ID每次跳2,超过10就出问题。结合你的代码逻辑,我给你几个针对性的排查和解决方向:
1. 补全手动模板下的CaptureRequest核心参数
TEMPLATE_MANUAL不像预览或拍照模板会自动填充必要的捕获参数,你必须手动设置曝光时间、ISO、对焦模式、白平衡这些核心参数,否则相机框架可能无法正常处理请求,多次请求后会因为参数缺失积累错误。
你可以在创建mCaptureRequest(拍照请求)和mPreviewRequest(预览请求)时,确保设置了这些关键参数:
// 以拍照请求为例,手动设置基础参数 mCaptureRequest = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_MANUAL); // 设置曝光时间(根据设备支持的范围,比如100000ns) mCaptureRequest.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 100000L); // 设置ISO(比如100) mCaptureRequest.set(CaptureRequest.SENSOR_SENSITIVITY, 100); // 因为你不需要自动对焦,设置为固定对焦 mCaptureRequest.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF); // 白平衡设置为自动或固定值 mCaptureRequest.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO); // 别忘了添加输出目标 mCaptureRequest.addTarget(mImageReader.getSurface());
2. 调整拍照流程,移除不必要的abortCaptures()调用
你的拍照逻辑里先调用stopRepeating(),接着立刻abortCaptures(),这可能会把刚提交的拍照请求也给终止掉,尤其是在框架还没来得及处理拍照请求的时候。多次调用abortCaptures()会打乱请求队列的顺序,导致后续请求无法正常触发回调。
建议修改拍照流程,确保预览停止后再提交拍照请求:
// 先停止重复预览,等待停止完成后再提交拍照请求 mCaptureSession.stopRepeating(new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { // 预览已停止,提交拍照请求 session.capture(mCaptureRequest, captureCallback, mBackgroundHandler); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { showToast("Stop preview failed"); } });
如果必须用abortCaptures(),也要放在stopRepeating的回调里确认预览停止后再执行,避免竞态条件。
3. 简化unlockFocus()逻辑,移除多余的单次预览请求
序列ID每次递增2,说明每次拍照时,除了你的拍照请求,还有一个额外的请求被提交——大概率是unlockFocus()里的mCaptureSession.capture(mPreviewRequest, null, mBackgroundHandler)这个单次预览请求。这个请求会和重复预览请求一起占用序列ID,多次积累后导致框架请求队列异常。
建议修改unlockFocus()逻辑,直接恢复重复预览即可:
private void unlockFocus() { // 不需要先提交单次预览请求,直接恢复重复预览 mCaptureSession.setRepeatingRequest(mPreviewRequest, mPreviewCaptureCallback, mBackgroundHandler); }
stopRepeating()后相机会话处于空闲状态,直接设置重复请求就能恢复预览,额外的单次请求只会增加不必要的队列负担。
4. 捕获框架错误的详细信息
错误码0是框架错误,你可以在onCaptureFailed里打印更详细的错误信息,帮你定位具体问题:
@Override public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) { super.onCaptureFailed(session, request, failure); Log.e("Camera2", "Capture failed: reason=" + failure.getReason() + ", seqId=" + failure.getSequenceId()); // 尝试恢复会话 unlockFocus(); }
5. 确保ImageReader的Surface资源及时释放
多次拍照后,mImageReader的Surface可能因为缓存满了或者未及时处理图像数据而异常。你需要确保OnImageAvailableListener里及时关闭图像:
mImageReader.setOnImageAvailableListener(reader -> { Image image = reader.acquireLatestImage(); if (image != null) { // 处理图像数据... image.close(); // 必须关闭,否则会导致Surface资源耗尽 } }, mBackgroundHandler);
按照这几个方向调整后,应该能解决多次拍照后无响应的问题。
内容的提问来源于stack exchange,提问作者Joachim Huet

