android camera2

sancaiodm Android应用 2023-07-13 1342 0

<1>从官网介绍可以看到,从 Android 5.0.1 L开始,Camera API1就已经被废弃,不建议使用

Camera:Android 5.0以下

Camera2:Android 5.0以上

<2>CameraX 

   CameraX 是 Jetpack 的新增库。基于Camera2开发,向上提供更简洁的API接口,向下处理了各种厂商机型的兼容性问题,有助于在众多设备上打造一致的开发者体验

CameraX作为目前主流的且官方不断维护和推荐使用的相机实现框架,掌握其实现基本原理和最佳实践有助于帮助开发者更便捷的使用手机自带的相机能力。


 Camera2 才支持的高级特性

1.在开启相机之前检查相机信息 

     出于某些原因,你可能需要先检查相机信息再决定是否开启相机,例如检查闪光灯是否可用。

     在 Caemra1 上,你无法在开机相机之前检查详细的相机信息,因为这些信息都是通过一个已经开启的相机实例提供的。

     在 Camera2 上,我们有了和相机实例完全剥离的 CameraCharacteristics 实例专门提供相机信息,所以我们可以在不开启相机的前提下检查几乎所有的相机信息。

2.在不开启预览的情况下拍照     

   在 Camera1 上,开启预览是一个很重要的环节,因为只有在开启预览之后才能进行拍照,因此即使显示预览画面与实际业务需求相违背的时候,

   你也不得不开启预览。而 Camera2 则不强制要求你必须先开启预览才能拍照。

3.一次拍摄多张不同格式和尺寸的图片      

   在 Camera1 上,一次只能拍摄一张图片,更不同谈多张不同格式和尺寸的图片了。而 Camera2 则支持一次拍摄多张图片,甚至是多张格式和尺寸都不同的图片。

   例如你可以同时拍摄一张 1440x1080 的 JPEG 图片和一张全尺寸的 RAW 图片。

4.控制曝光时间      

   在暗环境下拍照的时候,如果能够适当延长曝光时间,就可以让图像画面的亮度得到提高。在 Camera2 上,你可以在规定的曝光时长范围内配置拍照的曝光时间,

  从而实现拍摄长曝光图片,你甚至可以延长每一帧预览画面的曝光时间让整个预览画面在暗环境下也能保证一定的亮度。而在 Camera1 上你只能 YY 一下。

5.连拍

   连拍 30 张图片这样的功能在 Camera2 出现之前恐怕只有系统相机才能做到了(通过 OpenGL 截取预览画面的做法除外),也可能是出于这个原因,

   市面上的第三方相机无一例外都不支持连拍。有了 Camera2,你完全可以让你的相机应用程序支持连拍功能,甚至是连续拍 30 张使用不同曝光时间的图片。

6.灵活的 3A 控制     

  3A(AF、AE、AWB)的控制在 Camera2 上得到了最大化的放权,应用层可以根据业务需求灵活配置 3A 流程并且实时获取 3A 状态,

  而 Camera1 在 3A 的控制和监控方面提供的接口则要少了很多。例如你可以在拍照前进行 AE 操作,并且监听本这次拍照是否点亮闪光灯。)

何为HAL3?为了配合Camera2 的使用,Android Hal层Camera框架也做了相对应的改动,也就是HAL3。Camera1接口对应的是调用的HAL1框架。


<1>

 CameraCharacteristics 是描述相机设备的属性类,其中的属性都是 固定的,继承自 CameraMetadata 类

 包括:曝光补偿(Exposure compensation)、自动曝光/自动对焦/自动白平衡模式(AE / AF / AWB mode)、自动曝光/自动白平衡锁(AE / AWB lock)、

自动对焦触发器(AF trigger)、拍摄前自动曝光触发器(Precapture AE trigger)、测量区域(Metering regions)、

闪光灯触发器(Flash trigger)、曝光时间(Exposure time)、感光度(ISO Sensitivity)、帧间隔(Frame duration)、镜头对焦距离(Lens focus distance)、

色彩校正矩阵(Color correction matrix)、JPEG 元数据(JPEG metadata)、色调映射曲线(Tonemap curve)、裁剪区域(Crop region)、

目标 FPS 范围(Target FPS range)、拍摄意图(Capture intent)、硬件视频防抖(Video stabilization)等。

 CameraCharacteristics mCameraCharacteristics; // 相机属性

 

显示需要借助surface,一般采用surfaceview或者textureview;


 一、CameraManager 摄像头管理器,用于打开和关闭系统摄像头

getCameraIdList() :

返回当前设备中可用的相机列表

