一、介绍

最近在相机开发中发现 createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) 已经被标记为过时(@Deprecated)的函数了,取而代之的是 createCaptureSession(SessionConfiguration) 函数。

缘由

随着 Camera 功能越来越复杂,创建 Session 的方法也随之越来越多,比如:

createCaptureSession(List<Surface>, CameraCaptureSession.StateCallback, Handler)createCaptureSessionByOutputConfigurations(List<OutputConfiguration>, CameraCaptureSession.StateCallback, Handler)createReprocessableCaptureSession(InputConfiguration, List<Surface>, CameraCaptureSession.StateCallback, Handler)createReprocessableCaptureSessionByConfigurations(InputConfiguration, List<OutputConfiguration>, CameraCaptureSession.StateCallback, Handler)createConstrainedHighSpeedCaptureSession(List<Surface>, CameraCaptureSession.StateCallback, Handler)createCustomCaptureSession(InputConfiguration, List<OutputConfiguration>, int, CameraCaptureSession.StateCallback, Handler)

于是便推出了 createCaptureSession(SessionConfiguration) 来统一。SessionConfiguration 是 Android API 28 新增的类,用于聚合捕获会话初始化的所有支持的参数。

二、常用方法

1. 构造函数

只有一个构造函数如下:

/** * @param sessionType 会话类型,目前有SESSION_REGULAR和SESSION_HIGH_SPEED两个值,后者为高速帧率范围,通常用于拍摄高速动作或慢动作视频 * @param outputs 该会话输出的集合,不能为空 * @param executor 用于调用回调的执行器,不建议使用主线程 * @param cb 创建状态的回调函数,不能为空 */public SessionConfiguration (int sessionType, List<OutputConfiguration> outputs, Executor executor, CameraCaptureSession.StateCallback cb)

2. 设置参数

用于设置Session创建时的使用的一些初始值。
因为这些值可以通过 CaptureRequest.Builder 在创建前就设置好然后传递给 Session 使用,可以用来根据不同的值选择相机Hal层使用的pipeline。

/** * @param params CaptureRequest.Builder的输出目标和不在CameraCharacteristics#getAvailableSessionKeys 中的参数值将会忽略,建议使用初始捕获请求相同的模板类型构建会话参数,以便会话和初始请求的参数尽可能匹配。 */public void setSessionParameters (CaptureRequest params)

3. 判断 SessionConfiguration 是否支持

这个是 CemeraDevice 类的函数,一般也会使用到。

/** * @param sessionConfig 目标SessionConfiguration */public boolean isSessionConfigurationSupported (SessionConfiguration sessionConfig)

其余一些方法很少用,感兴趣的可以参考官网文档。

链接:https://developer.android.com/reference/android/hardware/camera2/params/SessionConfiguration

三、简单示例

一个简单的使用流程,熟悉一下创建流程。

// 创建一个 CaptureRequest.Builder 用于配置捕获请求CaptureRequest.Builder previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);previewRequestBuilder.addTarget(surface); // surface 是用于显示预览的 Surface 对象ArrayList<OutputConfiguration> outputConfigurations = new ArrayList<>();for (Surface surface : allSessionOutputs) { // allSessionOutputs是所有的 Surface 集合,包含预览+拍照等if (surface != null) {OutputConfiguration configuration = new OutputConfiguration(surface);outputConfigurations.add(configuration);}}// 创建和设置 SessionConfigurationCameraCaptureSession.StateCallback sessionCreateCallback = new CameraCaptureSession.StateCallback() {@Overridepublic void onConfigured(@NonNull CameraCaptureSession session) {// 会话创建成功,您可以开始处理预览或拍照操作}@Overridepublic void onConfigureFailed(@NonNull CameraCaptureSession session) {// 会话创建失败,处理错误情况}};SessionConfiguration sessionConfiguration = new SessionConfiguration(SessionConfiguration.SESSION_REGULAR, // SESSION_REGULAR或SESSION_HIGH_SPEEDoutputConfigurations, // 上面创建的ArrayListContext.getMainExecutor(),// 回调的执行器,注意这里是不建议使用主线程的sessionCreateCallback); // 回调函数sessionConfiguration.setSessionParameters(previewRequestBuilder.build());// 判断是否支持try {boolean supported = cameraDevice.isSessionConfigurationSupported(sessionConfig);if (!supported) {// 处理不支持的情况}} catch (CameraAccessException | IllegalArgumentException | NullPointerException e) {e.printStackTrace();// 处理异常的情况}// 创建捕捉会话cameraDevice.createCaptureSession(sessionConfiguration);

四、自定义的回调执行器

因为不建议在主线程中执行回调,所以通常我们会创建一个相机的执行器。

1. 创建相机后台线程

这里的 mCameraHandler 同样可以用于 openCamera() 等函数使用。

private Handler mCameraHandler;private HandlerThread mCameraThread;// 在打开相机的时候启动线程private void startBackgroundThread() {if (mCameraThread == null || mCameraHandler == null) {mCameraThread = new HandlerThread("CameraBackground");mCameraThread.start();mCameraHandler = new Handler(mCameraThread.getLooper());}}// 在关闭相机的时候停止线程private void stopBackgroundThread() {if (mCameraThread != null) {mCameraThread.quitSafely();}}
2. HandlerExecutor类

单独声明一个类或者内部类都可以。

public class HandlerExecutor implements Executor {private final Handler ihandler;public HandlerExecutor(Handler handler) {ihandler = handler;}@Overridepublic void execute(Runnable runCmd) {ihandler.post(runCmd);}}
3. 使用

只需要替换掉之前例子中的 Context.getMainExecutor() 即可。

SessionConfiguration sessionConfiguration = new SessionConfiguration(SessionConfiguration.SESSION_REGULAR, // SESSION_REGULAR或SESSION_HIGH_SPEEDoutputConfigurations, // 上面创建的ArrayListnew HandlerExecutor(mCameraHandler),// 回调的执行器,注意这里是不建议使用主线程的sessionCreateCallback); // 回调函数