Camera2相机拍照流程之预览功能梳理

1、获取CameraManager 相机管理器

        CameraManager是通过获取系统服务方式获取CameraManager对象

// 获取CameraManager 相机设备管理器
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

2、打开摄像头并展示预览画面

        2.1 监听显示预览控件状态

        activity被显示出来(执行到Activity的onResume方法)时,判断显示相机预览的控件TextTure是否可用,可用的话则打开相机;否则注册SurfaceTextureListener监听器对象,当可用是会回调onSurfaceTextureAvailable()函数,在此函数中进行打开相机:

        1、创建activity时第一次走到OnResume()时,会先走else逻辑,因为此时TextTure还不可用,需要注册SurfaceTextureListener监听器,监听器中监听到TextTure可用时(即onSurfaceTextureAvailable)这时会首次打开摄像头;

        2、后面再进入到activity的OnResume()时,则直接打开摄像头。

@Override
protected void onResume() {
    super.onResume();
    if (texture.isAvailable()) {
        openCamera(texture.getWidth(), texture.getHeight(), mCameraId);
    } else {
        texture.setSurfaceTextureListener(textureListener);
    }
    startBackgroundThread();
}


/**
 * TextureView 生命周期响应
 */
private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
    @Override //创建
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        //当TextureView创建完成,打开指定摄像头相机
        openCamera(width, height, mCameraId);
    }

    @Override //尺寸改变
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

    }

    @Override //销毁
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        return false;
    }

    @Override //更新
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {

    }
};

        2.2 打开摄像头,展示相机预览

/**
 * 打开指定摄像头ID的相机
 *
 * @param width
 * @param height
 * @param cameraId
 */
private void openCamera(int width, int height, int cameraId) {
    if (ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
        // TODO: Consider calling
        //return;
        requestPermission();
    }
    try {
        mSurfaceWidth = width;
        mSurfaceHeight = height;
          getCameraId(cameraId);
        CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId + "");
        StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        // 获取设备方向
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int totalRotation = sensorToDeviceRotation(characteristics, rotation);
        boolean swapRotation = totalRotation == 90 || totalRotation == 270;
        int rotatedWidth = mSurfaceWidth;
        int rotatedHeight = mSurfaceHeight;
        if (swapRotation) {
            rotatedWidth = mSurfaceHeight;
            rotatedHeight = mSurfaceWidth;
        }
        // 获取最佳的预览尺寸
        mPreviewSize = getPreferredPreviewSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);
        if (swapRotation) {
            texture.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
        } else {
            texture.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
        }
        if (mImageReader == null) {
            // 创建一个ImageReader对象,用于获取摄像头的图像数据,maxImages是ImageReader一次可以访问的最大图片数量
            mImageReader = ImageReader.newInstance(mPreviewSize.getWidth(), mPreviewSize.getHeight(),
                    ImageFormat.JPEG, 2);
            mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
        }
        //检查是否支持闪光灯
        Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
        mFlashSupported = available == null ? false : available;
        mCameraManager.openCamera(mCameraId + "", mStateCallback, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

1、要打开摄像头,需要先检测app的相机权限;

2、记录TextTure的宽高值;

3、通过cameramanager对象获取指定摄像头的特性信息CameraCharacteristics(下文详解);

4、通过characteristics对象获取相机支持的可用流配置;

5、获取android手机当前摆放的方向;

6、根据设备方向和摄像头方向,经过处理后得出最终的预览页控件的宽高大小(可能会发生旋转)。

7、从CameraCharacteristics中选择一个最匹配TextTure大小的宽高值;

8、然后重新设定TextTure的大小;

9、创建ImageReader图像读取流对象,ImageReader可以让应用直接访问到相机的image 数据,并渲染到Surface上,也就是TextTure控件上;创建ImageReader需要指定预览页的宽、高和图像的格式,和最大image数。

10、给ImageReader对象设置监听器OnImageAvailableListener; (ImageReader对象在打开摄像头显示预览这里其实不是必须的,可以在实际拍照的时候创建也可以)

11、检查摄像头是否支持开启闪光灯;

12、cameramanager对象调用openCamera()打开指定摄像头,并注册了状态回调对象StateCallback,因为openCamera()函数内部其实做了很多事情,是一个耗时动作,所以这里使用了回调函数异步执行。

13、执行打开摄像头动作后,当检测到摄像头已成功打开,则回调到onOpened(),可以获取到摄像头对象CameraDevice,这个类很重要。接下来就可以在该函数中创建预览了;

14、配置相机预览页大小,创建一个显示预览图像的缓冲区Surface。

15、通过CameraDevice构建一个预览请求构建器对象CaptureRequest.Builder,通过这个构建器设置预览请求对象的相关信息,比如指定预览数据显示位置,即Surface;

16、通过CameraDevice建立一个捕获会话CameraCaptureSession,有了这个会话对象后,后面的所有动作都是基于这个会话对象来操作了;创建会话时,也是注册了一个会话状态回调对象异步地执行接下来的动作;

17、当会话成功建立后,会回调onConfigured()函数;可以在该函数中继续设置预览请求对象的属性,比如设置自动对焦,设置闪光灯模式;

18、最后,预览请求构建器对象调用build()构建了一个捕获请求对象,并通过captureSession会话设置一个无休止的预览请求(即预览),即mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler);

通过这种无休止地发生预览请求实现了相机的预览。

19、到这里TextTure对象中的Surface上就成功展示了相机预览画面数据了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值