getCameraCharacteristics(String cameraId) :

根据摄像头id返回该摄像头的相关信息

openCamera(String cameraId, final CameraDevice.StateCallback callback,Handler handler):

打开指定cameraId的相机。参数callback为相机打开时的回调,参数handler为callback被调用时所在的线程


二、CameraDevice 描述系统摄像头

createCaptureRequest(int templateType):

CaptureRequest.Builder   mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); //预览请求

CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);//拍照请求

创建一个新的Capture请求。参数templateType代表了请求类型,请求类型一共分为六种,分别为:

TEMPLATE_PREVIEW : 创建预览的请求

TEMPLATE_STILL_CAPTURE: 创建一个适合于静态图像捕获的请求,图像质量优先于帧速率

TEMPLATE_RECORD : 创建视频录制的请求

TEMPLATE_VIDEO_SNAPSHOT : 创建视视频录制时截屏的请求

TEMPLATE_ZERO_SHUTTER_LAG : 创建一个适用于零快门延迟的请求。在不影响预览帧率的情况下最大化图像质量

TEMPLATE_MANUAL : 创建一个基本捕获请求,这种请求中所有的自动控制都是禁用的(自动曝光,自动白平衡、自动焦点)

createCaptureSession(List outputs,CameraCaptureSession.StateCallback callback,Handler handler):

创建CaptureSession会话。第一个参数 outputs 是一个 List 数组,相机会把捕捉到的图片数据传递给该参数中的 Surface 。

第二个参数 StateCallback 是创建会话的状态回调。第三个参数描述了 StateCallback 被调用时所在的线程


三、CameraCharacteristics描述摄像头的各种特性

类似于Camera1中的CamerInfo。通过CameraManager的getCameraCharacteristics(String cameraId)方法来获取


get(Key key) :

通过制定的key获取相应的相机参数。

常用的key值有:


CameraCharacteristics.LENS_FACING :

获取摄像头方向。前置摄像头(LENS_FACING_FRONT)或 后置摄像头(LENS_FACING_BACK)

CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL:

获取当前设备支持的相机特性

CameraCharacteristics.SENSOR_ORIENTATION:

获取摄像头方向

CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP:

获取StreamConfigurationMap,它是管理摄像头支持的所有输出格式和尺寸

CameraCharacteristics.FLASH_INFO_AVAILABLE:

是否支持闪光灯

CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT:

同时检测到人脸的数量

CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES:

相机支持的人脸检测模式

四、CaptureRequest 描述了一次操作请求

拍照、预览等操作都需要先传入CaptureRequest参数,具体的参数控制也是通过CameraRequest的成员变量来设置


addTarget(Surface outputTarget):

给此次请求添加一个Surface对象作为图像的输出目标


set(Key key, T value):

设置指定的参数值。


// 自动对焦

captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)

// 闪光灯

captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH)

// 根据摄像头方向对保存的照片进行旋转,使其为"自然方向"

captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, mCameraSensorOrientation)

// 人脸检测模式

captureRequestBuilder.set(CaptureRequest.STATISTICS_FACE_DETECT_MODE, CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE)

五、CameraCaptureSession

当需要拍照、预览等功能时,需要先创建该类的实例,然后通过该实例里的方法进行控制(例如:拍照 capture())


setRepeatingRequest(CaptureRequest request,CaptureCallback listener, Handler handler)://setRepeatingRequest表示不断发送请求(用于相机预览)

根据传入的 CaptureRequest 对象开始一个无限循环的捕捉图像的请求。

第二个参数 listener 为捕捉图像的回调,在回调中可以拿到捕捉到的图像信息


capture( CaptureRequest request,CaptureCallback listener, Handler handler):// capture表示只发一次请求(设置拍照捕捉请求参数或拍照)

示例:mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

拍照。第二个参数为拍照的结果回调

以下代来自google Camera2Basic 示例整理:

【1】capture()方法

            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);

            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,mBackgroundHandler);

                  final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

            mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);

            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

【2】setRepeatingRequest()方法

    private CaptureRequest mPreviewRequest;

                                mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

                                mPreviewRequest = mPreviewRequestBuilder.build();

                                mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);

            mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,mBackgroundHandler);


六、ImageReader 用于接收拍照结果和访问拍摄照片的图像数据。

得到一个ImageReader对象的方法为newInstance(int width, int height, int format, int maxImages)。前两个参数是保存图片的宽高,

第三个参数为保存图片的格式,第四个参数代表用户可以同时访问到的最大图片数量


注意:

