Camera Framework
分析,本文主要介绍 Camera API2
相关。
类文件速查表
类文件目录
1 | 1. Framework Java API1:frameworks/base/core/java/android/hardware/Camera.java |
JNI
相关
1 | // frameworks/base/core/jni |
API 1
中,使用 jni
通过 Binder
机制和 CameraService
通信。API 2
中,直接在 CameraManager.java
中通过 Binder
机制和 CameraService
通信。
AIDL
相关
Framework Camere AIDL
是 Camera
中客户端和服务端跨进程通信时使用的 AIDL
文件,代码都在 frameworks/av/camera/
目录下,其中 aidl
文件一共有 16 个:
1 | xmt@server005:~/frameworks/av/camera/aidl/android/hardware$ tree |
frameworks/av/camera/aidl/
目录下的 aidl
文件有两种类型:
- 作为
Binder
中的IInterface
跨进程通信中能提供的方法 - 作为
Binder
中的parcelable
跨进程通信数据传输的数据结构
很容易从名字上区分这两种类型的文件,IInterface
类型的文件都是以 I
开头的,比如:ICameraService.aidl, ICameraDeviceUser.aidl
等。不管是哪种类型的 aidl
文件,它们都会生成对应的 .java, .h, .cpp
文件,分别供 Java
层和 CPP
层调用。
IInterface
类型文件
IInterface
类型文件一共有 7 个,它们的 .java, .h, .cpp
文件,绝大部分都是自动生成的。
Java
文件是在 frameworks/base/Android.mk
中定义规则,在编译时自动生成:
1 | // frameworks/base/Android.mk |
在 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/dotdot/
目录下生成对应的 Java
文件:
1 | // out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/dotdot/ |
.h, .cpp
文件中,ICamera.aidl, ICameraClient.aidl
两个文件是直接以代码形式手动实现的:
1 | // 1. ICameraClient.aidl |
其他 5 个 aidl
文件是在 frameworks/av/camera/Android.bp
中定义规则,编译时自动生成对应的 .h, .cpp
文件:
1 | // frameworks/av/camera/Android.bp |
在 out/soong/.intermediates/frameworks/av/camera/libcamera_client/
目录下生成对应的 .h, .cpp
文件,通常在该目录下会同时生成 32 和 64 位两套代码,但实际两份代码是一样的,这里选取 64 位的:
- 64 位:
android_arm64_armv8-a_shared_core
- 32 位:
android_arm_armv7-a-neon_cortex-a53_shared_core
1 | // 目录 out/soong/.intermediates/frameworks/av/camera/libcamera_client |
parcelable
类型文件
parcelable
类型文件一共有 9 个,它们都是手动编写的代码。
Java
文件目录为 frameworks/base/core/java/android/hardware/
:
1 | // frameworks/base/core/java/android/hardware/ |
.h, .cpp
文件并不一定是和 aidl
文件名称一一对应的,而是在 aidl
文件中定义的,比如 CameraStatus.aidl
定义如下:
1 | package android.hardware; |
parcelable
类型的 aidl
文件对应的 .h, .cpp
文件目录为 frameworks/av/camera
,对应关系整理如下:
1 | // .h, .cpp 文件目录 frameworks/av/camera |
ICameraService
相关
分为客户端向服务端的请求 ICameraService.aidl
和客户端监听服务端的变化 ICameraServiceListener.aidl
。这两个 AIDL
是在 CameraService.cpp
中实现对应功能的。
1 | // 1. ICameraService.aidl |
ICameraServiceProxy.aidl
文件
CameraServiceProxy
服务是在 Java
层注册的:
1 | interface ICameraServiceProxy |
ICamera
相关
Camera API1
才会使用到,分为 ICamera.aidl, ICameraClient.aidl
它们的代码是手动实现的,参考:CameraClient.h/cpp, Camera.h/cpp
ICameraDevice
相关
Camera API2
才会使用到,分为客户端向服务端的请求 ICameraDeviceUser.aidl
和服务端发给客户端的回调 ICameraDeviceCallbacks.aidl
。
表示相机设备具备的能力,能够提供的函数;这两个 AIDL
是在 CameraDeviceClient
中实现对应功能的。
1 | // 1. ICameraDeviceUser.aidl |
Services
目录下的文件介绍
frameworks/av/services/camera/libcameraservice
AOSP
中这个目录下是 87 个文件,而 Qcom
的基线中增加了 27 个文件,分别为 api1/qticlient2
目录下的 25 个文件,以及 QTICamera2Client.cpp, QTICamera2Client.h
两个文件。
1 | . |
从目录结构上可以看出,API1/2
和 HAL1/3
就是在这一层体现的。
API1/API2
APP Java
客户端调用服务端方法时,Camera API1/2
接口对应功能都是在 CameraService
中实现的,而这里的 API1/2
目录对应的就是对上层不同版本接口的处理。
1 | api1 |
BasicClient
有三个重要的子类:
CameraClient
如果平台仅支持HAL 1
,即CAMERA_DEVICE_API_VERSION_1_0
;使用API 1/2 + HAL 1
都会对应该客户端。Camera2Client
如果平台支持HAL 3
,即CAMERA_DEVICE_API_VERSION_3_0
及以上版本;使用API 1 + HAL 3
对应的客户端。Camera2Client
会将API1
中的接口转换为API2
中对应的功能。CameraDeviceClient
如果平台支持HAL 3
,使用API 2 + HAL 3
对应的客户端。
平台仅支持 HAL 1
时,API 2
在 openCamera
时,通过 CameraDeviceUserShim
将 API 2
转换为 API 1
,即 HAL 1 + API 1
向下发起请求。LegacyCameraDevice
会将 CAMERA API2
转换为 CAMERA API1
,而 CameraDeviceUserShim
封装了 LegacyCameraDevice
。
QTICamera2Client
Qcom
的基线中增加了 27 个文件,分别为 api1/qticlient2
目录下的 25 个文件,以及 QTICamera2Client.cpp, QTICamera2Client.h
两个文件。
而 QTICamera2Client
是高通针对 API1
做的优化?在什么情况下会转换为 QTICamera2Client
呢?看如下源码:
1 | // 1. Camera2Client.h |
QTICamera2Client
是高通对 API 1
中 Camera2Client
做的一层封装,添加了部分功能,主要是向上提供 raw
数据。
1 | // 1. QTICamera2Client.h |
device1/device3
device1/device3
可以理解为 Framework
层对应 HAL
层的 HAL 1/3
。
1 | device1 |
API1/device1/HAL1
的连接过程
1 | // API1: CameraClient.h |
API1
的客户端 CameraClient
对应的 device1: CameraHardwareInterface
,而它直接包含了 HAL1
中 ICameraDevice
。
API1/3/device3/HAL3
的连接过程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36// API1: Camera2Client.h
class Camera2Client :
public Camera2ClientBase<CameraService::Client>{...}
// API2: CameraDeviceClient.h
class CameraDeviceClient :
public Camera2ClientBase<CameraDeviceClientBase>,
public camera2::FrameProcessorBase::FilteredListener{...}
// Camera2ClientBase.h
sp<CameraDeviceBase> mDevice;
// Camera2ClientBase.cpp
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(
const sp<CameraService>& cameraService,
const sp<TCamCallbacks>& remoteCallback,
const String16& clientPackageName,
const String8& cameraId,
int cameraFacing,
int clientPid,
uid_t clientUid,
int servicePid):
TClientBase(cameraService, remoteCallback, clientPackageName,
cameraId, cameraFacing, clientPid, clientUid, servicePid),
mSharedCameraCallbacks(remoteCallback),
mDeviceVersion(cameraService->getDeviceVersion(
TClientBase::mCameraIdStr)),
mDeviceActive(false)
{
...
mInitialClientPid = clientPid;
// 只要是 HAL3 ,则 device 都是对应的 Camera3Device
mDevice = new Camera3Device(cameraId);
...
}
从源码可以看出,不管是 API1/2
,只要是 HAL 3
,Camera2Client, CameraDeviceClient
两个客户端对应的都是 device3: Camera3Device
。
Camera3Device::HalInterface
内部类,用于和 HAL
层通信,实现了 HAL
层 ICameraDeviceSession.hal
部分代码:
1 | // Camera3Device.h |
cameraserver
进程
cameraserver
进程的源码在 frameworks/av/camera/cameraserver
目录下,该目录只有三个文件:
1 | . |
cameraserver
进程在启动时,做了三件事:
- 设置
Socket
通信时,对端关闭读取时进程不退出,返回错误信息(Socket
用在了哪?) HIDL
通信初始化Native Binder
初始化,CameraService
向service_manager
注册服务
1 | // frameworks/av/camera/cameraserver/main_cameraserver.cpp |
1 | // init 进程启动名字为 cameraserver 的进程及对应路径 |
CameraService
启动服务注册流程图:
CameraService
服务
CameraService
服务的名称为:media.camera
,主要有两个功能:
- 作为服务端
实现AIDL
对应功能,当API1/2
客户端发出请求后,作为服务端响应并处理这些功能。 - 作为客户端
实现HIDL
回调,用于响应HAL
层发回的回调。并且通过CameraProviderManager
和HAL
层实现双向通信。
服务名称
CameraService
继承了 BinderService<CameraService>
,将 CameraService::instantiate();
代码展开:
1 | // BinderService.h |
从继承关系及 CameraService.h
源码,getServiceName
设置了 CameraService
服务的名称为 media.camera
。
注册流程图
源码分析
先来看 CameraService.h
头文件相关定义:
1 | // CameraService.h |
BinderService
继承了BinderService
,用于注册服务。服务名称为media.camera
。camera_module_callbacks_t
继承了camera_module_callbacks_t
,它是在HAL
中定义的,用于HAL
向Framework
发送通知。StatusListener
继承了StatusListener
,它是在CameraProviderManager.h
中定义的,用于CameraProviderManager
向CameraService
发送通知。
现在查看 CameraService
的构造方法,因为在注册服务时 BinderService
会对 CameraService
强指针引用,所以会调用对应函数 onFirstRef
:
1 | // CameraService.cpp |
构造函数中非常简单,仅仅是将 camera_module_callbacks_t
结构体的函数指针赋值;在 onFirstRef
中,主要通过 enumerateProviders
来实例化对应的 CameraProviderManager
并连接 HAL
,最后去 ping
一次 CameraServiceProxy
代理服务,实际上是 ping
不通的,因为 CameraService.cpp
一定是比 CameraServiceProxy.java
启动的早。
1 | // CameraService.cpp |
如果 mCameraProviderManager
为空,则实例化并调用 initialize
;接着实例化 CameraFlashlight
;先看头文件 CameraProviderManager.h
中定义的几个重要数据结构和函数:
1 | // CameraProviderManager.h |
ServiceInteractionProxy
定义了几个纯虚函数,用于向HAL
系统服务中注册registerForNotifications
监听ICameraProvider.hal
的消息;getService
返回ICameraProvider
的实例。HardwareServiceInteractionProxy
ServiceInteractionProxy
的实现结构体,具体调用ICameraProvider
对应的registerForNotifications, getService
;也就是CameraProviderManager
持有ICameraProvider
的远程实例。onRegistration
registerForNotifications
的回调函数,注册成功后回调。StatusListener
状态监听接口,这些接口是在CameraService
中实现的;用于CameraProviderManager
回调CameraService
。sHardwareServiceInteractionProxy
静态变量,是初始化initialize
函数形参ServiceInteractionProxy
的默认值。
从 CameraService
中调用 CameraProviderManager::initialize
时,传入的是 CameraService
的实例,仅仅一个参数,所以 ServiceInteractionProxy
使用的是默认的 sHardwareServiceInteractionProxy
实例。
1 | // CameraProviderManager.cpp |
CameraProviderManager::initialize
中主要是初始化赋值 mListener, mServiceProxy
,并通过 sHardwareServiceInteractionProxy->registerForNotifications
向 HIDL
服务管理注册了自己,最后调用 addProviderLocked
。
1 | // CameraProviderManager.cpp |
addProviderLocked
中有如下信息:
- 通过代理获取
ICameraProvider
实例,用于和HAL
通信 - 新建
ProviderInfo
并初始化,保存ICameraProvider
实例 mProviders
保存所有的ProviderInfo
(实测只有一个实例元素,名称为legacy/0
)
1 | // CameraProviderManager.h |
ProviderInfo
继承了 ICameraProviderCallback, hidl_death_recipient
,它会处理来着 ICameraProvider
的回调。
1 | // CameraProviderManager.cpp |
ProviderInfo::initialize
初始化,主要是从 HAL
获取设备名后,添加具体的设备信息。
1 | // CameraProviderManager.h |
头文件中可以看出,DeviceInfo
有两个子类,分别对应 HAL 1
和 HAL 3
,并将具体的 ICameraDevice
版本保存到 mInterface
中;所以设备添加时也会根据不同版本分别添加:
1 | // CameraProviderManager.cpp |
根据传入的 deviceName
解析版本号、类型、设备 Id
(前后摄),并根据 major
版本号(表示 HAL 1
或者 HAL 3
) 分别初始化对应的 DeviceInfo
;在 initializeDeviceInfo
中通过 getDeviceInterface
获取对应的 ICameraDevice
版本,在对应版本 DeviceInfo
实例化时保存;也就是将 DeviceInfo
和 HAL
层的 ICameraDevice
绑定。
1 | // CameraProviderManager.cpp |
这里分析的是 DeviceInfo3
的构造函数,它会向 HAL
层请求当前设备的配置信息,并保存 mCameraCharacteristics
,后续查看属性时都会通过这个变量查询。CameraService::enumerateProviders
中,首先新建并初始化 CameraProviderManager
,其持有和 HAL
通信的实例;接着新建并初始化 CameraFlashlight
,用于控制闪光灯。先看头文件:
1 | // CameraFlashlight.h |
头文件定义的几个信息:
CameraHardwareInterfaceFlashControl
HAL 1
闪光灯控制类,通过CameraHardwareInterface
向下调用。ProviderFlashControl
HAL 3
闪光灯控制类。FlashControlBase
基类。CameraProviderManager
主要用于ProviderFlashControl
向下发送信息。camera_module_callbacks_t
HAL
层的回调。
1 | // CameraFlashlight.cpp |
CameraFlashlight
的构造函数仅仅初始化了几个本地变量,CameraService
中调用 CameraFlashlight::findFlashUnits
时,会根据 HAL 1/3
分别来创建对应的闪光灯控制类。至此整个 CameraService
注册流程结束。
小结
CameraService
初始化和注册流程中,实例化了两个对象:
CameraProviderManager mCameraProviderManager
对象Flashlight mFlashlight
对象
CameraProviderManager
初始化完后:
mProviders
保存了ProviderInfo
对象;并关联了ICameraProvider
,用于和HAL
通信ProviderInfo
中mDevices
保存了所有的DeviceInfo1, DeviceInfo3
设备信息,并关联ICameraDevice
实例,用于直接通信DeviceInfo1
中保存了CameraParameters2 mDefaultParameters
参数信息DeviceInfo3
中保存了CameraMetadata mCameraCharacteristics
参数信息
CameraFlashlight
新建和初始化后:
- 如果是
HAL 1
会实例化控制类CameraHardwareInterfaceFlashControl
- 如果是
HAL 3
会实例化控制类ProviderFlashControl
Camera Open
流程
API
Camera API 2
开启摄像头设备时,通过 CameraManager.openCamera
来打开:
1 | // CameraManager.java |
String cameraId
表示前后摄的ID
,通常 0 表示后摄。CameraDevice.StateCallback callback
打开设备时,状态回调接口。Handler handler
表示回调接口在哪个线程执行。
示例
打开一个设备,在回调中保存 CameraDevice
:
1 | CameraDevice.StateCallback mCameraDeviceStateCallback |
CameraDevice.StateCallback
接口
在打开设备时,会传入 StateCallback
回调接口,它有四个方法,都是在 CameraDeviceImpl
中回调的:
onOpened
在CameraManager.openCameraDeviceUserAsync
方法中,CameraDeviceImpl.setRemoteDevice(cameraUser);
会触发StateCallback.onOpened
回调。onClosed
CameraDevice.close
是在CameraDeviceImpl.close
中实现的,同时会触发StateCallback.onClosed
回调。onDisconnected
CameraDeviceImpl.setRemoteDevice(cameraUser);
中如果远程连接断开,或者ICameraDeviceCallbacks.onDeviceError
返回了ERROR_CAMERA_DISCONNECTED
错误码,都会触发StateCallback.onDisconnected
回调。onError
在Binder
通信中绑定失败binderDied
,setRemoteFailure
以及ICameraDeviceCallbacks.onDeviceError
返回了ERROR_CAMERA_DEVICE/ERROR_CAMERA_SERVICE
错误码,都会触发StateCallback.onError
回调。
在设备打开时,会通过 StateCallback
回调返回打开状态,从代码可以看出,只要 ICameraService.connectDevice
成功后,直接调用 CameraDeviceImpl.setRemoteDevice(cameraUser);
来触发 StateCallback.onOpened
,表示设备打开成功。StateCallback
是 Java
接口,它的 onDisconnected, onError
两个回调方法,需要真实的与物理设备交互;所以需要通过 ICameraDeviceCallbacks.aidl
从 Framework Service
中获取真实的信息回调。
流程图
Camera API 2
开启相机设备流程图:
源码分析
通过 CameraManager.openCamera
打开设备,我们重点分析如下代码,代码执行路径为 :openCamera -> openCameraForUid -> openCameraDeviceUserAsync
1 | // CameraManager.java |
从上面展示的 API
部分代码中可以看出:
- 支持
API 2
如果系统开启了HAL 3
,则支持API 2
;此时通过ICameraService
访问服务。 - 不支持
API 2
如果系统仅支持HAL 1
,则API 2
需要通过CameraDeviceUserShim
转换为对应的API 1 + HAL 1
来实现对应功能。CameraDeviceUserShim
是ICameraDeviceUser
的实现类;整个frameworks/base/core/java/android/hardware/camera2/legacy
目录下的代码都是为了实现这个转换功能。
整个打开设备的动作有如下功能:
- 新建了
CameraDeviceImpl
实例,它是CameraDevice
的实现类 CameraManager
通过CameraService.connectDevice
连接设备,获取到ICameraDeviceUser, ICameraDeviceCallbacks
对象,它们用于后续CameraDeviceImpl.java
和CameraDeviceClient.cpp
绑定通信- 新建
ICameraDeviceUserWrapper
实例,它是对ICameraDeviceUser
的包装类,捕获并处理远程访问异常等
这里需要重点分析 connectDevice
:
1 | // CameraService.cpp |
CameraService::connectDevice
函数调用了模板函数 connectHelper
,而该模板主要的两个功能就是:makeClient
新建客户端,initialize
初始化客户端。
1 | Status CameraService::makeClient(const sp<CameraService>& cameraService, |
makeClient
主要是根据 device, HAL
版本和调用 API
的版本来创建对应的客户端:
HAL 1 + API 1
:新建CameraClient
HAL 1 + API 2
:不支持HAL 3 + API 1
:新建Camera2Client
HAL 3 + API 2
:新建CameraDeviceClient
这里的三个变量 effectiveApiLevel, legacyMode=0, halVersion
,主要是有三个连接函数决定: connect, connectLegacy, connectDevice
,其中 connectLegacy
可以指定 HAL
版本(来决定到底使用哪个 client
):
- 使用系统自带相机
effectiveApiLevel=1, legacyMode=1, halVersion=256(HAL 1)
,系统自带应用使用的是connectLegacy
。 - 使用标准
API2
接口effectiveApiLevel=2, legacyMode=0, halVersion=-1
,其中 -1 表示CAMERA_HAL_API_VERSION_UNSPECIFIED
。
所谓的 HAL
版本,实际指的就是 Device
的版本:其中 HAL 1
对应 CAMERA_DEVICE_API_VERSION_1_0
;HAL 3
对应的是 CAMERA_DEVICE_API_VERSION_3_0
及以上版本。而 HAL 2
和 CAMERA_DEVICE_API_VERSION_2_0
已经废弃。
因为手机平台使用 HAL 3
时,为了满足部分应用中使用了 API 1
的接口,常常需要兼容 HAL 1
,所以支持 HAL 3
即意味着同时会支持 HAL 1
。
这里流程跟踪的是新建 CameraDeviceClient
,先看头文件:
1 | // CameraService.h |
从类图结构来看:BasicClient
是三个客户端 CameraClient, Camera2Client, CameraDeviceClient
的基类;而 Camera2ClientBase
中的变量 CameraDeviceBase
实际的子类是 Camera3Device
。来看构造函数的流程:
1 | // CameraDeviceClient.cpp |
根据类继承关系,一条链路实例化各个子类,最终会新建 Camera3Device
实例。makeClient
新建完客户端后,调用客户端的初始化:
1 | // CameraDeviceClient.cpp |
CameraDeviceClient::initializeImpl
是一个模板函数,主要有两个功能:调用 Camera2ClientBase
及其父类初始化;新建 FrameProcessorBase
实例,它主要功能是在发出预览、拍照、录像请求后,HAL
层向 Framework
层返回结果的回调类,后面讲预览流程时会详细分析。
1 | // Camera2ClientBase.cpp |
Camera2ClientBase::initialize
也是一个模板函数,最终会调用 Camera3Device
的初始化:
1 | // Camera3Device.cpp |
Camera3Device::initialize
初始化中,重点实现的功能为打开物理设备,并获取 ICameraDeviceSession
用于后续直接和 HAL
通信,并通过它从 HAL
获取请求队列和结果队列;最后新建 HalInterface
实例,并将 ICameraDeviceSession
保存并绑定。
1 | // CameraProviderManager.cpp |
CameraProviderManager::openSession
打开设备时,会向 HAL
打开设备,将 ICameraDeviceCallback
传入 HAL
并获取 ICameraDeviceSession
实例。接着看 Camera3Device::initializeCommonLocked
:
1 | // Camera3Device.cpp |
在 initializeCommonLocked
中新建了很多实例:
StatusTracker
:状态跟踪线程Camera3BufferManager
:输出流的图形缓冲区管理,比如Camera3OutputStream
的管理TagMonitor
:相机元数据metadata
的监视器,比如3A
信息等RequestThread
:请求线程,比如拍照、录像、预览的数据请求PreparerThread
:监测数据已经准备好流的线程
小结
以上流程图都是基于 API 2 + HAL 3
,当 Camera Open
流程结束后:
- 客户端调用
API
时,得到了CameraDevice
的实例,并将ICameraDeviceUser
和CameraDeviceImpl
绑定 - 根据
HAL 1/3
生成了对应的Device
客户端,当前生成的是CameraDeviceClient
实例 Camera3Device
在初始化时,调用CameraProviderManager.openSession
,它会通过HIDL
通知HAL
层打开摄像头物理设备;打开成功会Camera3Device::HalInterface
和ICameraDeviceSession
实例绑定- 新建
RequestThread
对象,后台运行线程,用于监听API
发起的请求CaptureRequest
:预览、拍照、录像等 - 新建
FrameProcessorBase
对象,后台运行线程,用于监听HAL
返回的请求结果CaptureResult
打开设备时,实际上
Framework, HAL
已经创建好会话ICameraDeviceSession
;而下面分析的API
创建会话流程,实际是根据不同需求(预览、拍照、录像)来创建和配置输出流。
创建会话流程
API
在打开设备后,获取到了 CameraDevice
的实例,通过它来创建会话 Session
:
1 | // CameraDevice.java |
List<Surface> outputs
表示有多少个输出流,通常为预览流和拍照/录像,两个输出流。CameraCaptureSession.StateCallback callback
创建会话状态回调。Handler handler
回调方法使用哪个线程响应,如果为null
表示当前线程。
API
创建会话过程源码分析:
1 | // CameraDeviceImpl.java |
- 将
List<Surface>
转换为List<OutputConfiguration>
createCaptureSession
创建会话时,输入Surface, InputConfiguration
都为空,即只有输出流- 根据
isConstrainedHighSpeed
来创建CameraCaptureSession
实例;如果支持高速模式,则创建CameraConstrainedHighSpeedCaptureSessionImpl
实例;否则创建普通CameraCaptureSessionImpl
实例
示例
创建预览 mTextureSurface
和拍照 ImageReader.getSurface
两个输出流的会话,使用当前线程处理回调接口:
1 | mCameraDevice.createCaptureSession( |
CameraCaptureSession.StateCallback
回调
CameraCaptureSession.StateCallback
回调用来处理 createCaptureSession
创建会话过程中出现的各种状态,比如创建成功、失败等,这些回调处理直接在 API Java
层实现的;回调接口中会获取到 CameraCaptureSession
实例。
1 | public static abstract class StateCallback { |
createCaptureSession
创建会话时,会创建 CameraCaptureSessionImpl
实例,而 CameraCaptureSession.StateCallback
接口的回调都是在 CameraCaptureSessionImpl
中实现的:
1 | // CameraCaptureSessionImpl.java |
用户指定的 StateCallback
传入后,在方法 createUserStateCallbackProxy
中,通过 CallbackProxies
重新生成一个代理 mStateCallback
对象,通过反射的方式,完成所有回调响应过程。
- 如果
configureStreamsChecked
创建Stream
成功,则响应回调mStateCallback.onConfigured
- 如果失败则响应
mStateCallback.onConfigureFailed
,其他场景会产生剩余的回调
动态代理类 CallbackProxies
源码注释(JDK
中的动态代理只支持接口 interface
,对于抽象类只能自己实现了):
1 | /** |
流程图
源码分析
API
中创建捕获会话 createCaptureSession
时,CameraDeviceImpl.configureStreamsChecked
源码中可以看到;CameraDeviceImpl
是通过 ICameraDeviceUser
来向 Framework, HAL
层发送配置信息的:
1 | // CameraDeviceImpl.java |
configureStreamsChecked
配置流有三个主要过程:beginConfigure, createStream, endConfigure
,都是通过 ICameraDeviceUser
向下发送信息。 native
代码中由 CameraDeviceClient.cpp
实现了 ICameraDeviceUser
中的所有功能,这里重点分析 createStream
函数:
1 | // CameraDeviceClient.cpp |
CameraDeviceClient.createStream
中,将 API
传入的 OutputConfiguration
数据,转换成 native Surface, OutputStreamInfo
;根据 OutputConfiguration
中 IGraphicBufferProducer
的个数创建对应的 native Surface
,并最终通过设备来创建流。
1 | binder::Status CameraDeviceClient::createSurfaceFromGbp( |
这里的 NATIVE_WINDOW_FORMAT
格式代表着不同流的类型,在 system\core\libsystem\include\system\graphics-base.h
文件中定义:
1 | typedef enum { |
HAL_PIXEL_FORMAT_BLOB
拍照流
值为 33 ,通常对应mImageReader.getSurface()
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
预览和录像流
值为 34 ,通常对应预览new Surface(mTextureView.getSurfaceTexture())
和录像mMediaRecorder.getSurface
。
CameraDeviceClient::createStream
最终会调用 Camera3Device::createStream
,它会根据 NATIVE_WINDOW_FORMAT
格式创建不同配置的流:
1 | // Camera3Device.cpp |
注意:每配置一个输出 Surface
,都会创建对应的输出流 Camera3OutputStream
,这是一个 for
循环过程。
在 API
调用过程中,CameraDeviceImpl.configureStreamsChecked
的第三步为 endConfigure
,而 CameraDeviceClient::endConfigure
代码流程如下:
1 | // CameraDeviceClient.cpp |
它的主要作用就是通过 Camera3Device
来配置流,configureStreamsLocked
配置流主要有三个过程:startConfiguration, configureStreams, endConfigure
:
1 | // Camera3Device.cpp |
最终通过 Camera3Device::HalInterface::configureStreams
向 HAL
层发起配置信息:
1 | // Camera3Device.cpp |
这里需要注意的是 HAL 3.3, 3.2
的配置是有区别的;执行完配置后,Camera3Stream::finishConfiguration
结束配置:
1 | // Camera3Stream.cpp |
这里 mConsumer
是 native Surface
,也就是将生产者-消费者模型连接起来;同时 configureConsumerQueueLocked
有非常多的 native window
配置。
小结
创建会话 createCaptureSession
过程中,小结如下:
API
调用时,最终通过CameraCaptureSession.StateCallback
获取到CameraCaptureSessionImpl
实例ICameraDeviceUser.createStream
由输入的Surface
信息,根据不同的format
创建对应输出流Camera3OutputStream
ICameraDeviceUser.endConfigure
最终通过CameraDeviceSession.configureStream_3_3
会向HAL
层发送配置信息
相机预览过程中,如果 session
创建成功,会出现正常的预览界面;如果 session
创建失败,则预览会出现黑屏。
预览/拍照/录像流程
API
创建会话 createCaptureSession
成功后,通过拿到的 CameraCaptureSession
来预览、拍照、录像:
1 | // CameraCaptureSession.java |
CaptureRequest request
捕获请求,比如创建一个预览模板的请求CameraDevice.TEMPLATE_PREVIEW
;拍照模板的请求CameraDevice.TEMPLATE_STILL_CAPTURE
;录像模板的请求CameraDevice.TEMPLATE_RECORD
。CameraCaptureSession.CaptureCallback listener
捕获状态的回调接口。Handler handler
回调接口使用哪个线程响应,如果是null
表示当前线程。
CameraDevice
请求模板是一组常量:
1 | // CameraDevice.java |
各模板对应的含义:
TEMPLATE_PREVIEW
创建适合相机预览的窗口,高帧率优于高质量的后期处理。TEMPLATE_STILL_CAPTURE
创建适合拍照的请求,优先考虑帧速率的图像质量。TEMPLATE_RECORD
创建适合录像的请求,使用稳定的帧率。TEMPLATE_VIDEO_SNAPSHOT
创建录像时快照的请求,在不中断录像的前提下最大化图像质量。TEMPLATE_ZERO_SHUTTER_LAG
创建ZSL
零延时拍照请求,也就是连拍功能,在不影响帧率的前提下最大化图像质量,并开启3A
算法。TEMPLATE_MANUAL
手动控制模板,禁用所有的自动控制3A
算法。
示例
给 mTextureSurface
创建预览请求 TEMPLATE_PREVIEW
,使用后台线程处理回调接口:
1 | CaptureRequest.Builder previewRequestBuilder = |
给 ImageReader
创建拍照请求 TEMPLATE_STILL_CAPTURE
,使用后台线程处理回调:
1 | CaptureRequest.Builder captureRequestBuild = mCameraDevice |
给 MediaRecorder
创建录像请求 TEMPLATE_RECORD
,不处理回调:
1 | CaptureRequest.Builder recordCaptureBuild = mCameraDevice |
CameraCaptureSession.CaptureCallback
回调
CameraCaptureSession
在请求预览、拍照、录像等功能时,出现的各种状态通过 CameraCaptureSession.CaptureCallback
回调来处理,回调是由 HAL
层发起向上传递的;回调接口中通常包含当前会话信息 CameraCaptureSession
,捕获请求 CaptureRequest
,捕获的结果 CaptureResult
等。
1 | // CameraCaptureSession.java |
API
在发起请求 CameraCaptureSession.setRepeatingRequest/capture
时,用户会创建 CaptureCallback
的实例,这些接口都在 CameraDeviceImpl
中实现回调。
onCaptureStarted
该回调接口从HAL
回调路径为:CameraDeviceClient::notifyShutter -> CameraDeviceImpl.onCaptureStarted -> onCaptureStarted
。onCapturePartial
该回调接口搜索整个framework
,发现没有任何地方会回调它。onCaptureProgressed, onCaptureCompleted, onCaptureSequenceCompleted
三个接口都是在CameraDeviceImpl.onResultReceived
中回调的。onCaptureSequenceAborted
CameraDeviceClient.cpp
中的submitCaptureRequest, stopRepeating, flush
这三个函数会回调该接口。onCaptureFailed, onCaptureBufferLost
从HAL
回调路径为CameraDeviceClient::notifyError -> CameraDeviceImpl.onDeviceError
,而这两个接口在CameraDeviceImpl
中的回调路径为onDeviceError -> onCaptureErrorLocked -> onCaptureFailed/onCaptureBufferLost
。
流程图
预览/拍照/录像流程基本一致,这里仅给出预览的流程图:预览流程,查看原图
源码分析
在分析预览、拍照、录像流程前,先回顾下打开设备 openCamera
时,做的一些初始化:
1 | // CameraDeviceClient.cpp |
在 CameraDeviceClient::initializeImpl
中,调用了 Camera2ClientBase::initialize
的初始化,以及实例化一个 FrameProcessorBase
对象;
1 | // Camera2ClientBase.cpp |
这里 Camera2ClientBase::initializeImpl
中主要是调用了 Camera3Device::initialize
函数,下面只关心和捕获请求有关的代码:
1 | // Camera3Device.cpp |
在 Camera3Device::initializeCommonLocked
中实例化了 RequestThread
对象。至此,捕获流程中的发起请求的对象 RequestThread
和响应回调的对象 FrameProcessorBase
都实例化完毕,并开始运行。他们两个都继承的是线程,参看 system
目录下的 Thread.h/Threads.cpp
源码,可以看到 threadLoop
是在一个 while
中被循环调用的。当 threadLoop
返回 true
时就会不停的循环;返回 false
时会退出循环:
1 | // Threads.cpp |
先来看发送捕获请求的线程 RequestThread
:
1 | // Camera3Device.h |
这里只关注 RequestThread
类中几个关键函数和变量,NextRequest
结构体包含了请求信息,逐个向 HAL
发送这些信息;类中定义了多个条件变量,重点关注 mRequestSignal
条件变量, threadLoop
运行时,会通过 mRequestSignal.waitRelative
阻塞等待 50 ms;直到等到捕获请求后 mRequestSignal.signal
发出通知,threadLoop
继续运行。
1 | // Camera3Device.cpp |
RequestThread
在没有捕获请求时,会循环调用 threadLoop
,并阻塞等待 mRequestSignal
的通知。再看响应回调的线程 FrameProcessorBase
:
1 | // FrameProcessorBase.h |
FrameProcessorBase::threadLoop
代码非常简单,device->waitForNextFrame
阻塞等待 10ms ,这里 CameraDeviceBase
实际类型为 Camera3Device
:
1 | // Camera3Device.h |
Camera3Device::waitForNextFrame
代码也很简单,调用条件变量 mResultSignal.waitRelative
实现阻塞等待 10 ms。
至此初始化过程中,捕获请求线程 RequestThread
循环执行 threadLoop
,并会阻塞等待 mRequestSignal
的通知;回调响应线程 FrameProcessorBase
循环执行 threadLoop
,并会阻塞等待 mResultSignal
的通知。
当用户调用 API
创建捕获请求时,mRequestSignal
会发出通知;因为预览、拍照、录像流程基本一样,一起分析:
1 | // CameraCaptureSessionImpl.java |
createCaptureCallbackProxy
创建了一个回调动态代理,通过 CameraDeviceImpl.setRepeatingRequest/capture
下发预览或者拍照的捕获请求:
1 | // CameraDeviceImpl.java |
从代码流程来看,预览和录像使用同一个接口;预览和拍照的主要区别是 repeating
的值;当为 true
时,表示预览/录像;当为 false
时,表示为拍照。通过 ICameraDeviceUser.submitRequestList
向下发送请求:
1 | // CameraDeviceClient.cpp |
如果是预览/录像,则调用 Camera3Device->setStreamingRequestList
;如果是拍照,则调用 Camera3Device->captureList
:
1 | //Camera3Device.cpp |
同样,预览/录像和拍照请求在 Camera3Device
中的区别也主要是 repeating
的值,都会调用 Camera3Device::submitRequestsHelper
,并通过 RequestThread
发起捕获请求;当预览/录像时,调用 setRepeatingRequests
;当拍照时,调用 queueRequestList
:
1 | // Camera3Device.cpp |
预览/录像时会将捕获请求存入 mRepeatingRequests
列表中;拍照时会将捕获请求存入 mRequestQueue
列表中;它们最终都会调用 unpauseForNewRequests
,而该函数的核心功能就是通过 mRequestSignal.signal
发出消息,通知在开启设备初始化过程中 waitForNextRequestLocked
的阻塞等待。我们重新进入 RequestThread::threadLoop
中,继续向下分析:
1 | // Camera3Device.cpp |
当 waitForNextRequestBatch
拿到请求通知后,会将捕获请求存入 mNextRequests
中,当前平台支持批量请求处理,sendRequestsBatch -> processBatchCaptureRequests
流程,向 HAL
层发送捕获请求 mHidlSession->processCaptureRequest
,至此捕获请求从 API
发送到 HAL
整个流程全部分析完毕。
当 HAL
拿到捕获的结果后,会从 ICameraDeviceSession.processCaptureResult
回调到 Framework
层:
1 | // Camera3Device.cpp |
从代码流程来看,从 HAL
传过来的捕获结果,不管是发回部分结果 sendPartialCaptureResult
还是最终结果 sendCaptureResult
,最终都会调用 insertResultLocked
,它的主要功能就是将捕获结果放入 mResultQueue
队列,并由 mResultSignal.signal
发出消息,通知在开启设备初始化过程中 waitForNextFrame
的阻塞等待。一旦 FrameProcessorBase::threadLoop
获取到捕获结果后,逐个处理:
1 | // FrameProcessorBase.cpp |
代理流程可以看出,逐个取出 CaptureResult
并处理,最终调用 CameraDeviceClient::onResultAvailable
向 API
发送捕获结果:
1 | // CameraDeviceClient.cpp |
而 API
中的回调是在 CameraDeviceImpl.java
中实现的:
1 | // CameraDeviceImpl.java |
在 CameraDeviceImpl
中处理 CameraCaptureSession.CaptureCallback
各回调结果:如果返回的是部分结果,则回调 onCaptureProgressed
;如果返回最终结果,则回调 onCaptureCompleted
。整个预览、拍照、录像流程及回调分析完毕。
小结
Camera3Device::RequestThread
这个类主要是处理预览、拍照、录像的请求CaptureRequest
。FrameProcessorBase.cpp
这个类主要是处理请求后的回调函数,回调中会包含捕获的结果CaptureResult
。Condition
不管是请求还是结果回调,因为是多线程处理,都涉及到条件变量的阻塞等待和通知机制。CameraDeviceSession.CaptureCallback
该回调接口都是在CameraDeviceImpl
中实现的。
三者异同
预览、拍照、录像三者的流程基本一致,它们之间有如下异同:
- 预览
捕获请求模板为CameraDevice.TEMPLATE_PREVIEW
;API
接口为CameraCaptureSession.setRepeatingRequest
;repeating
值为true
。 - 拍照
捕获请求模板为CameraDevice.TEMPLATE_STILL_CAPTURE
;API
接口为CameraCaptureSession.Capture
;repeating
值为false
。 - 录像
捕获请求模板为CameraDevice.TEMPLATE_RECORD
;API
接口为CameraCaptureSession.setRepeatingRequest
;repeating
值为true
。
也就是说,预览和录像仅仅是捕获请求模板不一样;而预览和拍照不管是模板,接口,repeating
值都不一样;但是它们三者最终在 Framework
中代码流程基本一致。
CameraServiceProxy
注册服务
AIDL
1 | interface ICameraServiceProxy |
从 AIDL
文件看出,CameraServiceProxy
主要是响应 CameraService
的请求,也就是向 Framework Java
发送消息。
流程图
CameraServiceProxy
服务名称:media.camera.proxy
;CameraServiceProxy
继承了 SystemService
,注册流程如下:
源码分析
先来看注册流程的源码,服务的标准注册流程:
1 | // CameraServiceProxy.java |
类中的 User
指的是 Android
多用户;再看回调接口的实现:
1 | // CameraServiceProxy.java |
小结
通常情况下 API
中,CameraManager
通过 ICameraService.aidl
向 CameraService
下发请求;而 CameraService
通过 ICameraServiceListener.aidl
发回回调。
而如果没有 API
请求的情况下,CameraService
无法向 Framework Java
发送信息,所以系统开机时注册了 CameraServiceProxy
服务,用于响应 CameraService
的回调。
其他
Camera
相关声音
1 | void CameraService::loadSound() { |
CameraMetadata
CameraMetadataNative
和 CameraMetadata
是同一个类型,只是命名空间不一样。
1 | namespace android { |
常见问题
API 2 + HAL 1
平台仅支持 HAL 1
时,API 2
在 openCamera
时,通过 CameraDeviceUserShim
将 API 2
转换为 API 1
,即 HAL 1 + API 1
向下发起请求。LegacyCameraDevice
会将 CAMERA API2
转换为 CAMERA API1
,而 CameraDeviceUserShim
封装了 LegacyCameraDevice
。
AIDL
生成多类型文件
AIDL
可以同时生成 .java, .h, .cpp
文件,编译规则在 Android.bp
中配置。
总结
后续
- 数据传递
Binder
通信机制,数据传输限制在 1M ,那整个通信机制是如何传递图片的呢?以及预览的呢?传递的是什么?createCaptureSession
创建捕获会话时,配置输出流;当setRepeatingRequest
发起预览请求时,回调结果为CaptureResult
,它是如何和输出流关联的呢? SurfaceFlinger
显示相关知识Buffer
相关管理
这些都是API 1
模式下的数据流,不过有参考意义。