Android Camera2 之 CameraCaptureSession 详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/afei__/article/details/86108482

一、简介

CameraCaptureSession 是一个事务,用来向相机设备发送获取图像的请求。

主要有 setRepeatingRequest()capture() 方法。setRepeatingRequest() 是重复请求获取图像数据,常用于预览或连拍,capture() 是获取一次,常用于单张拍照。

CameraCaptureSession 类是一个抽象类,其直接的实现类为 CameraConstrainedHighSpeedCaptureSession

官方文档链接:https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession

二、获取 CameraCaptureSession 实例

通过 CameraDevice 类的 createCaptureSession() 方法创建,并在回调的 onConfigured(CameraCaptureSession session) 方法中获取实例。

示例:

try {
    mCameraDevice.createCaptureSession(Arrays.asList(mPreviewSurface, mImageReader.getSurface()),
            new CameraCaptureSession.StateCallback() {

        @Override
        public void onConfigured(@NonNull CameraCaptureSession session) {
            mCaptureSession = session;
            // ...(省略)
        }

        @Override
        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
            Log.e(TAG, "ConfigureFailed. session: mCaptureSession");
        }
    }, mBackgroundHandler); // handle 传入 null 表示使用当前线程的 Looper
} catch (CameraAccessException e) {
    e.printStackTrace();
}

参数说明:

  • outputs : 输出的 Surface 集合,每个 CaptureRequest 的输出 Surface 都应该是 outputs 的一个子元素。例如上例中使用了一个 mPreviewSurface 用于预览的输出,一个 mImageReader.getSurface() 用于拍照的输出。
  • callback : 创建会话的回调。成功时将调用 onConfigured(CameraCaptureSession session) 方法。
  • handler : 指定回调执行的线程,传 null 时默认使用当前线程的 Looper。

三、内部类

1. CameraCaptureSession.StateCallback

当相机捕捉事务的状态发生变化时,会回调这个类中的相应方法。其中只有 onConfiguredonConfigureFailed 两个方法是抽象的(必须重写),其余均有空实现。

方法名 描述
onConfigureFailed(CameraCaptureSession session) 该会话无法按照相应的配置发起请求时回调
onConfigured(CameraCaptureSession session) 相机设备完成配置,并开始处理捕捉请求时回调
onActive(CameraCaptureSession session) 在 onConfigured 后执行,即开始真的处理捕捉请求了
onCaptureQueueEmpty(CameraCaptureSession session) 当相机设备的输入捕捉队列为空时回调
onClosed(CameraCaptureSession session) 当事务关闭时回调
onReady(CameraCaptureSession session) 每当没有捕捉请求处理时都会回调该方法,即该方法会回调多次

示例: 见上面创建 CameraCaptureSession 的代码即可。

2. CameraCaptureSession.CaptureCallback

当一个捕捉请求发送给相机设备时,可以使用这个类来跟踪各进度。
所有方法均有默认的空实现,根据需求重写相应的方法即可。

方法名 描述
onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) 当相机设备开始为请求捕捉输出图时
onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) 当图像捕获部分进行时就会回调该方法,此时一些(但不是全部)结果是可用的
onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) 当图像捕捉完全完成时,并且结果已经可用时回调该方法
onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) 对应 onCaptureCompleted 方法,当相机设备产生 TotalCaptureResult 失败时就回调该方法
onCaptureSequenceCompleted(CameraCaptureSession session, int sequenceId, long frameNumber) 当一个捕捉段完成时并且所有 CaptureResult 或者 captureFailure 都通过该监听器返回时被回调,这个方法独立于 CaptureCallback 的其他方法
onCaptureSequenceAborted(CameraCaptureSession session, int sequenceId) CaptureResult 或者 captureFailure 没有通过该监听器被返回而被中断时被回调,这个方法同样独立于 CaptureCallback 的其他方法
onCaptureBufferLost(CameraCaptureSession session, CaptureRequest request, Surface target, long frameNumber) 当捕捉的缓冲没有被送到目标 surface 时被回调

