Camera2多页面预览和获取相机流

Camera2多页面预览获取相机流

camera2识别拍照的博客已经多的不能再多了,我这里就不再卖弄了。

在工作中遇到一种使用场景,app中有两个页面都可以进行摄像头人脸识别,并且两个页面同时只能有一个页面使用相机。

起初想着只要页面切换时回收相机,再次打开就行了,不料快速切换时导致摄像头黑屏、卡顿,崩溃,网上找了一些博客,最多的就是同页面多窗口预览。只能自己动手封装一个了。经过长久的斗争,终于实现,遂记录一下。

话不多说,现在开始

因为多页面使用摄像头,遂决定使用单例封装一个相机工具类,预览切换只是在不同页面挂载不同的预览,相机流输出始终都一样

  1. 第一步先初始化摄像头
// 预览surface列表
private List<Surface> surfaceList = new ArrayList<>();
// surface与页面对应关系
private HashMap<String, Surface> previewMap = new HashMap<>();
public void initCamera() {
        if (cameraManager == null) {
            cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        }

        surfaceList.clear();
        previewMap.clear();
        try {
            String[] cameraIdList = cameraManager.getCameraIdList();
            if (cameraIdList.length > 0) {
                this.cameraId = cameraIdList[0];
            } else {
                LogUtils.e("initCamera fail, not found camera!!!!");
                reture;
            }
            // 获取指定摄像头的特性
            characteristics = cameraManager.getCameraCharacteristics(this.cameraId);
            // 获取摄像头支持的配置属性
            StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            supportPreview = map.getOutputSizes(SurfaceTexture.class);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            LogUtils.e(e.getMessage());
        }
}
  1. 第二部打开摄像头

动态申请权限,打开摄像头

public void openCamera() {
        if (cameraManager == null) {
            LogUtils.e("camera is not init");
            return;
        }
        try {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(@NonNull CameraDevice cameraDevice) {
                        mCameraDevice = cameraDevice;
                    }

                    @Override
                    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                        LogUtils.e("onDisconnected");
                        mCameraDevice = null;
                    }

                    @Override
                    public void onError(@NonNull CameraDevice cameraDevice, int i) {
                        LogUtils.e("onError");
                        mCameraDevice.close();
                        mCameraDevice = null;
                    }
                }, mBackgroundHandler);
            }

        } catch (CameraAccessException exception) {
            LogUtils.e(exception.getMessage());
        }
    }
  1. 添加预览和相机流输出
 public void addPreview(SurfaceTexture surfaceTexture, String fragmentTag, int width, int height) {
        Size mPreviewSize = PreviewSizeUtil.getOptimalSize(supportPreview, width, height);
        initImageReader(mPreviewSize);

        //设置TextureView的缓冲区大小
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        //获取Surface显示预览数据
        Surface mSurface = new Surface(surfaceTexture);
        previewMap.put(fragmentTag, mSurface);
        takePreview();
        LogUtils.i("open preview by addPreview from %s", fragmentTag);
}
 private void initImageReader(Size previewSize) {
        // 创建一个ImageReader对象,用于获取摄像头的图像数据
        if (imageReader != null) {
            if (!previewMap.containsKey(PREVIEW_IMAGE_READER)) {
                previewMap.put(PREVIEW_IMAGE_READER, imageReader.getSurface());
            }
            return;
        }
        imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
                ImageFormat.YUV_420_888, 2);
        //设置获取图片的监听
        imageReader.setOnImageAvailableListener(imageReader -> {
            // 输出的相机流
        }, mBackgroundHandler);
        previewMap.put(PREVIEW_IMAGE_READER, imageReader.getSurface());
    }
  1. 开启预览
/**
 * 创建预览
 */
