CameraX 是一个 Jetpack 支持包之一,据官网介绍主要目的就是为了编写 camera APP 更加简单高效,该模块提供了一个一致的、高效的编程 API,可以在左右的 Android 设备上面使用,并且向后兼容到 Android 5.0(API 21)。虽然 CameraX 使用的还是 camera2 的接口,但是它通过封装提供了一个更加简单的、基于用例的生命周期追踪的封装接口。并且这层封装还把设备相关的代码隐藏了起来,这部分全部交给 CameraX 来完成,用户就不用再去添加设备兼容性相关的代码到自己的工程代码里面了,这可以减少很多的代码量。

CameraX 可以提供和系统预装相机类似的功能给到三方的 Camera APP,这个是一个非常大的提升了,据介绍两行代码就可以完成基本的功能了,怕不怕。此外还可以通过 CameraX Extensions 来添加一些设备支持的其它功能,比如说:人像模式、HDR、夜景模式、美颜等等。本文就简单介绍下 CameraX 的一些概念性的东西。

文档参考:

  1. https://developer.android.google.cn/training/camerax/architecture
  2. https://developer.android.google.cn/training/camerax
  3. https://source.android.google.cn/devices/camera/camerax-vendor-extensions

CameraX 带来的主要提升

CameraX 使开发变得更加方便,CameraX 是基于用例的,也就是说可以不用过度注意细节,把更多的精力放在业务逻辑上面,而不是业务逻辑底层的东西,CameraX 区分了几个基本的用例模式:

  1. Preview:用于预览,也就是说这里获取到的图片都是拿来预览显示的。
  2. Image analysis:可以让算法模块直接访问到相关的 image buffer 并用于数据处理以及分析,比如可以直接传递给 MLkit 模块进行处理。
  3. Image capture:高质量图片抓取。

从 Android 5.0(API 21)往后的版本,CameraX 保证了其都拥有共同的 camera 行为,所有的设备上面都可以保持一致。在不同的设备上面保持行为一致是比较难得一件事情,和 IOS 设备不一样,Android 设备历史包袱太重了,市场上面硬件设备五花八门,下面的几个点都是会影响到一致性的:图像比例、原点、旋转、预览图像宽高以及高分辨率图片,在 CameraX 的加持下,这些都是可以搞定的,听起来很厉害。

使用 CameraX Extension 可以获得和 Native APP 差不多的相机能力,只需要两句代码即可完成,上面也提到过这部分可以支持的特性,这里就不在赘述了。

CameraX 的基本架构

这部分涉及到甚多的 APP 层级代码,本文不是非常关心这部分,所以就会抽出一点理论性的东西介绍,代码什么的就直接看官方文档就可以了,在开头也列出来了。

首先 CameraX 是用于更方便使用 Camera API2 的 JetPack 扩展,其将整个 Camera API2 整合成了:Preview、Image analysis、Image capture 三个大的类别。开发者可以使用其中一个或者同时使用多个功能组成自己的 APP 用例。要想使用这个 Lib,需要指定下面几个项目类别:

  • 期望的 use case,这部分是可以配置的
  • 用指定的 listener 来表明自己用获取到的输出做什么用途
  • 绑定到 Android Architecture Lifecycles 来实现自动化的生命周期管理

使用 set() 来配置一个 use case,然后使用 build() 完成构建,每一个用例都有一组特定的 API,比如对于 Image capture 来说就会提供 takePicture() API 来进行拍照动作。CameraX 使用生命周期管理框架来代替 onResumeonPause,使用 cameraProvider.bindToLifecycle 来绑定相应的 lifecycle 管理框架,一个示例代码如下:

val preview = Preview.Builder().build()val viewFinder: PreviewView = findViewById(R.id.previewView)// The use case is bound to an Android Lifecycle with the following codeval camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview)// PreviewView creates a surface provider and is the recommended providerpreview.setSurfaceProvider(viewFinder.createSurfaceProvider(camera.cameraInfo))