这个参数应该根据具体需业务需求尽可能的小,因为它的数值越大意味着需要消耗的内存就越高

acquireNextImage():

得到ImageReader图像队列中的下一张图片,返回值是一个Image对象


九、Image 一个完整的图片缓存

getPlanes():获取该图像的像素平面数组。这个数组的大小跟图片的格式有关,如 JPEG格式数组大小为1


十、 Plane 图像数据的单色平面

getBuffer():获取包含帧数据的ByteBuffer。通过这个ByteBuffer我们就可以把图片保存下来

以上参考:

https://www.jianshu.com/p/0ea5e201260f



1、CameraCharacteristics

Camera2与Camera一样也有cameraId的概念,我们通过mCameraManager.getCameraIdList()来获取cameraId列表,

然后通过mCameraManager.getCameraCharacteristics(id)

获取每个id对应摄像头的参数。


关于CameraCharacteristics里面的参数,主要用到的有以下几个:

LENS_FACING:前置摄像头(LENS_FACING_FRONT)或 后置摄像头(LENS_FACING_BACK)。

SENSOR_ORIENTATION:摄像头拍照方向。

FLASH_INFO_AVAILABLE:是否支持闪光灯。

CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL:获取当前设备支持的相机特性。

注:事实上,在各个厂商的的Android设备上,Camera2的各种特性并不都是可用的,

需要通过characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)方法来根据返回值来获取支持的级别,具体说来:

INFO_SUPPORTED_HARDWARE_LEVEL_FULL:全方位的硬件支持,允许手动控制全高清的摄像、支持连拍模式以及其他新特性。

INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED:有限支持,这个需要单独查询。

INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY:所有设备都会支持,也就是和过时的Camera API支持的特性是一致的。

利用这个INFO_SUPPORTED_HARDWARE_LEVEL参数,我们可以来判断是使用Camera还是使用Camera2,具体方法如下:

@TargetApi(Build.VERSION_CODES.LOLLIPOP)

public static boolean hasCamera2(Context mContext) {

    if (mContext == null) return false;

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return false;

    try {

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

        String[] idList = manager.getCameraIdList();

        boolean notFull = true;

        if (idList.length == 0) {

            notFull = false;

        } else {

            for (final String str : idList) {

                if (str == null || str.trim().isEmpty()) {

                    notFull = false;

                    break;

                }

                final CameraCharacteristics characteristics = manager.getCameraCharacteristics(str);

                final int supportLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);

                if (supportLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {

                    notFull = false;

                    break;

                }

            }

        }

        return notFull;

    } catch (Throwable ignore) {

        return false;

    }

}

更多CameraCharacteristics参数,可以参见CameraCharacteristics官方文档。


2、打开相机

打开相机之前,我们首先要获取CameraManager,然后获取相机列表,进而获取各个摄像头(主要是前置摄像头和后置摄像头)的参数。

 mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);

try {

    final String[] ids = mCameraManager.getCameraIdList();

    numberOfCameras = ids.length;

    for (String id : ids) {

        final CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(id);

        final int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);

        if (orientation == CameraCharacteristics.LENS_FACING_FRONT) {

            faceFrontCameraId = id;

            faceFrontCameraOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

            frontCameraCharacteristics = characteristics;

        } else {

            faceBackCameraId = id;

            faceBackCameraOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);

            backCameraCharacteristics = characteristics;

        }

    }

} catch (Exception e) {

    Log.e(TAG, "Error during camera initialize");

}

打开相机主要调用的是mCameraManager.openCamera(currentCameraId, stateCallback, backgroundHandler)方法,如你所见,它有三个参数:

String cameraId:摄像头的唯一ID。

CameraDevice.StateCallback callback:摄像头打开的相关回调。

Handler handler:StateCallback需要调用的Handler,我们一般可以用当前线程的Handler。

mCameraManager.openCamera(currentCameraId, stateCallback, backgroundHandler);

上面我们提到了CameraDevice.StateCallback,它是摄像头打开的一个回调,定义了打开,关闭以及出错等各种回调方法,我们可以在这些回调方法里做对应的操作。

private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {

    @Override

    public void onOpened(@NonNull CameraDevice cameraDevice) {

        //获取CameraDevice

        mcameraDevice = cameraDevice;

    }

    @Override

    public void onDisconnected(@NonNull CameraDevice cameraDevice) {

        //关闭CameraDevice

        cameraDevice.close();

    }

    @Override

    public void onError(@NonNull CameraDevice cameraDevice, int error) {

        //关闭CameraDevice

        cameraDevice.close();

    }

};


3、关闭相机