private void takePreview() {
        if (mCameraDevice == null) {
            openCamera();
            return;
        }
        try {
            //创建预览请求
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice
                    .TEMPLATE_PREVIEW);

            // 设置自动对焦模式
            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            surfaceList.clear();
            for (Map.Entry<String, Surface> surfaceEntry : previewMap.entrySet()) {
                if (surfaceEntry.getValue() == null) {
                    continue;
                }
                if (PREVIEW_IMAGE_READER.equals(surfaceEntry.getKey())) {
                    surfaceList.add(surfaceEntry.getValue());
                } else {
                    surfaceList.add(0, surfaceEntry.getValue());
                }
                mCaptureRequestBuilder.addTarget(surfaceEntry.getValue());
            }

            //创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行

            if (!hasPreview()) {
                LogUtils.e("not preview surface");
                return;
            }
            mCameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mPreviewSession = session;
                    openPreview();
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }


/**
 * 开启预览
 */
private void openPreview() {
        if (mCameraDevice == null) {
            openCamera();
        }
        try {
            //开始预览
            mCaptureRequest = mCaptureRequestBuilder.build();

            //设置反复捕获数据的请求,这样预览界面就会一直有数据显示
            mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
  1. 停止预览
 /**
 * 停止预览
 */
private void stopPreview() {
    try {
        if (mPreviewSession != null && mCameraDevice != null) {
            mPreviewSession.stopRepeating();
        }
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}
  1. 恢复预览
/**
     * 重新开启预览
     *
     * @param fragmentTag
     */
    public void reStartPreview(String fragmentTag) {
        LogUtils.i("open preview from %s", fragmentTag);
        if (mCaptureRequestBuilder != null && previewMap.containsKey(fragmentTag)) {
            mCaptureRequestBuilder.addTarget(previewMap.get(fragmentTag));
            openPreview();
            mHasPreview = true;
        }
    }
  1. 移除预览
 /**
     * 移除预览
     *
     * @param fragmentTag fragment
     */
    public void removePreview(String fragmentTag) {
        previewMap.remove(fragmentTag);
        LogUtils.i("stop preview by removePreview from %s", fragmentTag);
        stopPreview();
        mHasPreview = false;
    }
  1. 停止相机、回收资源
/**
     * 停止拍照释放资源
     */
    private void stopCamera() {
        if (imageReader != null) {
            imageReader.setOnImageAvailableListener(null, null);
            imageReader.close();
            imageReader = null;
        }
        if (mPreviewSession != null) {
            stopPreview();
            previewMap.clear();
            mPreviewSession.close();
            mPreviewSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        if (cameraManager != null) {
            cameraManager = null;
        }
    }

我们的业务是两个fragment切换的,在fragment的textureView的监听中添加:

private void initTexture() {
        viewBinding.homeTexture.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
            @Override
            public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
                cameraHelper.addPreview(surface, TAG, width, height);
            }

            @Override
            public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

            }

            @Override
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
                cameraHelper.stopPreview(TAG);
                return false;
            }

            @Override
            public void onSurfaceTextureUpdated(SurfaceTexture surface) {

            }
        });
    }

页面隐藏状态变化时,停止或恢复预览

public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (hasCamera.equals(Constants.HAS_CAMERA)) {
            if (!hidden) {
                cameraHelper.reStartPreview(TAG);
            } else {
                cameraHelper.stopPreview(TAG);
            }
        }
    }

因为我们设备型号太多,涉及到摄像头旋转和镜像,我们的代码设计了传入旋转和镜像,如不需要,可使用上方的例子。
我提供下完整帮助类源码:

package com.paintfuture.utils.utils;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Size;
import android.view.Surface;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;

import com.paintfuture.utils.sdk.ShangTangThreadManager;
import com.sensetime.sdk.video.module.sdk.common.StImage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author Leeray
 * @date: 2023/2/7
 */
public class CameraHelper {
    /**
     * imageReader预览帧的key
     */
    public static final String PREVIEW_IMAGE_READER = "imageReader";
    private HandlerThread mBackgroundThread;
    private Handler mBackgroundHandler;
    private HandlerThread stTread;
    private Handler stHandler;
    private String cameraId = "0";
    private static CameraHelper cameraHelper;
    private Context context;
    private CameraManager cameraManager;
    private CameraCharacteristics characteristics;
    private ImageReader imageReader;
    private Size[] supportPreview;
    private CameraDevice mCameraDevice;
    private CameraCaptureSession mPreviewSession;
    private CaptureRequest.Builder mCaptureRequestBuilder;
    private CaptureRequest mCaptureRequest;