关于更多生命周期相关的代码以及使用介绍可以参考这里:https://developer.android.google.cn/training/camerax/architecture#lifecycles。其余还有并发 use case 等等的介绍,也可以参照链接里面的页面了解,这里就不再多说了。并且对于每一种 use case 用例的实现,链接里面也给出了相对应的子链接,可以参考其代码实现。

CameraX Extension

CameraX 提供了 bokeh、HDR 以及其它的效果接口,这些如果手机硬件厂商有实现的话就可以套接到这个接口上面。对于想要支持 vendor extension 的设备来说,下面的几个点是需要的(如果一个设备支持这些的话就可以优先启用这些扩展来支持更加灵活强大的功能项):

  • OEM 设备提供了相关效果的库包
  • OEM 库在当前设备上面有安装上去
  • OEM 库也需要通过某种方式 report 出来,说我这个支持对应的效果扩展
  • 操作系统版本要对应,这里安卓 5.0 以后的应该都是可以的

对于终端设备来讲,也并不是一定得要提供这些特性,对于没有实现的,会跳过这部分就当做不支持。有些设备可能别的都有,但是缺少 OTA 升级的库包,或者是单纯版本对不上,这些情况都是无法真正支持的。下面的图片也展示了 CameraX 的扩展结构:

可以看到 OEM Vendor lib 连接了 Camera2 以及 Extensions 两个模块,最主要的 data flow 是在 OEM Vendor lib 和 Extension 之间以及 Extension 和 CameraX core 之间的。如果需要应用 vendor extension 的话,需要创建一个 Extender 对象,可以通过这个对象设置 Builder,并且可以配置相关效果的设置。在使用的时候也需要先通过接口查询扩展项是否可用,因为如果扩展项处于不可用状态的话,enableExtension() 调用就是无效的,啥都不做。在 ImageCapture 模式下启用扩展的时候可能会限制可选的 camera 数量,在这个用例下使用 bindToLifecycle() 来绑定生命周期管理框架的时候,如果没有发现有支持这个扩展的 camera 的话,就会丢出一个异常。下面的代码给了一个 image capture 用例的示范:

