惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

阮一峰的网络日志
阮一峰的网络日志
Jina AI
Jina AI
GbyAI
GbyAI
D
DataBreaches.Net
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
Visual Studio Blog
P
Proofpoint News Feed
The Cloudflare Blog
H
Help Net Security
MyScale Blog
MyScale Blog
T
The Blog of Author Tim Ferriss
量子位
博客园 - 聂微东
Apple Machine Learning Research
Apple Machine Learning Research
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
MongoDB | Blog
MongoDB | Blog
Last Week in AI
Last Week in AI
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
月光博客
月光博客

音视频开发进阶

音视频教程-第三节 音视频教程-第二节 真的,AI 可能就是新时代的信息差 充值 Cursor 之后,工作有了哪些变化?🤔 个人'蒸馏'大模型能做哪些有意思的事情 DeepSeek 大模型在 Mac 上的部署和运行 音视频教程-第一节 【WebRTC 专栏】-- Android 开发集成 WebRTC 库的几种方式 【WebRTC 专栏】-- 在 Mac M1 等系列芯片编译和开发 WebRTC-Android 库 Meta Llama3 大模型在 Mac 上的部署和运行 iOS VideoToolBox 解码 HEVC Open-GOP 视频的问题排查 Flutter 状态管理之 InheritedWidget 使用和分析 用 ChatGPT 回答技术问题怎么样 ? 音视频开发系统入门大致路线 UE 4.27 添加自定义 ShadingModel 用 UE4 虚幻引擎做个捏脸小功能~~ UE4 材质练习 之 凹凸贴图偏移的使用 UE4 材质练习系列基础 OpenGL上下文创建以及共享机制 007 | 播放器系列专栏-解析 MP4 文件读取信息 006 | 播放器系列专栏-在 Mac 上查看 MP4 格式信息 干货 | 快速抽取缩略图是怎么练成的? 关于直播、WebRTC、FFmpeg 的那些事 005 | 播放器系列专栏-在 Windows 上查看 MP4 格式信息 将音视频中的花屏、绿屏、黑屏问题一网打尽 关于音视频里面的解码帧率和渲染帧率 004 | 播放器系列专栏-认识MP4视频(下) 003 | 播放器系列专栏-认识MP4视频(上) 入门或者转行音视频,应该要怎么做? H264视频文件如何缩放分辨率
Android Camera 模型及 API 接口演变
音视频开发进阶 · 2018-04-12 · via 音视频开发进阶

一个专注音视频领域的小圈子

要了解 Android Camear 相机模型的演变,首先还是得了解硬件抽象层 HAL 相关的知识内容。 可以通过这篇文章了解相关知识 Android 硬件抽象层调用流程小结,包括底层驱动、HAL 硬件抽象层接口、应用层到 HAL 的调用流程。

基本上 HAL 的调用流程都是相似的,对于 Camera 也是这样。

Android Camera HAL 调用

应用进程通过 Binder 通信得到一个系统服务,这个系统服务就是用来访问硬件的。

系统服务最后都是通过 HAL 的接口来访问硬件的驱动程序,从而最终访问硬件设备。

而 HAL 接口的实现方式则是由不同厂商去完成的,只需要按照接口定义的规范实现就好。

正是由于 Android Camera 的硬件抽象层发生了变化,访问硬件的方式有所改变,才导致相机模型发生变化,上层 API 接口也就随之变化了。

当了解了这些变化之后,再回过头去看 Camera 的 API 调用就显得清晰多了。

Android 5.0 之前的 Camera 版本,功能比较单一,不像 5.0 之后那样支持很多特性,这也是由于它的 HAL 所决定的。

用的是 android.hardware.Camera 包下的内容,回顾一下 Camera 1.0 的调用流程:

  • 创建预览类 ( SurfaceView )
  • 打开相机( Camera.open )
  • 设置预览 ( setPreviewDisplay )
  • 开始预览( startPreview )
  • 对焦( autoFocus )
  • 拍摄( takePicture )
  • 拍照监听器处理( PictureCallback )

Android 5.0 之前 HAL 接口

HAL 接口被设计成了三种运行模式:

  • 预览
  • 静态拍摄
  • 视频录制

其中,预览对应于代码中 Camera 类的 startPreview 函数,而静态拍摄对应于 Camera 类的 takePicture 函数,视频录制则是在 MediaRecorder 类的 setCamera 函数中传入 Camera 对象实例。

三种模式具有略有不同又相互重叠的功能。这样就难以实现新类型的功能(例如连拍模式),因为新类型的功能会介于其中两种模式之间。

从图中可以看到,应用层 Camera 会发出一个请求队列到 HAL ,请求队列中的每个请求都对应三种运行模式中的一种。

当你想要在预览时拍照,然后再返回预览模式,那么就得在拍照前发送请求切换到静态拍摄模式,拍完后再发送请求切换到预览模式。