    // 预览surface列表
    private List<Surface> surfaceList = new ArrayList<>();
    // surface与页面对应关系
    private HashMap<String, Surface> previewMap = new HashMap<>();
    private boolean mHasPreview = false;

    public static CameraHelper getInstance(Context context) {
        if (cameraHelper == null) {
            cameraHelper = new CameraHelper(context);
        }
        return cameraHelper;
    }

    private CameraHelper(Context context) {
        this.context = context;
    }

    public void initCamera() {
        if (cameraManager == null) {
            cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        }

        surfaceList.clear();
        previewMap.clear();
        try {
            String[] cameraIdList = cameraManager.getCameraIdList();
            if (cameraIdList.length > 0) {
                this.cameraId = cameraIdList[0];
            } else {
                LogUtils.e("initCamera fail, not found camera!!!!");
                return;
            }
            // 获取指定摄像头的特性
            characteristics = cameraManager.getCameraCharacteristics(this.cameraId);
            // 获取摄像头支持的配置属性
            StreamConfigurationMap map = characteristics.get(
                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            supportPreview = map.getOutputSizes(SurfaceTexture.class);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            LogUtils.e(e.getMessage());
        }
        startBackgroundThread();
        startStThread();
    }

    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    private void startStThread() {
        stTread = new HandlerThread("sendFrame");
        stTread.start();
        stHandler = new Handler(stTread.getLooper());
    }

    public boolean hasCamera() {
        String[] cameraIdList = new String[0];
        if (cameraManager == null) {
            cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        }
        try {
            cameraIdList = cameraManager.getCameraIdList();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        return cameraIdList.length > 0;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void openCamera() {
        if (cameraManager == null) {
            LogUtils.e("camera is not init");
            return;
        }
        try {
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
                cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() {
                    @Override
                    public void onOpened(@NonNull CameraDevice cameraDevice) {
                        mCameraDevice = cameraDevice;
                    }

                    @Override
                    public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                        LogUtils.e("onDisconnected");
                        mCameraDevice = null;
                    }

                    @Override
                    public void onError(@NonNull CameraDevice cameraDevice, int i) {
                        LogUtils.e("onError");
                        mCameraDevice.close();
                        mCameraDevice = null;
                    }
                }, mBackgroundHandler);
            }

        } catch (CameraAccessException exception) {
            LogUtils.e(exception.getMessage());
        }
    }

    /**
     * 移除预览
     *
     * @param fragmentTag fragment
     */
    public void removePreview(String fragmentTag) {
        previewMap.remove(fragmentTag);
        LogUtils.i("stop preview by removePreview from %s", fragmentTag);
        stopPreview();
        mHasPreview = false;
    }

    public void removeAllPreview() {
        LogUtils.i("removeAllPreview");
        previewMap.clear();
        stopPreview();
        mHasPreview = false;
    }

    /**
     * 重新开启预览
     *
     * @param fragmentTag
     */
    public void reStartPreview(String fragmentTag) {
        LogUtils.i("open preview from %s", fragmentTag);
        if (mCaptureRequestBuilder != null && previewMap.containsKey(fragmentTag)) {
            mCaptureRequestBuilder.addTarget(previewMap.get(fragmentTag));
            openPreview();
            mHasPreview = true;
        }
    }

    public void previewSizeChange(SurfaceTexture surfaceTexture, String fragmentTag, String cameraType) {
        stopPreview(fragmentTag);
        Size mPreviewSize = PreviewSizeUtil.getOptimalSize(supportPreview, cameraType);
        //设置TextureView的缓冲区大小
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        //获取Surface显示预览数据
        Surface mSurface = new Surface(surfaceTexture);
        previewMap.put(fragmentTag, mSurface);
        openPreview();
        mHasPreview = true;
    }

    /**
     * 停止预览
     *
     * @param fragmentTag
     */
    public void stopPreview(String fragmentTag) {
        LogUtils.i("stop preview from %s", fragmentTag);
        stopPreview();
        mHasPreview = false;
    }

