Android camera2 之我的理解

参考:http://www.jianshu.com/p/060016ba01ff
参考:http://wiki.jikexueyuan.com/project/android-actual-combat-skills/android-hardware-camera2-operating-guide.html
参考:http://www.itdadao.com/articles/c15a228519p0.html

总体分析

1、camera2 流程分析:
这里写图片描述
2、android.hardware.camera2类图
这里写图片描述
CameraManager:管理所有的摄像头(CameraDevice)设备的管理者,打开摄像头等功能。

CameraDevice:一个手机设备一般有两个摄像头(CameraDevice),前置和后置。该类通过CameraCharacteristics对象提供摄像头的硬件信息,配置信息和输出参数等。

CameraCaptureSession:通过CameraDevice 中createCaptureSession(List, CameraCaptureSession.StateCallback, Handler)创建一个CaptureSession会话,所有的CaptureRequest和返回的data都在这个会话中进行。其中,该类中的capture (CaptureRequest request, CameraCaptureSession.CaptureCallback listener, Handler handler)的功能是捕获一次(one-shot),一般用于照相setRepeatingRequest (CaptureRequest request, CameraCaptureSession.CaptureCallbacklistener, Handler handler)是不停的发出capture的请求,也就是一直在捕获画面,一般用于捕获画面输出至预览界面或者录制视频。Capture()比setRepeatingRequest ()优先级高,当在setRepeatingRequest 时进行Capture,会先处理Capture,然后继续setRepeatingRequest 。(PS:可以根据平时使用相机时,首先我们看到的预览界面是setRepeatingRequest 显示出来的,当点击拍照时执行Capture,然后又出现预览界面继续实行setRepeatingRequest )。

CameraRequest:request中定义了照相效果的一些参数,并且必须使用addTarget()函数为这个request添加一个target surface,在最后CameraDevice返回的数据送到这个target surface中。在android camera2的API文档中,这个target surface可以是Surface View,Surface Texture,将返回的数据传递到预览界面中;还可以是MediaRecorder或mageReader,将返回的数据传给这两个类,进行进一步处理,形成视频文件或者图片。

TotalCaptureResult:继承CaptureResult类,CaptureResult继承CameraMetadata类。包含camera device的状态信息。
3、照相流程分析:
这里写图片描述

拍照

1、在Camera2的API中,将一个Camera device比作管道,输入一个个请求,返回包括元数据和一系列的图像缓冲,而且请求是按顺序执行的。获得camera device 对象:

CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);

2、选择合适的相机。
相机的CameraCharacteristics,可以通过:

for (String cameraId : cameraManager.getCameraIdList()) {
    CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
}

得到相机的参数。
然后根据CameraCharacteristics选择相机:如是否需要闪光灯支持:

Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
mFlashSupported = available == null ? false : available;

是否为前置摄像头:

Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);

以及获取图片输出的尺寸和预览画面输出的尺寸:

StreamConfigurationMap configurationMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);

if (configurationMap == null) continue;

//获取图片输出的尺寸
configurationMap.getOutputSizes(ImageFormat.JPEG);
//获取预览画面输出的尺寸,因为我使用TextureView作为预览
configurationMap.getOutputSizes(SurfaceTexture.class

3、打开相机

获取了CameraId后,就可以根据CameraId打开相应的Camera,获取CameraDevice对象。

CameraManager manager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
try {
    manager.openCamera(mCameraId, mStateCallback, mMainHandler);
} catch (CameraAccessException e) {
    e.printStackTrace();
}

查看API,openCamera需要三个参数

image_1apnlgr2anpu19mpguodps1jjb9.png-22.7kB

第一个是我们之前获取的CameraId,第二个参数是当CameraDevice被打开时的回调StateCallback,在这个回调里我们可以获取到CameraDevice对象,第三个参数是一个Handler,决定了回调函数触发的线程,若为null,则选择当前线程。

在StateCallback中,我们要实现三个方法,分别为CameraDevice被打开时触发的方法,失去连接时触发的方法,发生异常时触发的方法。在第一个方法中我们可以成功获取到CameraDevice对象,从而进行接下来的相关操作。

private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            //打开成功,可以获取CameraDevice对象
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
           //断开连接
        }

        @Override
        public void onError(@NonNull CameraDevice camera, final int error) {
            //发生异常
        }
    };

4、发送预览请求

在发送预览请求之前,我们必须先通过CameraDevice对象创建一个CameraCaptureSession的会话对象,通过CameraCaptureSession对象发送预览请求
创建CameraCaptureSession对象同样需要三个参数,第一个是相机预览数据输出的Surface的集合,第二个是回调,在这个回调中我们可以获取CameraCaptureSession对象,第三个参数是Handler,回调触发的线程。

mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession session) {
                            mCaptureSession = session;
                            //发送预览请求
                            sendRepeatPreviewRequest();

                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                        }
                    }, mCameraHandler);

sendRepeatPreviewRequest函数

private boolean sendRepeatPreviewRequest() {
        try {
            CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            builder.addTarget(mPreviewSurface);
            builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
            builder.setTag(RequestTag.Preview);
            addBaselineCaptureKeysToRequest(builder);

            mCaptureSession.setRepeatingRequest(builder.build(),
                    mFocusStateListener,
                    mCameraHandler);
            return true;
        } catch (CameraAccessException e) {
            e.printStackTrace();
            return false;
        }
    }

4、发送拍摄请求

CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            builder.setTag(RequestTag.Capture);
            addBaselineCaptureKeysToRequest(builder);
            builder.set(CaptureRequest.JPEG_ORIENTATION,
                    CameraUtil.getJPEGOrientation(parameters.getOrientation(), mCameraCharacteristics));
            builder.addTarget(mPreviewSurface);
            builder.addTarget(mImageReader.getSurface());
            mCaptureSession.capture(builder.build(),
                    mFocusStateListener,
                    mCameraHandler);

摄像

1、


版权声明:本文为lushuo9156原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。