价值投资 长期主义 编程 美食 旅行 梦想 参禅 悟道

0%

AndroidCamera 3 CameraManager

CameraManager

1、概述

CameraManager 是一个负责查询和建立相机连接的系统服务,关键功能:

  1. 将相机信息封装到 CameraCharacteristics 中,并提获取 CameraCharacteristics 实例的方式。
  2. 根据指定的相机 ID 连接相机设备。
  3. 提供将闪光灯设置成手电筒模式的快捷方式。

2、获取实例

通过 Context 类的 getSystemService() 方法来获取一个系统服务

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

3、内部类

CameraManager.AvailabilityCallback

相机设备的可用状态发生变化时,触发回调。

  • public void onCameraAvailable(@NonNull String cameraId)
  • public void onCameraUnavailable(@NonNull String cameraId)

String cameraId 相机设备的唯一标识。

CameraManager.TorchCallback

闪光灯的可用状态发生变化时触发回调。

  • public void onTorchModeUnavailable(@NonNull String cameraId)
  • public void onTorchModeChanged(@NonNull String cameraId, boolean enabled)
    • String cameraId 相机设备的唯一标识。
    • boolean enabled 闪光灯变化前的状态

CameraManager.CameraManagerGlobal

全局Camera管理实例,单例,保持一个与camera service得连接,同时分发API注册得可用回调。

4、主要接口

获取Camera设备列表

1
2
3
4
@NonNull
public String[] getCameraIdList() throws CameraAccessException {
return CameraManagerGlobal.get().getCameraIdList();
}

注册可用状态变化回调

注册一个回调用来当可用状态变化的时候,进行通知。

  • 注册一个相同的回调,那么新的会替代旧的。
  • 第一次注册回调时,立刻激活一次回调,回报当前可用的camera设备;
  • 不管什么时候调用了camera被打开了都会触发回调;
  • 如果没有必要时,记得注销回调。不然会占用资源。 回调将独立于一般Activity的生命周期,独立调用CameraManger。
  • 支持再给定的Handle或Executor 上触发回调;

支持的接口

1
2
3
4
5
public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback,
@Nullable Handler handler) {
CameraManagerGlobal.get().registerAvailabilityCallback(callback,
CameraDeviceImpl.checkAndWrapHandler(handler));
}
  • @NonNull AvailabilityCallback callback 新的回调

  • @Nullable Handler handler 在之上会调用callback,如果设置为null,则使用当前线程(android.os.Looper looper);

1
2
3
4
5
6
7
public void registerAvailabilityCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull AvailabilityCallback callback) {
if (executor == null) {
throw new IllegalArgumentException("executor was null");
}
CameraManagerGlobal.get().registerAvailabilityCallback(callback, executor);
}
  • @NonNull @CallbackExecutor Executor executor, 在之上调用callback。
  • @NonNull AvailabilityCallback callback 新的回调。

注销可用状态回调

移除之前注册的回调,此callback 不会再接收连接和断开的事件。

1
2
3
public void unregisterAvailabilityCallback(@NonNull AvailabilityCallback callback) {
CameraManagerGlobal.get().unregisterAvailabilityCallback(callback);
}

注册闪光灯回调

注册回调用于关注闪光灯状态

  • 注册一个相同的回调,那么新的会替代旧的。

  • 第一次注册时,会立刻回调具备闪光灯单元的所有Camera设备。

  • 注册此回调到camera service后,记得不需要的时候注销此回调,不然一旦闪光灯状态变化会触发回调,影响相应资源释放。回调将独立于一般Activity的生命周期,独立调用CameraManger。

  • 支持再给定的Handle或Executor 上触发回调。

支持的接口

1
2
3
4
public void registerTorchCallback(@NonNull TorchCallback callback, @Nullable Handler handler) {
CameraManagerGlobal.get().registerTorchCallback(callback,
CameraDeviceImpl.checkAndWrapHandler(handler));
}
  • @NonNull TorchCallback callback 新的回调

  • @Nullable Handler handler 在之上会调用callback,如果设置为null,则使用当前线程(android.os.Looper looper);

1
2
3
4
5
6
7
public void registerTorchCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull TorchCallback callback) {
if (executor == null) {
throw new IllegalArgumentException("executor was null");
}
CameraManagerGlobal.get().registerTorchCallback(callback, executor);
}
  • @NonNull @CallbackExecutor Executor executor, 在之上调用callback。
  • @NonNull TorchCallback callback 新的回调。

注销闪光灯回调

移除之前注册的回调,此callback 不会再接收闪光灯状态变化的事件。

1
2
3
public void unregisterTorchCallback(@NonNull TorchCallback callback) {
CameraManagerGlobal.get().unregisterTorchCallback(callback);
}

获取Camera特性

查询并获取指定Camera的特性和能力,这些特性是不可修改的。

  • 从API 29 开始,此接口也可用于查询物理摄像头的特性,物理摄像头仅可以是逻辑复合摄像头的一部分,不能直接被openCamera接口打开。
