如何使用createReprocessCaptureRequest?Camera2实现30FPS连续拍照求助
用Camera2的ReprocessCaptureRequest实现30FPS连续拍照
我之前做过类似的高帧率连续拍照需求,ReprocessCaptureRequest确实是最优解——它能复用预览阶段已经处理好的帧数据,跳过重复的传感器读取和前期图像处理,直接生成拍照输出,完美适配30FPS的要求。结合你给出的代码片段,我给你梳理完整的实现步骤和示例:
核心概念先搞懂
- ReprocessableCaptureSession:专门用于重处理的会话,需要传入
InputConfiguration来指定你要复用的源帧格式/尺寸(就是你代码里的预览尺寸和JPEG格式)。 - ReprocessableCaptureResult:从预览的捕获结果中拿到的“可重处理”对象,只有它能用来创建重处理请求,普通的
CaptureResult不行。 - ReprocessCaptureRequest:基于上述结果创建的请求,直接把源帧转换成你需要的输出(比如JPEG照片),无需重新从传感器取帧。
完整实现步骤
1. 确认设备支持重处理
在打开相机前,先检查设备是否支持重处理:
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); int maxReprocessFrames = characteristics.get(CameraCharacteristics.REPROCESS_MAX_FRAMES); if (maxReprocessFrames <= 0) { // 设备不支持重处理, fallback到普通连续拍照 return; }
2. 创建ReprocessableCaptureSession(你的代码补全)
你已经写了创建会话的开头,这里补全sessionStateCallback的关键实现:
// 定义全局变量保存会话 private ReprocessableCaptureSession mReprocessSession; private ImageReader mImageReader; // 你的现有代码 InputConfiguration inputConfiguration = new InputConfiguration( mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG); mCameraDevice.createReprocessableCaptureSession( inputConfiguration, Arrays.asList(surface, mImageReader.getSurface()), // surface是预览的Surface,mImageReader是拍照输出 new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { mReprocessSession = (ReprocessableCaptureSession) session; // 这里先启动预览,同时保存可重处理的结果 startPreviewWithReprocessResultCapture(); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { // 处理配置失败 } }, mBackgroundHandler);
3. 启动预览并捕获ReprocessableCaptureResult
预览时,需要在CaptureCallback中保存ReprocessableCaptureResult,后续用来创建重处理请求:
private ReprocessableCaptureResult mLatestReprocessResult; private void startPreviewWithReprocessResultCapture() { try { CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previewRequestBuilder.addTarget(surface); mReprocessSession.setRepeatingRequest( previewRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); // 尝试转换为可重处理结果 if (result instanceof ReprocessableCaptureResult) { mLatestReprocessResult = (ReprocessableCaptureResult) result; } } }, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }
4. 创建并提交ReprocessCaptureRequest实现连续拍照
现在就可以用保存的mLatestReprocessResult创建重处理请求,实现高帧率拍照:
// 连续拍照的方法,比如按下快门后调用 private void startContinuousReprocessCapture() { if (mReprocessSession == null || mLatestReprocessResult == null) { return; } try { // 基于最新的可重处理结果创建请求 CaptureRequest.Builder reprocessRequestBuilder = mReprocessSession.createReprocessCaptureRequest(mLatestReprocessResult); // 设置输出到ImageReader(拍照结果) reprocessRequestBuilder.addTarget(mImageReader.getSurface()); // 可以设置JPEG质量等参数 reprocessRequestBuilder.set(CaptureRequest.JPEG_QUALITY, (byte) 90); // 方式1:用setRepeatingRequest实现连续拍摄(自动维持帧率) mReprocessSession.setRepeatingRequest( reprocessRequestBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); // 每次拍照完成的回调,这里可以更新UI } }, mBackgroundHandler); // 方式2:如果需要手动控制拍摄次数,用连续提交singleCapture // for (int i = 0; i < 30; i++) { // mReprocessSession.capture(reprocessRequestBuilder.build(), null, mBackgroundHandler); // } } catch (CameraAccessException e) { e.printStackTrace(); } }
5. 处理ImageReader的输出
别忘了设置ImageReader的监听来获取拍照的JPEG数据:
mImageReader.setOnImageAvailableListener(reader -> { Image image = reader.acquireNextImage(); if (image != null) { // 处理JPEG数据,比如保存到文件 ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); // 保存文件逻辑... image.close(); // 必须关闭,否则会内存泄漏 } }, mBackgroundHandler);
注意事项
- 输入格式匹配:
InputConfiguration的格式必须和预览请求的输出格式一致,比如你用了ImageFormat.JPEG,预览请求的输出也得是JPEG(不过通常预览用YUV_420_880更高效,你可以调整输入格式为YUV,后续重处理转JPEG)。 - 帧率控制:setRepeatingRequest会自动根据设备能力维持最高帧率,如果你需要严格30FPS,可以通过设置
CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE来指定。 - 资源释放:记得在关闭相机时,先停止重复请求,再关闭会话和相机设备,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Ivan Berest
相关产品推荐
相关产品推荐