通过上面的描述,关闭就很简单了。

//关闭CameraDevice

cameraDevice.close();


4、开启预览

Camera2都是通过创建请求会话的方式进行调用的,具体说来:

调用mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)方法创建CaptureRequest,

调用mCameraDevice.createCaptureSession()方法创建CaptureSession。

CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType)


createCaptureRequest()方法里参数templateType代表了请求类型,请求类型一共分为六种,分别为:

private CaptureRequest.Builder mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

TEMPLATE_PREVIEW:创建预览的请求

TEMPLATE_STILL_CAPTURE:创建一个适合于静态图像捕获的请求,图像质量优先于帧速率。

TEMPLATE_RECORD:创建视频录制的请求

TEMPLATE_VIDEO_SNAPSHOT:创建视视频录制时截屏的请求

TEMPLATE_ZERO_SHUTTER_LAG:创建一个适用于零快门延迟的请求。在不影响预览帧率的情况下最大化图像质量。

TEMPLATE_MANUAL:创建一个基本捕获请求,这种请求中所有的自动控制都是禁用的(自动曝光,自动白平衡、自动焦点)。


createCaptureSession(@NonNull List<Surface> outputs, @NonNull CameraCaptureSession.StateCallback callback, @Nullable Handler handler)

createCaptureSession()方法一共包含三个参数:

List outputs:我们需要输出到的Surface列表。

CameraCaptureSession.StateCallback callback:会话状态相关回调。

Handler handler:callback可以有多个(来自不同线程),这个handler用来区别那个callback应该被回调,一般写当前线程的Handler即可。

关于CameraCaptureSession.StateCallback里的回调方法:

onConfigured(@NonNull CameraCaptureSession session); 摄像头完成配置,可以处理Capture请求了。

onConfigureFailed(@NonNull CameraCaptureSession session); 摄像头配置失败

onReady(@NonNull CameraCaptureSession session); 摄像头处于就绪状态,当前没有请求需要处理。

onActive(@NonNull CameraCaptureSession session); 摄像头正在处理请求。

onClosed(@NonNull CameraCaptureSession session); 会话被关闭

onSurfacePrepared(@NonNull CameraCaptureSession session, @NonNull Surface surface); Surface准备就绪

理解了这些东西,创建预览请求就十分简单了。


previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

previewRequestBuilder.addTarget(workingSurface);


//注意这里除了预览的Surface,我们还添加了imageReader.getSurface()它就是负责拍照完成后用来获取数据的

mCameraDevice.createCaptureSession(Arrays.asList(workingSurface, imageReader.getSurface()),

        new CameraCaptureSession.StateCallback() {

            @Override

            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {

                cameraCaptureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler);

            }


            @Override

            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                Log.d(TAG, "Fail while starting preview: ");

            }

        }, null);


可以发现,在onConfigured()里调用了cameraCaptureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler),这样我们就可以

持续的进行预览了。


注:上面我们说了添加了imageReader.getSurface()它就是负责拍照完成后用来获取数据,具体操作就是为ImageReader设置一个OnImageAvailableListener,然后在它的onImageAvailable()

方法里获取。

mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() {

        @Override

        public void onImageAvailable(ImageReader reader) {

            //当图片可得到的时候获取图片并保存

            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));

        }

 };


5、关闭预览

关闭预览就是关闭当前预览的会话,结合上面开启预览的内容,具体实现如下:

if (captureSession != null) {

    captureSession.close();

    try {

        captureSession.abortCaptures();

    } catch (Exception ignore) {

    } finally {

        captureSession = null;

    }

}

拍照

拍照具体来说分为三步:


1 对焦

try {

    //相机对焦

    previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);

    //修改状态

    previewState = STATE_WAITING_LOCK;

    //发送对焦请求

    captureSession.capture(previewRequestBuilder.build(), captureCallback, backgroundHandler);

} catch (Exception ignore) {

}


我们定义了一个CameraCaptureSession.CaptureCallback来处理对焦请求返回的结果。

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

    @Override

    public void onCaptureProgressed(@NonNull CameraCaptureSession session,

                                    @NonNull CaptureRequest request,

                                    @NonNull CaptureResult partialResult) {

    }


    @Override

    public void onCaptureCompleted(@NonNull CameraCaptureSession session,

                                   @NonNull CaptureRequest request,

                                   @NonNull TotalCaptureResult result) {

            //对焦完成

            final Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);

            if (afState == null) {

                //对焦失败,直接拍照

                captureStillPicture();

            } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState

                    || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState

                    || CaptureResult.CONTROL_AF_STATE_INACTIVE == afState

                    || CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN == afState) {

                Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);

                if (aeState == null ||

                        aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {

                    previewState = STATE_PICTURE_TAKEN;

                    //对焦完成,进行拍照

                    captureStillPicture();

                } else {

                    runPreCaptureSequence();

                }

            }

    }

};