1
2
3
@NonNull
public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
throws CameraAccessException
  • @NonNull String cameraId 可以是一个独立的camera 或者仅是一个物理摄像头。

打开Camera

建立一个到给定Camera的连接。

  • 及时打开的是使用 getCameraIdList 获取的cameraId指定的Camera 也可能操作失败,因为Camera有可能已经断开连接或者被其他更高级别的API打开而被占用。
  • 即使低优先级的client已经打开了Camera,高优先级的client也可以成功打开Camera,此时低级别的Client会收到回调事件android.hardware.camera2.CameraDevice.StateCallback#onDisconnected。如果你的client处于 顶层或者前台的Activity 那么你的client可以获得更高的优先级。
  • 一旦成功打开Camera,会触发回调 CameraDevice.StateCallback#onOpened,那么你就可以使用Camera的相关操作,比如发起拍照请求等。
  • 如果在初始化期间Camera断开,那么会有一个CameraDevice.StateCallback#onDisconnected回调其中带有Camera状态,回调CameraDevice.StateCallback#onOpened就会被跳过。
  • 如果打开Camera失败,会触发回调CameraDevice.StateCallback#onError onError,随后在这个Camera上的调用就会抛出异常CameraAccessException。

支持的接口

1
2
3
4
5
@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback,
@Nullable Handler handler)
throws CameraAccessException
  • @NonNull String cameraId: camera 唯一标识
  • CameraDevice.StateCallback callback CameraDevice状态回调
  • @Nullable Handler handler 在其上运行回调。
1
2
3
4
5
@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull @CallbackExecutor Executor executor,
@NonNull final CameraDevice.StateCallback callback)
throws CameraAccessException
  • @NonNull String cameraId: camera 唯一标识
  • @NonNull @CallbackExecutor Executor executor CameraDevice状态回调
  • @Nullable Handler handler 在其上运行回调。
1
2
3
4
5
public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback,
@NonNull Executor executor,
int clientUid)
throws CameraAccessException
  • 此接口为隐藏接口

  • int clientUid UID为clientUid 的应用将打开Camera,一般设置为USE_CALLING_UID,除非是可信任的服务。

设置闪光灯模式

设置指定camera得闪光灯模式,不需要打开camera。

  • 使用getCameraIdList获取可用Camera列表,使用getCameraCharacteristics查看Camera是否包含闪光灯。即使Camera包含闪光灯,也有可能打开闪光灯失败,因为或许在使用中。

  • setTorchMode调用成功,CameraManager.TorchCallback#onTorchModeChanged会触发。即使打开了闪光灯,应用也不是独占闪光灯或者Camera。如果最后一个打开闪光灯得应用退出了,闪光灯将关闭。

1
2
3
4
5
6
7
public void setTorchMode(@NonNull String cameraId, boolean enabled)
throws CameraAccessException {
if (CameraManagerGlobal.sCameraServiceDisabled) {
throw new IllegalArgumentException("No cameras available on device");
}
CameraManagerGlobal.get().setTorchMode(cameraId, enabled);
}

5、核心实现

相关代码位于源码位置:

1
2
3
4
5
frameworks\base\core\java\android\hardware\camera2\CameraManager.java
./frameworks/av/camera/aidl/android/hardware/ICameraServiceListener.aidl
./frameworks/av/camera/aidl/android/hardware/ICameraServiceProxy.aidl
./frameworks/av/camera/aidl/android/hardware/ICameraService.aidl
。。。
  • Application framework:用于给APP提供访问hardware的Camera API2,通过binder来访问camera service。

  • AIDL: 基于Binder实现的一个用于让App framework代码访问natice 代码的接口。其实现存在于下述路径:frameworks/av/camera/aidl/android/hardware。其中:

    • ICameraService 是相机服务的接口。用于请求连接、添加监听等。
    • ICameraDeviceUser 是已打开的特定相机设备的接口。应用框架可通过它访问具体设备。
    • ICameraServiceListener 和 ICameraDeviceCallbacks 分别是从 CameraService 和 CameraDevice 到应用框架的回调。
  • Natice framework:frameworks/av/。提供了ICameraService、ICameraDeviceUser、ICameraDeviceCallbacks、ICameraServiceListener等aidl接口的实现。以及camera server的main函数。

  • Binder IPC interface:提供进程间通信的接口,APP和CameraService的通信、CameraService和HAL的通信。其中,AIDL、HIDL都是基于Binder实现的。

  • Camera Service:frameworks/av/services/camera/。同APP、HAL交互的服务,起到了承上启下的作用。

  • HAL:Google的HAL定义了可以让Camera Service访问的标准接口。对于供应商而言,必须要实现这些接口。

查看CameraManager类,其主要功能由其内部类 CameraManagerGlobal 代理实现。CameraManagerGlobal 是一个单例,CameraManagerGlobal 是真正的实现层,它与 CameraService 创建连接,从而创建相机的连路。

万水千山总是情,打赏一块行不行!