Android Camera2 自定义相机

Android Camera2 自定义相机

在Android API21中Google发布了Camera2类来取代Camera类,两者的变动也是比较大的,所以需要重新学习一下Camera2的用法,写下这篇博客当做笔记了。

开头是一些网上烂大街的东西,不过作为基础的知识还是要记录一下,官网地址点这里

Android Camera2 流程示意图

Google采用了pipeline(管道)的概念,将Camera Device相机设备和Android Device安卓设备连接起来, Android Device通过管道发送CaptureRequest拍照请求给Camera Device,Camera Device通过管道返回CameraMetadata数据给Android Device,这一切建立在一个叫作CameraCaptureSession的会话中。

Camera2中主要类

Camera2自定义流程图
Android Camera2 自定义相机_第1张图片

来看一下具体的实现

TextureView

使用TextureView作为预览的展示View,之前一般使用的都是SurfaceView来实现的。


首先,TextureView在Andriod4.0之后的API中才能使用。其次SurfaceView可以通过SurfaceHolder.addCallback方法在子线程中更新UI,TextureView则可以通TextureView.setSurfaceTextureListener在子线程中更新UI,两者更新画面的方式也有些不同,由于SurfaceView的双缓冲功能,可以是画面更加流畅的运行,但是由于其holder的存在导致画面更新会存在间隔。并且,由于holder的存在,SurfaceView也不能进行像View一样的setAlpha和setRotation方法,但是对于一些类似于坦克大战等需要不断告诉更新画布的游戏来说,SurfaceView绝对是极好的选择。但是比如视频播放器或相机应用的开发,TextureView则更加适合。(摘抄自http://blog.csdn.net/lrh_12580/article/details/51308139)

private final TextureView.SurfaceTextureListener mSurfaceTextureListener
            = new TextureView.SurfaceTextureListener() {

        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
            openCamera(width, height); //打开Camera
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
            configureTransform(width, height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture texture) {
        }

    };

生命周期绑定

由于camera使用的时候和我们使用IO流很像,所以要保证在Activity销毁的时候Camera资源释放,所以一般讲Camera的生命周期与Activity的生命周期进行绑定,在onResume()时打开Camera,在onPause()时关闭Camera,释放资源。

@Override
    public void onResume() {
        super.onResume();
        startBackgroundThread();
        if (mTextureView.isAvailable()) {
           openCamera(mTextureView.getWidth(),mTextureView.getHeight());
        } else {
         mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        }
       }
  @Override
    public void onPause() {
        closeCamera();
        stopBackgroundThread();
        super.onPause();
    }

主要代码

通过CameraManager打开Camera

CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            String[] camIds = manager.getCameraIdList();
            mCameraId = camIds[0];   //一般0代表后置摄像头,1表示前置
            manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
        }

第一个比较重要的CallBack : CameraDevice.StateCallback,通过这个CallBack提供的方法可以判断Camera是否成功启动,并执行各种情况下的操作。启动成功后就需要创建一个预览画面的Session();

  private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {

        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            // This method is called when the camera is opened.  We start camera preview here.
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int error) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
            Activity activity = getActivity();
            if (null != activity) {
                activity.finish();
            }
        }

    };

创建负责管理处理预览请求和拍照请求CameraCaptureSession

private void createCameraPreviewSession() {
        try {
            // 创建预览需要的CaptureRequest.Builder
            final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            // 将SurfaceView的surface作为CaptureRequest.Builder的目标
            previewRequestBuilder.addTarget(mSurfaceHolder.getSurface());
            // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求
            mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback()
            {
                @Override
                public void onConfigured(CameraCaptureSession cameraCaptureSession) {
                    if (null == mCameraDevice) return;
                    // 当摄像头已经准备好时,开始显示预览
                    mCameraCaptureSession = cameraCaptureSession;
                    try {
                       // 自动对焦
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                      //   打开闪光灯
                        previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                      //   显示预览
                        CaptureRequest previewRequest = previewRequestBuilder.build();
                        mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
                    Toast.makeText(MainActivity.this, "creat faile", Toast.LENGTH_SHORT).show();
                }
            },null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

然后就要在CaptureCallback中处理预览或拍照,其实主要是处理各种拍照时的状态,预览不需要进行处理,在上一步就已经在TextureView中可以展示了

private CameraCaptureSession.CaptureCallback mCaptureCallback
            = new CameraCaptureSession.CaptureCallback() {

        private void process(CaptureResult result) {
              .......
        }
  }

拍照

拍照是将Target改成对应的ImageReader,交给它来处理一张图片

CaptureRequest.Builder captureBuilder =mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(mImageReader.getSurface());
mCaptureSession.capture(captureBuilder.build(), mCaptureCallback, null);
mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
            @Override
            public void onImageAvailable(ImageReader reader) {
                Image image = reader.acquireLatestImage();
                // get image bytes
                ByteBuffer imageBuf = image.getPlanes()[0].getBuffer();
                final byte[] imageBytes = new byte[imageBuf.remaining()];
                imageBuf.get(imageBytes);
                image.close();
                ......  //处理图片

            }
        }, childHandler);

到这里基本的流程就结束了。

具体参考GitHub

你可能感兴趣的:(Android学习笔记)