示例: 见最下面。

四、常用方法

1. int setRepeatingRequest(CaptureRequest request, CameraCaptureSession.CaptureCallback listener, Handler handler)

不断的重复请求捕捉画面,常用于预览或者连拍场景。

参数解释:

  • request : 不断发送的捕捉请求,不能为 null
  • listener : 捕捉请求的进度监听器,可以为 null
  • handler : 上面这个 listener 回调方法执行的线程,传 null 表示使用当前线程的 Looper。
  • 返回值 : 一个唯一的 sequence ID,用于 CaptureCallback#onCaptureSequenceCompleted

2. int capture(CaptureRequest request, CameraCaptureSession.CaptureCallback listener, Handler handler)

提交一个获取单张图片的捕捉请求,常用于拍照场景。参数解释同上。

3. void stopRepeating()

停止任何一个正常进行的重复请求。

4. void abortCaptures()

尽可能快的取消当前队列中或正在处理中的所有捕捉请求。

5. void close()

异步关闭这个 CameraCaptureSession。应当在相机释放的步骤中对 session 也进行关闭操作。

6. CameraDevice getDevice()

获取该 CameraCaptureSession 创建对应的 CameraDevice 对象。

五、使用示例

1. 创建事务和请求预览

/**
 * Creates a new {@link CameraCaptureSession} for camera preview.
 */
private void createCameraPreviewSession() {
    try {
        SurfaceTexture texture = mTextureView.getSurfaceTexture();
        assert texture != null;
        // We configure the size of default buffer to be the size of camera preview we want.
        texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        // This is the output Surface we need to start preview.
        Surface surface = new Surface(texture);
        // We set up a CaptureRequest.Builder with the output Surface.
        mPreviewRequestBuilder
                = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewRequestBuilder.addTarget(surface);
        // Here, we create a CameraCaptureSession for camera preview.
        mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                new CameraCaptureSession.StateCallback() {

                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                        // The camera is already closed
                        if (null == mCameraDevice) {
                            return;
                        }
                        // When the session is ready, we start displaying the preview.
                        mCaptureSession = cameraCaptureSession;
                        try {
                            // Auto focus should be continuous for camera preview.
                            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                            // Flash is automatically enabled when necessary.
                            setAutoFlash(mPreviewRequestBuilder);
                            // Finally, we start displaying the camera preview.
                            mPreviewRequest = mPreviewRequestBuilder.build();
                            mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                    mCaptureCallback, mBackgroundHandler);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {
                        showToast("Failed");
                    }
                }, null
        );
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

2. 拍照

    private void captureStillPicture() {
        try {
            final Activity activity = getActivity();
            if (null == activity || null == mCameraDevice) {
                return;
            }
            // This is the CaptureRequest.Builder that we use to take a picture.
            final CaptureRequest.Builder captureBuilder =
                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(mImageReader.getSurface());

            // Use the same AE and AF modes as the preview.
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            setAutoFlash(captureBuilder);

            // Orientation
            int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));

            CameraCaptureSession.CaptureCallback captureCallback
                    = new CameraCaptureSession.CaptureCallback() {

                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                               @NonNull CaptureRequest request,
                                               @NonNull TotalCaptureResult result) {
                    showToast("Saved: " + mFile);
                    Log.d(TAG, mFile.toString());
                    unlockFocus();
                }
            };

            mCaptureSession.stopRepeating();
            mCaptureSession.abortCaptures();
            mCaptureSession.capture(captureBuilder.build(), captureCallback, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

我们在 onCaptureCompleted() 回调中执行 unlockFocus() 重新开启预览。而保存图片的逻辑实际是在 mImageReader 的回调中。

3. 完整代码:

https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java

猜你喜欢

转载自blog.csdn.net/afei__/article/details/86108482