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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:50:21