返回

Camera2入门:TextureView实现预览和拍照

Android

使用 Camera2 API 和 TextureView 实现 Android 相机功能

相机预览

在 Android 应用中实现相机预览需要以下步骤:

  1. 添加 TextureView: TextureView 是一种专门用于处理图像和视频内容的视图控件。在布局文件中添加 TextureView 以显示相机预览:
<TextureView
    android:id="@+id/texture_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  1. 添加监听事件: TextureView 提供了一个监听器,当其 SurfaceTexture 可用时触发。在代码中添加监听器:
TextureView textureView = findViewById(R.id.texture_view);
textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
        // 当 SurfaceTexture 可用时,设置相机参数并打开相机
    }
  1. 设置相机参数并打开相机: 当 SurfaceTexture 可用时,我们需要设置相机参数并打开相机:
private void setupCamera(int width, int height) {
    CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
    try {
        String cameraId = cameraManager.getCameraIdList()[0];
        CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);

        StreamConfigurationMap streamConfigurationMap = cameraCharacteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

        // 设置预览尺寸
        Size previewSize = streamConfigurationMap.getOutputSizes(SurfaceTexture.class)[0];

        // 创建相机预览会话
        SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
        surfaceTexture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());

        Surface surface = new Surface(surfaceTexture);

        List<Surface> outputSurfaces = new ArrayList<>();
        outputSurfaces.add(surface);

        CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
            @Override
            public void onOpened(CameraDevice cameraDevice) {
                // 相机已打开,开始预览
                cameraDevice.createCaptureSession(outputSurfaces, new CaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(CaptureSession session) {
                        try {
                            // 设置预览请求
                            CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            previewRequestBuilder.addTarget(surface);

                            CaptureRequest previewRequest = previewRequestBuilder.build();

                            // 开始预览
                            session.setRepeatingRequest(previewRequest, null, null);
                        } catch (CameraAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }, null);
            }
        };

        cameraManager.openCamera(cameraId, stateCallback, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

拍照

要实现拍照,我们需要执行以下步骤:

  1. 创建 CameraCaptureSession.CaptureCallback: CameraCaptureSession.CaptureCallback 用于处理拍照完成后的操作:
private final CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
        // 拍照完成
    }
};
  1. 创建 CaptureRequest.Builder: CaptureRequest.Builder 用于设置拍照参数:
CaptureRequest.Builder captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(imageReader.getSurface());
  1. 创建 CaptureRequest: CaptureRequest 是最终用于拍照的请求:
CaptureRequest captureRequest = captureRequestBuilder.build();
  1. 开始拍照: 使用 CaptureSession 发出拍照请求:
cameraSession.capture(captureRequest, captureCallback, null);

常见问题解答

  1. 如何调整相机分辨率?

    • 可以在 StreamConfigurationMap 中找到受支持的分辨率列表,并在 createCaptureRequest 中设置所需的尺寸。
  2. 如何控制对焦和曝光?

    • Camera2 API 允许使用 CaptureRequest.Builder 设置对焦和曝光参数,如对焦模式和曝光时间。
  3. 如何保存捕获的图像?

    • 创建一个 ImageReader 来捕获图像数据,并在 onCaptureCompleted 回调中保存图像。
  4. 如何实现连拍模式?

    • 使用 createBurstCaptureRequestList 方法创建突发请求列表,然后使用 setRepeatingBurst 方法设置突发模式。
  5. 如何使用前置和后置摄像头?

    • CameraManager 提供了 getCameraIdList 方法,可以用来获取设备上的可用摄像头列表,其中包括前置和后置摄像头。