2 拍照

我们定义了一个captureStillPicture()来进行拍照。

private void captureStillPicture() {

    try {

        if (null == mCameraDevice) {

            return;

        }

        //构建用来拍照的CaptureRequest

        final CaptureRequest.Builder captureBuilder =  mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

        captureBuilder.addTarget(imageReader.getSurface());

        //使用相同的AR和AF模式作为预览

        captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);

        //设置方向

        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getPhotoOrientation(mCameraConfigProvider.getSensorPosition()));

        //创建会话

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

            @Override

            public void onCaptureCompleted(@NonNull CameraCaptureSession session,

                                           @NonNull CaptureRequest request,

                                           @NonNull TotalCaptureResult result) {

                Log.d(TAG, "onCaptureCompleted: ");

            }

        };

        //停止连续取景

        captureSession.stopRepeating();

        //捕获照片

        captureSession.capture(captureBuilder.build(), CaptureCallback, null);


    } catch (CameraAccessException e) {

        Log.e(TAG, "Error during capturing picture");

    }

}


3 取消对焦

拍完照片后,我们还要解锁相机焦点,让相机恢复到预览状态。

try {

    //重置自动对焦

    previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);

    captureSession.capture(previewRequestBuilder.build(), captureCallback, backgroundHandler);

    //相机恢复正常的预览状态

    previewState = STATE_PREVIEW;

    //打开连续取景模式

    captureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler);

} catch (Exception e) {

    Log.e(TAG, "Error during focus unlocking");

}


7、开始视频录制

//先关闭预览,因为需要添加一个预览输出的Surface,也就是mediaRecorder.getSurface()

closePreviewSession();


//初始化MediaRecorder,设置相关参数

if (preparemediaRecorder()) {

    final SurfaceTexture texture = Camera2Manager.this.texture;

    texture.setDefaultBufferSize(videoSize.getWidth(), videoSize.getHeight());

    try {

        //构建视频录制aptureRequest

        previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);

        final List<Surface> surfaces = new ArrayList<>();

        //设置预览Surface

        final Surface previewSurface = workingSurface;

        surfaces.add(previewSurface);

        previewRequestBuilder.addTarget(previewSurface);

        //设置预览输出Surface

        workingSurface = mediaRecorder.getSurface();

        surfaces.add(workingSurface);

        previewRequestBuilder.addTarget(workingSurface);

        mCameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {

            @Override

            public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {

                captureSession = cameraCaptureSession;


                previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

                try {

                    //持续发送Capture请求,实现实时预览。

                    captureSession.setRepeatingRequest(previewRequestBuilder.build(), null, backgroundHandler);

                } catch (Exception e) {

                }

                try {

                    //开始录像

                    mediaRecorder.start();

                } catch (Exception ignore) {

                    Log.e(TAG, "mediaRecorder.start(): ", ignore);

                }

                isVideoRecording = true;


                uiHandler.post(new Runnable() {

                    @Override

                    public void run() {

                        cameraVideoListener.onVideoRecordStarted(videoSize);

                    }

                });

            }

            @Override

            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

                Log.d(TAG, "onConfigureFailed");

            }

        }, backgroundHandler);

    } catch (Exception e) {

        Log.e(TAG, "startVideoRecord: ", e);

    }

}

关于MediaRecorder上面讲Camera的时候我们就已经说过,这里不再赘述。

以上便是视频录制的全部内容,就是简单的API使用,还是比较简单的。


8、结束视频录制

结束视频录制主要也是关闭会话以及释放一些资源,具体说来:


关闭预览会话

停止mediaRecorder

释放mediaRecorder

//关闭预览会话

if (captureSession != null) {

    captureSession.close();

    try {

        captureSession.abortCaptures();

    } catch (Exception ignore) {

    } finally {

        captureSession = null;

    }

}


//停止mediaRecorder

if (mediaRecorder != null) {

    try {

        mediaRecorder.stop();

    } catch (Exception ignore) {

    }

}


//释放mediaRecorder

try {

    if (mediaRecorder != null) {

        mediaRecorder.reset();

        mediaRecorder.release();

    }

} catch (Exception ignore) {


} finally {

    mediaRecorder = null;

}














camera1技术开发相机及API的详细说明 示例

评论