Android Camera2 教程 · 第一章 · 概览

从 Android 5.0 开始,Google 引入了一套全新的相机框架 Camera2(android.hardware.camera2)而且废弃了旧的相机框架 Camera1(android.hardware.Camera)。做为一个专门从事相机应用开发的开发者来讲,这一刻我等了过久了,Camera1 那寥寥无几的 API 和极差的灵活性早已不能知足日益复杂的相机功能开发。Camera2 的出现给相机应用程序带来了巨大的变革,由于它的目的是为了给应用层提供更多的相机控制权限,从而构建出更高质量的相机应用程序。本文是 Camera2 教程的开篇做,本章将介绍如下几个内容:android

  • 一些 Camera2 的重要概念
  • 一些只有 Camera2 才支持的高级特性
  • 一些从 Camera1 迁移到 Camera2 的建议

本章涉及的代码不多,由于咱们会在接下来的教程中深刻介绍 Camera2 的 API。框架

1 Pipeline

Camera2 的 API 模型被设计成一个 Pipeline(管道),它按顺序处理每一帧的请求并返回请求结果给客户端。下面这张来自官方的图展现了 Pipeline 的工做流程,咱们会经过一个简单的例子详细解释这张图。async

Pipeline 示意图性能

为了解释上面的示意图,假设咱们想要同时拍摄两张不一样尺寸的图片,而且在拍摄的过程当中闪光灯必须亮起来。整个拍摄流程以下:spa

  1. 建立一个用于从 Pipeline 获取图片的 CaptureRequest。
  2. 修改 CaptureRequest 的闪光灯配置,让闪光灯在拍照过程当中亮起来。
  3. 建立两个不一样尺寸的 Surface 用于接收图片数据,而且将它们添加到 CaptureRequest 中。
  4. 发送配置好的 CaptureRequest 到 Pipeline 中等待它返回拍照结果。

一个新的 CaptureRequest 会被放入一个被称做 Pending Request Queue 的队列中等待被执行,当 In-Flight Capture Queue 队列空闲的时候就会从 Pending Request Queue 获取若干个待处理的 CaptureRequest,而且根据每个 CaptureRequest 的配置进行 Capture 操做。最后咱们从不一样尺寸的 Surface 中获取图片数据而且还会获得一个包含了不少与本次拍照相关的信息的 CaptureResult,流程结束。线程

2 Supported Hardware Level

相机功能的强大与否和硬件息息相关,不一样厂商对 Camera2 的支持程度也不一样,因此 Camera2 定义了一个叫作 Supported Hardware Level 的重要概念,其做用是将不一样设备上的 Camera2 根据功能的支持状况划分红多个不一样级别以便开发者可以大概了解当前设备上 Camera2 的支持状况。截止到 Android P 为止,从低到高一共有 LEGACY、LIMITED、FULL 和 LEVEL_3 四个级别:设计

  1. LEGACY:向后兼容的级别,处于该级别的设备意味着它只支持 Camera1 的功能,不具有任何 Camera2 高级特性。
  2. LIMITED:除了支持 Camera1 的基础功能以外,还支持部分 Camera2 高级特性的级别。
  3. FULL:支持全部 Camera2 的高级特性。
  4. LEVEL_3:新增更多 Camera2 高级特性,例如 YUV 数据的后处理等。

3 Capture

相机的全部操做和参数配置最终都是服务于图像捕获,例如对焦是为了让某一个区域的图像更加清晰,调节曝光补偿是为了调节图像的亮度。所以,在 Camera2 里面全部的相机操做和参数配置都被抽象成 Capture(捕获),因此不要简单的把 Capture 直接理解成是拍照,由于 Capture 操做可能仅仅是为了让预览画面更清晰而进行对焦而已。若是你熟悉 Camera1,那你可能会问 setFlashMode() 在哪?setFocusMode() 在哪?takePicture() 在哪?告诉你,它们都是经过 Capture 来实现的。code

Capture 从执行方式上又被细分为【单次模式】、【屡次模式】和【重复模式】三种,咱们来一一解释下:教程

  • 单次模式(One-shot):指的是只执行一次的 Capture 操做,例如设置闪光灯模式、对焦模式和拍一张照片等。多个一次性模式的 Capture 会进入队列按顺序执行。接口

  • 屡次模式(Burst):指的是连续屡次执行指定的 Capture 操做,该模式和屡次执行单次模式的最大区别是连续屡次 Capture 期间不容许插入其余任何 Capture 操做,例如连续拍摄 100 张照片,在拍摄这 100 张照片期间任何新的 Capture 请求都会排队等待,直到拍完 100 张照片。多组屡次模式的 Capture 会进入队列按顺序执行。

  • 重复模式(Repeating):指的是不断重复执行指定的 Capture 操做,当有其余模式的 Capture 提交时会暂停该模式,转而执行其余被模式的 Capture,当其余模式的 Capture 执行完毕后又会自动恢复继续执行该模式的 Capture,例如显示预览画面就是不断 Capture 获取每一帧画面。该模式的 Capture 是全局惟一的,也就是新提交的重复模式 Capture 会覆盖旧的重复模式 Capture。

4 CameraManager

CameraManager 是一个负责查询和创建相机链接的系统服务,它的功能很少,这里列出几个 CameraManager 的关键功能:

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

5 CameraCharacteristics

CameraCharacteristics 是一个只读的相机信息提供者,其内部携带大量的相机信息,包括表明相机朝向的 LENS_FACING;判断闪光灯是否可用的 FLASH_INFO_AVAILABLE;获取全部可用 AE 模式的 CONTROL_AE_AVAILABLE_MODES 等等。若是你对 Camera1 比较熟悉,那么 CameraCharacteristics 有点像 Camera1 的 Camera.CameraInfo 或者 Camera.Parameters