import androidx.camera.extensions.BokehExtenderfun onCreate() {    // Create a Builder same as in normal workflow.    val builder = ImageCapture.Builder()    // Create a camera provider    val cameraProvider : ProcessCameraProvider = ... // Get the provider instance    // Create an Extender object which can be used to apply extension    // configurations.    val bokehImageCapture = BokehImageCaptureExtender.create(builder)    // Select the camera    val cameraSelector = CameraSelector.Builder()                                       .requireLensFacing(CameraX.LensFacing.BACK)                                       .build()    // Query if extension is available (optional).    if (bokehImageCapture.isExtensionAvailable()) {        // Enable the extension if available.        bokehImageCapture.enableExtension()    }    // Finish constructing configuration with the same flow as when not using    // extensions.    val useCase = ImageCapture.Builder().build()    cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, useCase)}

下面的图是一个 Vendor 扩展结构图:

三方的 APP 构建在 CameraX 扩展 lib 上面,通过 androidx.camera.extensions 接口 API 进行通信,再下层一点的 extensions-interface 也是由 CameraX 定义的,用于 CameraX 和 Vendor lib 进行交互,对于 Vendor 来说,必须要实现对应版本的接口。下面会通过人像模式的 Vendor 实现来进行一个简介,其它的模式实现也都是可以通过这个来进行推导实现。对于 Vendor 来说,不必要每一个都要实现,对于没有实现的效果来说,CameraX 会报告三方 APP 说我不支持就完事儿了,因为三方 APP 使用的原因,Vendor 实现的 lib 不应该有任何特殊的权限控制,不然三方就直接用不了了。

CameraX 在最开始的时候会检查 Vendor lib 的版本号看是否兼容,检查只包括主版本号和次版本号,比如 1.1,再后面的就当做是补丁号了,仅仅做一些 bug fix,不会改变接口。CameraX 会通过 ExtensionVersionImpl 接口来进行版本号校验。当 CameraX 决定好使用的版本号之后,InitializerImpl.init 方法就会被调用表明 APP 想要进行一些初始化动作,并且会一直等到 OnExtensionsInitializedCallback 返回成功之后才会进行其它的调用。

有关于 CameraX 扩展的这部分在:https://source.android.google.cn/devices/camera/camerax-vendor-extensions 这里可以找到相关的实现描述,由于这部分是与 framework 相关性较大,这里也就不做深入探索了,目前来讲对我来说知道有这么一个玩意儿就行了,用到时再去细究,不然记了也是白记,很快就忘掉了。

End

这里为止,Android Camera 的大概结构介绍就告一段落了,我觉得基本上差不多该提及的都有提到了,本系列也不是入门系列,有一定基础的话看起来会更加顺畅一点,零基础的我这个就很不适合看,会有一脸懵的感觉。接下来如果还更新 Android Camera 的话可能就会更新一些与内部设计结构相关的东西,这部分短时间内并不打算写出来,因为我觉得这部分比较抽象理论,而且很进阶,不好写,就算写出来大概率也是一个月一篇的样子,emmm,恰逢公众号和 CSDN 博客都有新开了付费阅读功能,这么老大劲写出来的估计会试用一波付费阅读。

后面应该会写一写 C++ 语言相关的东西,比较接近基础,这部分其实大部分都可以找到通用学习文章,但是我并不打算因此不写这部分内容,我就权当做自己学习 C++ 所做的笔记吧,当然会融入一些自我的思考,不然就是流水账,显得毫毫毫毫无技术含量了,穿插着应该会有一些数据结构与算法的内容,再夯实一下基础吧。目前个人的技能点就分了下面几个大的方面:

  1. 基础数据结构与算法
  2. 基础语言 C/C++ 编程(这个与上面一个都是比较通用的玩意儿,基本上网络上面的文章都是铺天盖地的,当然极度硬核的还是不是特别的多)
  3. 视频流数据管理、处理、分发框架(这部分有很多很多很多可以说的细节,算是比较硬核的一个点了,属于你网上都找不到太多资料的那种)
  4. 基本嵌入式视觉处理(视频防抖相关的技术族,包括但不限于图像插值、二维数据滤波、图像的投影变换、线性代数在图像几何的应用等等等等)

不得不说,现在工程细分的太深入了,当然也是因为产品质量的不断提高与客户需求的不断提升导致的,以前都是囫囵囵差不多做出来就完事儿了,现在不行,你不仅要做出来,还得稳定、效果好,这就使得越来越多的细节加入到具体的模块处理当中,导致不断的模块细分。咱就说防抖这一个,里面就能分出一个 10~20 人左右的团队来,每个人专门去做具体的某一块。这么庞大的技术细节,让我也不知道如何取舍,目前就希望不断地夯实上面四个技术点,然后有机会的话再去延伸其它的点感觉技术生涯前 8~10 年差不多就可以僵在这几个点上面了,后面可能不用再去关注那么多细节了,更多地会是注重整体结构性设计,不过走着看着吧,太远的未来终归是无法确定。


更多相关文章

  1. 没有一行代码,「2020 新冠肺炎记忆」这个项目却登上了 GitHub 中
  2. 编译 Android(安卓)版本的 Opus 音频编解码库的方法
  3. 老罗牛文二、在Ubuntu上下载、编译和安装Android最新源代码
  4. Service与Android系统设计(2)-- Parcel
  5. Android(安卓)1.6 支持更多的屏幕大小和分辨率
  6. Programming access to Android(安卓)Market
  7. 给Unity的Android工程加上广告代码(1)
  8. 静态扫描工具提升Android代码质量
  9. Android(安卓)SAX方式解析XML文件

随机推荐

  1. 这个冬天,他们实现了梦想中的华丽转身…
  2. 在Linux中的脚本中安装应用程序
  3. linux shell 里面,真值为0,假值为非0
  4. linux 多线程基础
  5. linux 内核协议栈
  6. Linux进程间通信(二):信号集函数 sigemptyse
  7. Linux C语言实现的Socket通信
  8. 总结一下linux中的分段机制
  9. 如何在Linux中以编程方式获取给定相对路
  10. 提高Linux安全性--hosts.allow, hosts.de