Android Camera 2.0 的相机模型

在 Android 5.0 之后,相机 API 就有了较大的变化,用的是 android.hardware.camera2 包下的内容了。

回顾一下 Camera 2.0 的调用流程:

  • 创建预览类( SurfaceView 或者 TextureView 都行)
  • 打开相机( CameraManager.openCamera )
  • 相机回调( CemeraDevice.StateCallback )
  • 创建 CameraCaptureSession 会话( createCaptureSession )
  • 创建一个进行预览的请求( CaptureRequest.Builder )
  • 预览请求中设置输出的 Surface( addTarget )
  • 在会话中发出预览的请求( setRepeatingRequest )
  • 在会话的回调类中处理发出请求的结果( CameraCaptureSession.CaptureCallback )
  • 拍照时,创建一个拍照的请求( CaptureRequest )
  • 在会话中发出拍照的请求( capture )
  • 在会话的回调类中处理发出请求的结果( CameraCaptureSession.CaptureCallback )

以上就是 Camera 2.0 相关的调用流程和对应的重要函数,大致就是每做一次操作都要在会话中发出一次请求。

更具体的如下极客学院流程图所示:

Android Camera 2.0 调用

Camera 2.0 的架构将多个运行模式整合为一个统一的视图,可以使用这种视图实现之前的任何模式以及一些其他模式,如连拍模式。这样一来,便可以提高用户对聚焦、曝光以及更多后期处理(例如降噪、对比度和锐化)效果的控制能力。此外,这种简化的视图还能够使应用开发者更轻松地使用相机的各种功能。

Camera 2.0 将相机系统塑造为一个管道,该管道可按照 1:1 的基准将传入的帧捕获请求转化为帧。这些请求会封装有关帧的捕获和处理的所有配置信息,其中包括分辨率和像素格式;手动传感器、镜头和闪光灯控件;3A 运行模式;RAW->YUV 处理控件;统计信息生成等等。

简单来说,应用框架从相机系统请求帧,然后相机系统将结果返回到输出流。

可以将 Camera 2.0 看作是 Camera 1.0 的单向流管道。它会将每个捕获请求转化为传感器捕获的一张图像,这张图像将被处理成:

  • 包含有关捕获的元数据的结果对象。
  • 图像数据的 1 到 N 个缓冲区,每个缓冲区会进入自己的目的地 Surface。也就是我们创建 CaptureRequest 时的 addTarget 添加的 Surface。

可能的输出 Surface 组经过预配置:

  • 每个 Surface 都是一个固定分辨率的图像缓冲区流的目标位置
  • 一次只能将少量的 Surface 配置为输出(约 3 个)

一个请求中包含所需的全部捕获设置,以及要针对该请求将图像缓冲区推送到其中的输出 Surface 的列表。请求可以只发生一次(使用 capture ),也可以无限重复(使用 setRepeatingRequest )。捕获的优先级高于重复请求的优先级。

相机运行核心模式

如上图所示,一个 capture 请求,左边就是要输出的目的 Surface 列表。而 CameraDevice 框内的就是请求的队列。相机的硬件设备会处理每个请求,将图像数据的缓冲区输出到设置的目的 Surface 中,同时在回调的 onCaptureComplete 方法中处理请求的结果 CaptureResult。

就是这样一个队列模型,相机系统不断地处理队列中的请求,并且一次可以发起多个请求,而且提交的请求不会出现阻塞的情况,请求始终按照接收的顺序处理。

同样的,如果想要实现连拍功能,只要不断发送捕获的请求 capture 就好了,而不需要像之前一样每次拍完照还得设置回预览模式。

相机模型

这是一个更全面的相机模型图:

相机模型

在模型图里把一些主要函数和流程图都绘制包含进去了。我们调用的流程基本也是顺着紫色的 API 接口来的。

可以看到,相机可以设置六种类型的 Surface 输出:

  • MediaRecorder
  • SurfaceView
  • RenderScriptAllocation
  • ImageReader
  • MediaCodec
  • SurfaceTexture

而在 CameraCaptureSession 会话类中,发出的请求方法有如下:

  • capture()
  • captureBurst()
  • setStreamingRequest()
  • setStreamingBurst()
  • stopRepeating()

发出请求后,交由相机硬件去处理,处理后的会先将图像数据输出到缓冲区,然后再从缓冲区输出到设置的目的 Surface。

同时,在会话中发出请求,在请求的回调中还会返回 CaptureResult 这样的请求结果,相当于是一个请求有两个返回的来源了。

经过这样的理解安卓相机模型之后,再去看 API 的调用就不会那么困惑了。

关于 Android Camera 的相关代码,可以参考我的 Github 工程:https://github.com/glumes/Camera2Sample

参考

1、https://source.android.com/devices/camera/

原创文章,转载请注明来源:    Android Camera 模型及 API 接口演变