6 CameraDevice

CameraDevice 表明当前链接的相机设备,它的职责有如下四个:

  1. 根据指定的参数建立 CameraCaptureSession。
  2. 根据指定的模板建立 CaptureRequest。
  3. 关闭相机设备。
  4. 监听相机设备的状态,例如断开链接、开启成功和开启失败等。

熟悉 Camera1 的人可能会说 CameraDevice 就是 Camera1 的 Camera 类,实则不是,Camera 类几乎负责了全部相机的操做,而 CameraDevice 的功能则十分的单一,就是只负责创建相机链接的事务,而更加细化的相机操做则交给了稍后会介绍的 CameraCaptureSession。

7 Surface

Surface 是一块用于填充图像数据的内存空间,例如你可使用 SurfaceView 的 Surface 接收每一帧预览数据用于显示预览画面,也可使用 ImageReader 的 Surface 接收 JPEG 或 YUV 数据。每个 Surface 均可以有本身的尺寸和数据格式,你能够从 CameraCharacteristics 获取某一个数据格式支持的尺寸列表。

8 CameraCaptureSession

CameraCaptureSession 实际上就是配置了目标 Surface 的 Pipeline 实例,咱们在使用相机功能以前必须先建立 CameraCaptureSession 实例。一个 CameraDevice 一次只能开启一个 CameraCaptureSession,绝大部分的相机操做都是经过向 CameraCaptureSession 提交一个 Capture 请求实现的,例如拍照、连拍、设置闪光灯模式、触摸对焦、显示预览画面等等。

9 CaptureRequest

CaptureRequest 是向 CameraCaptureSession 提交 Capture 请求时的信息载体,其内部包括了本次 Capture 的参数配置和接收图像数据的 Surface。CaptureRequest 能够配置的信息很是多,包括图像格式、图像分辨率、传感器控制、闪光灯控制、3A 控制等等,能够说绝大部分的相机参数都是经过 CaptureRequest 配置的。值得注意的是每个 CaptureRequest 表示一帧画面的操做,这意味着你能够精确控制每一帧的 Capture 操做。

10 CaptureResult

CaptureResult 是每一次 Capture 操做的结果,里面包括了不少状态信息,包括闪光灯状态、对焦状态、时间戳等等。例如你能够在拍照完成的时候,经过 CaptureResult 获取本次拍照时的对焦状态和时间戳。须要注意的是,CaptureResult 并不包含任何图像数据,前面咱们在介绍 Surface 的时候说了,图像数据都是从 Surface 获取的。

11 一些只有 Camera2 才支持的高级特性

若是要我给出强有力的理由解释为何要使用 Camera2,那么经过 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 操做,而且监听本此次拍照是否点亮闪光灯。

12 一些从 Camera1 迁移到 Camera2 的建议

若是你熟悉 Camera1,而且打算从 Camera1 迁移到 Camera2 的话,但愿如下几个建议能够对你起到帮助:

  1. Camera1 严格区分了预览和拍照两个流程,而 Camera2 则把这两个流程都抽象成了 Capture 行为,只不过一个是不断重复的 Capture,一个是一次性的 Capture 而已,因此建议你不要带着过多的 Camera1 思惟使用 Camera2,避免由于思惟上的束缚而没法充分利用 Camera2 灵活的 API。

  2. 如同 Camera1 同样,Camera2 的一些 API 调用也会耗时,因此建议你使用独立的线程执行全部的相机操做,尽可能避免直接在主线程调用 Camera2 的 API,HandlerThread 是一个不错的选择。

  3. Camera2 全部的相机操做均可以注册相关的回调接口,而后在不一样的回调方法里写业务逻辑,这可能会让你的代码由于不够线性而错综复杂,建议你能够尝试使用子线程的阻塞方式来尽量地保证代码的线性执行(熟悉 Dart 的人必定很喜欢它的 async 和 await 操做)。例如在子线程阻塞等待 CaptureResult,而后继续执行后续的操做,而不是将代码拆分到到 CaptureCallback.onCaptureCompleted() 方法里。

  4. 你能够认为 Camera1 是 Camera2 的一个子集,也就是说 Camera1 能作的事情 Camera2 必定能作,反过来则不必定行得通。

  5. 若是你的应用程序须要同时兼容 Camera1 和 Camera2,我的建议分开维护,由于 Camera1 蹩脚的 API 设计极可能让 Camera2 灵活的 API 没法获得充分的发挥,另外将两个设计上彻底不兼容的东西搅和在一块儿带来的痛苦可能远大于其带来便利性,多写一些冗余的代码也许还更开心。

  6. 官方说 Camera2 的性能会更好,这句话听听就好,起码在较早期的一些机器上运行 Camera2 的性能并无比 Camera1 好。

  7. 当设备的 Supported Hardware Level 低于 FULL 的时候,建议仍是使用 Camera1,由于 FULL 级别如下的 Camera2 能提供的功能几乎和 Camera1 同样,因此倒不如选择更加稳定的 Camera1。

13 结束语

本章到此结束,主要是介绍了 Camera2 的一些基础概念,让你们可以基本了解 Camera2 的工做流程和基础概念,而且知道使用 Camera2 可以作些什么。若是你对 Camera2 仍是感到很陌生,没关系,后续的教程会带领你们逐步深刻了解 Camera2。

相关文章
相关标签/搜索