• 一文看懂 Camera2 framework:以具体 preview 流程为例 独家原创


    目录

    一、总体流程环节

    二、Camera Framework 核心类

    三、Camera Metadata 获取、设置及查询

    四、预览整体流程

    五、深入:关于openCamera


    其实很简单,纸老虎,一捅就破。

    一、总体流程环节

    相机预览时,app 应用会调用 framework 的 java 接口,framework 又会调用 native camera service,然后 camera service 再调用 camera hal 的接口,最后对 driver 发指令。层层调用,service 只是中间透传环节,关键在于开始的 framework 流程与最后的 hal 接口实现,那么我们就从头看起,更好理解。

    二、Camera Framework 核心类

    一般来说,camera service (c++ 代码) 也在 framework 目录下,但 service 是起到中间传递的作用,所以这里主要讲的是 java 类。camera service 后续根据需要发表博客。

    Camera Framework 核心类如下:

     文件目录及每个类的作用已注明。这里参数的获取与传递依靠 MetaData,关于 MetaData 的定义、内存分布以及在 native 侧的使用方式见本人写的另一篇博客。

    Camera MetaData介绍_独家原创_alibli的博客-CSDN博客

    在 framework 层分析的好处就是现在可以更加具体到实际的 Metadata。

    三、Camera Metadata 获取、设置及查询

    CameraCharacteristics 类里定义了大量元数据类似,我们会在 Camera open 之前获取这些元数据,简单点说,获取参数的可设置值或范围。那么常用的 key 有哪些呢?如下:

    当然这里只举常用的一类,比如 SENSOR_INFO_PIXEL_ARRAY_SIZE,相关的还有 SENSOR_INFO_ACTIVE_ARRAY_SIZE、SCALER_CROP_REGION 等等。

    核心流程:open camera 之前我们获取到了可以各属性可设置的范围,在有效范围内,创建 session 发 request 就可以传入我们实际要设置的值,设置结果则是查询 CaptureResult 的 key。那么你可能有疑惑,整个流程是啥样的呢?下面来打消你的疑惑。

    四、预览整体流程

    关键接口入参与返回值罗列:

    1. // 以下接口只列举入参最多的一个
    2. public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
    3. throws CameraAccessException
    4. public void openCamera(@NonNull String cameraId,
    5. int oomScoreOffset,
    6. @NonNull @CallbackExecutor Executor executor,
    7. @NonNull final CameraDevice.StateCallback callback)
    8. throws CameraAccessException
    9. // 旧版已废弃
    10. @Deprecated
    11. public abstract void createCaptureSession(@NonNull List outputs,
    12. @NonNull CameraCaptureSession.StateCallback callback,
    13. @Nullable Handler handler)
    14. throws CameraAccessException;
    15. // 新版一个接口一统江湖
    16. public void createCaptureSession(SessionConfiguration config)
    17. throws CameraAccessException
    18. // SessionConfiguration构造函数
    19. public SessionConfiguration(@SessionMode int sessionType,
    20. @NonNull List outputs,
    21. @NonNull @CallbackExecutor Executor executor,
    22. @NonNull CameraCaptureSession.StateCallback cb)
    23. public CaptureRequest.Builder createCaptureRequest(@RequestTemplate int templateType,
    24. Set physicalCameraIdSet)
    25. throws CameraAccessException
    26. public abstract int setRepeatingRequest(@NonNull CaptureRequest request,
    27. @Nullable CaptureCallback listener,
    28. @Nullable Handler handler)
    29. throws CameraAccessException

    应用层调用 getSystemService 即可获取 CameraManager,CameraManger 是 framework 中总体管理者,通过他的 openCamera(...) 接口创建 CameraDevice 示例,因为 openCamera(...) 入参传入了 cameraId 以及 StateCallback 实例。注意,在 openCamera(...) 之前会调用 manager.getCameraCharacteristics(cameraId) 方法,这样就获取了 Camera 设备支持的参数设置范围。

    当  StateCallback 的 onOpened(...) 回调被调用时,说明相机开启完成,这时候创建 CameraCaptureSession 实例。然后创建 CaptureRequest 实例,session 调用 setRepeatingRequest(...) 将 CaptureRequest 实例下发到 hal 层。

    最后 CaptureCallback 会返回获取到的数据与状态。

    五、深入:关于openCamera

    来看 camera framework(java) 与 camera service (c++) 之间的联系。CameraManager 的 openCamera 接口最终调用自己的 openCameraDeviceUserAsync(...) 方法:

    1. /**
    2. * Helper for opening a connection to a camera with the given ID.
    3. *
    4. * @param cameraId The unique identifier of the camera device to open
    5. * @param callback The callback for the camera. Must not be null.
    6. * @param executor The executor to invoke the callback with. Must not be null.
    7. * @param uid The UID of the application actually opening the camera.
    8. * Must be USE_CALLING_UID unless the caller is a service
    9. * that is trusted to open the device on behalf of an
    10. * application and to forward the real UID.
    11. *
    12. * @throws CameraAccessException if the camera is disabled by device policy,
    13. * too many camera devices are already open, or the cameraId does not match
    14. * any currently available camera device.
    15. *
    16. * @throws SecurityException if the application does not have permission to
    17. * access the camera
    18. * @throws IllegalArgumentException if callback or handler is null.
    19. * @return A handle to the newly-created camera device.
    20. *
    21. * @see #getCameraIdList
    22. * @see android.app.admin.DevicePolicyManager#setCameraDisabled
    23. */
    24. private CameraDevice openCameraDeviceUserAsync(String cameraId,
    25. CameraDevice.StateCallback callback, Executor executor, final int uid,
    26. final int oomScoreOffset) throws CameraAccessException {
    27. CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
    28. CameraDevice device = null;
    29. Map physicalIdsToChars =
    30. getPhysicalIdToCharsMap(characteristics);
    31. synchronized (mLock) {
    32. ICameraDeviceUser cameraUser = null;
    33. android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
    34. new android.hardware.camera2.impl.CameraDeviceImpl(
    35. cameraId,
    36. callback,
    37. executor,
    38. characteristics,
    39. physicalIdsToChars,
    40. mContext.getApplicationInfo().targetSdkVersion,
    41. mContext);
    42. ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
    43. try {
    44. ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
    45. if (cameraService == null) {
    46. throw new ServiceSpecificException(
    47. ICameraService.ERROR_DISCONNECTED,
    48. "Camera service is currently unavailable");
    49. }
    50. cameraUser = cameraService.connectDevice(callbacks, cameraId,
    51. mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
    52. oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);
    53. } catch (ServiceSpecificException e) {
    54. if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
    55. throw new AssertionError("Should've gone down the shim path");
    56. } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
    57. e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
    58. e.errorCode == ICameraService.ERROR_DISABLED ||
    59. e.errorCode == ICameraService.ERROR_DISCONNECTED ||
    60. e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
    61. // Received one of the known connection errors
    62. // The remote camera device cannot be connected to, so
    63. // set the local camera to the startup error state
    64. deviceImpl.setRemoteFailure(e);
    65. if (e.errorCode == ICameraService.ERROR_DISABLED ||
    66. e.errorCode == ICameraService.ERROR_DISCONNECTED ||
    67. e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
    68. // Per API docs, these failures call onError and throw
    69. throwAsPublicException(e);
    70. }
    71. } else {
    72. // Unexpected failure - rethrow
    73. throwAsPublicException(e);
    74. }
    75. } catch (RemoteException e) {
    76. // Camera service died - act as if it's a CAMERA_DISCONNECTED case
    77. ServiceSpecificException sse = new ServiceSpecificException(
    78. ICameraService.ERROR_DISCONNECTED,
    79. "Camera service is currently unavailable");
    80. deviceImpl.setRemoteFailure(sse);
    81. throwAsPublicException(sse);
    82. }
    83. // TODO: factor out callback to be non-nested, then move setter to constructor
    84. // For now, calling setRemoteDevice will fire initial
    85. // onOpened/onUnconfigured callbacks.
    86. // This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
    87. // cameraUser dies during setup.
    88. deviceImpl.setRemoteDevice(cameraUser);
    89. device = deviceImpl;
    90. }
    91. return device;
    92. }

    来看核心的部分:

    ICameraService cameraService = CameraManagerGlobal.get().getCameraService();

    这行即获取到 ICameraService 对象,这个类是什么呢?在 camera framework 中以 I 开头的基本都是 aidl 文件,这个文件就在 framework/av/camera/aidl/android/hardware/ICameraService.aidl。aidl 声明了接口,具体实现就对应在 camera service 中,这样就跟 native 层联系起来了。

    接下来调用 connetDevice,里面传入了 callbacks,cameraId 等,返回 cameraUser:

    1. cameraUser = cameraService.connectDevice(callbacks, cameraId,
    2. mContext.getOpPackageName(), mContext.getAttributionTag(), uid,
    3. oomScoreOffset, mContext.getApplicationInfo().targetSdkVersion);

    cameraUser 又是 ICameraDeviceUser 对象的实例,I 打头又是 aidl 类,对应实现是在 camera service 侧的 BnCameraDeviceUser,这个类最终被 CameraDeviceClient 继承。传入的 callback 则是 ICameraDeviceCallbacks 类型,这个对应 service 侧的 BnCameraDeviceCallbacks,被 ServiceCallback 继承。

    1. deviceImpl.setRemoteDevice(cameraUser);
    2. device = deviceImpl;

    deviceImpl 是 CameraDeviceImpl 实例,CameraDeviceImpl 是抽象类 CameraDevice 的具体实现类。setRemoteDevice 传入 cameraUser 会被用于创建 ICameraDeviceUserWrapper 对象,Wrapper 代表是 ICameraDeviceUser 的包装类。这里 mRemoteDevice 即是 framework 与 service 之间沟通的关键桥梁。

    1. // CameraDeviceImpl.java setRemoteDevice(...)方法中
    2. mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);

    欢迎交流~

  • 相关阅读:
    元器件贸易企业,理应“以快制胜”
    springboot实验课程辅助管理系统毕业设计-附源码191113
    【DCMTK】DcmItem::putAndInsertOFStringArray失败
    linux 下 top命令显示的是内存是堆内存吗?
    8月20日计算机视觉理论学习笔记——神经网络与BP算法
    LRU、LFU 内存淘汰算法的设计与实现
    leetcode-495-提莫攻击
    C++ XML文件和解析
    istio: 如何对istio数据平面进行benchmark
    PPI转以太网模块通过XD1.0替代EM277模块在汽车零件组装系统中的应用
  • 原文地址:https://blog.csdn.net/weixin_36389889/article/details/126074786