    public void addPreview(@NonNull SurfaceTexture surfaceTexture, String fragmentTag, String cameraType, int angel, int mirror) {
        Size mPreviewSize = PreviewSizeUtil.getOptimalSize(supportPreview, cameraType);
        initImageReader(mPreviewSize, angel, mirror);

        //设置TextureView的缓冲区大小
        surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        //获取Surface显示预览数据
        Surface mSurface = new Surface(surfaceTexture);
        previewMap.put(fragmentTag, mSurface);
        takePreview();
        LogUtils.i("open preview by addPreview from %s", fragmentTag);
    }

    private ReentrantLock lock = new ReentrantLock();
    private final Integer mImageReaderLock = 1;

    private void initImageReader(Size previewSize, int angel, int mirror) {
        // 创建一个ImageReader对象,用于获取摄像头的图像数据
        if (imageReader != null) {
            if (!previewMap.containsKey(PREVIEW_IMAGE_READER)) {
                previewMap.put(PREVIEW_IMAGE_READER, imageReader.getSurface());
            }
            return;
        }
        imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
                ImageFormat.YUV_420_888, 2);
        //设置获取图片的监听
        imageReader.setOnImageAvailableListener(imageReader -> {
            Image image = imageReader.acquireLatestImage();
            if (image == null) {
                return;
            }
            synchronized (mImageReaderLock) {
                if (!mImageReaderLock.equals(1)) {
                    image.close();
                    return;
                }
                if (ImageFormat.YUV_420_888 == image.getFormat()) {
                    lock.lock();
                    try {
                        byte[] bytes = ImageUtil.yuv420ToNv21(image);
                        if (mHasPreview) {
                            byte[] newBytes = new byte[bytes.length];
                            if (angel == 90) {
                                BitMapUtils.rotateNV21_90(bytes, newBytes, previewSize.getHeight(),
                                        previewSize.getWidth());
                            } else if (angel == 180) {
                                BitMapUtils.rotateNV21_180(bytes, newBytes, previewSize.getHeight(),
                                        previewSize.getWidth());
                            } else if (angel == 270) {
                                BitMapUtils.rotateNV21_270(bytes, newBytes, previewSize.getHeight(),
                                        previewSize.getWidth());
                            } else {
                                newBytes = bytes;
                            }

                            // 是否需要镜面旋转
                            if (mirror == 180) {
                                newBytes = BitMapUtils.frameMirror(newBytes, previewSize.getWidth(), previewSize.getHeight());
                            }
                            if (angel == 0 && mirror == 0) {
                                sendFrameToSt(newBytes, image.getWidth(), image.getHeight());
                            } else {
                                sendFrameToSt(newBytes, previewSize.getWidth(), previewSize.getHeight());
                            }
                        }
                    } catch (Exception exception) {
                        LogUtils.e("onImageAvailable error: %s", exception.getMessage());
                    } finally {
                        lock.unlock();
                    }
                }
            }
            image.close();
        }, mBackgroundHandler);
        previewMap.put(PREVIEW_IMAGE_READER, imageReader.getSurface());
    }

    private void takePreview() {
        if (mCameraDevice == null) {
            openCamera();
            return;
        }
        try {
            //创建预览请求
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice
                    .TEMPLATE_PREVIEW);

            // 设置自动对焦模式
            mCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            surfaceList.clear();
            for (Map.Entry<String, Surface> surfaceEntry : previewMap.entrySet()) {
                if (surfaceEntry.getValue() == null) {
                    continue;
                }
                if (PREVIEW_IMAGE_READER.equals(surfaceEntry.getKey())) {
                    surfaceList.add(surfaceEntry.getValue());
                } else {
                    surfaceList.add(0, surfaceEntry.getValue());
                }
                mCaptureRequestBuilder.addTarget(surfaceEntry.getValue());
            }

            //创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行

            if (!hasPreview()) {
                LogUtils.e("not preview surface");
                return;
            }
            mCameraDevice.createCaptureSession(surfaceList, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mPreviewSession = session;
                    openPreview();
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }


    /**
     * 是否存在预览页面
     *
     * @return
     */
    private boolean hasPreview() {
        boolean hasPreview = false;
        for (Map.Entry<String, Surface> surfaceEntry : previewMap.entrySet()) {
            if (!PREVIEW_IMAGE_READER.equals(surfaceEntry.getKey())) {
                hasPreview = true;
                break;
            }
        }
        mHasPreview = hasPreview;
        return hasPreview;
    }

    public Matrix configureTextureViewTransform(int viewWidth, int viewHeight, int width,
                                                int height, int cameraRotation) {
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, width,
                height);
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (cameraRotation == 90 || cameraRotation == 270) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / viewWidth,
                    (float) viewWidth / viewHeight);
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(cameraRotation, centerX, centerY);
        } else if (180 == cameraRotation) {
            matrix.postRotate(180, centerX, centerY);
        }
        return matrix;
    }

    /**
     * 数据帧发送商汤
     *
     * @param frameInfo
     * @param width
     * @param height
     */
    private void sendFrameToSt(byte[] frameInfo, int width, int height) {
        stHandler.post(() -> {
            StImage stImage = new StImage(width, height, width, StImage.StPixelFormat.PixFmtNV21,
                    frameInfo);
            ShangTangThreadManager.QueueInfo queueInfo = new ShangTangThreadManager
                    .QueueInfo(System.currentTimeMillis(), stImage);
            ShangTangThreadManager.mAllImagesQueue[0].offer(queueInfo);
        });
    }

    /**
     * 开启预览
     */
    private void openPreview() {
        if (mCameraDevice == null) {
            openCamera();
        }
        try {
            //开始预览
            mCaptureRequest = mCaptureRequestBuilder.build();

            //设置反复捕获数据的请求,这样预览界面就会一直有数据显示
            mPreviewSession.setRepeatingRequest(mCaptureRequest, null, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止预览
     */
    private void stopPreview() {
        try {
            if (mPreviewSession != null && mCameraDevice != null) {
                mPreviewSession.stopRepeating();
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void stopBackgroundThread() {
        if (mBackgroundThread == null || stTread == null) {
            return;
        }
        mBackgroundThread.quitSafely();
        stTread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
            stTread.join();
            stTread = null;
            stHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止拍照释放资源
     */
    private void stopCamera() {
        if (imageReader != null) {
            imageReader.setOnImageAvailableListener(null, null);
            imageReader.close();
            imageReader = null;
        }
        if (mPreviewSession != null) {
            stopPreview();
            previewMap.clear();
            mPreviewSession.close();
            mPreviewSession = null;
        }
        if (mCameraDevice != null) {
            mCameraDevice.close();
            mCameraDevice = null;
        }
        if (cameraManager != null) {
            cameraManager = null;
        }
    }

    public void cameraRelease() {
        stopCamera();
        stopBackgroundThread();
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Camera2 API 进行相机预览需要以下步骤: 1. 获取相机服务。 ```java CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); ``` 2. 获取相机 ID。 ```java String cameraId = cameraManager.getCameraIdList()[0]; ``` 3. 打开相机。 ```java cameraManager.openCamera(cameraId, new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) { mCameraDevice = camera; } @Override public void onDisconnected(CameraDevice camera) { camera.close(); mCameraDevice = null; } @Override public void onError(CameraDevice camera, int error) { camera.close(); mCameraDevice = null; } }, null); ``` 4. 创建预览请求。 ```java private void createPreviewSession() { try { SurfaceTexture texture = mTextureView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(texture); mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession session) { mCaptureSession = session; try { mPreviewRequest = mPreviewRequestBuilder.build(); mCaptureSession.setRepeatingRequest(mPreviewRequest, null, null); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession session) { Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_SHORT).show(); } }, null); } catch (CameraAccessException e) { e.printStackTrace(); } } ``` 5. 开始预览。 ```java private void startPreview() { try { createPreviewSession(); } catch (CameraAccessException e) { e.printStackTrace(); } } ``` 注意:以上代码仅供参考,具体实现可能需要根据实际需求进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值