三 Android Camer2 Pipeline总结... 5
3.1 Pipeline架构... 5
3.2 关键组件... 6
四 Android Camer2 相机开发流程总结... 8
4.1 开发流程综述... 8
4.2 Camera2消息流转... 8
4.3 开关相机流程及API调用... 9
4.4 SurfaceView与TextView.. 11
五 BasicCaptureDemo设计优化... 13
5.1 优化目标... 13
5.2 优化效果展示... 13
5.3 界面布局调整... 18
5.4 APP主入口... 19
5.5 主流程设计... 19
5.5 AutoFitTextureView设计... 20
5.6 Camera2BasicFragment设计... 20
六 Android LogCat采集日志... 22
6.1 Log API及等级... 22
6.2 LogCat打开方式... 22
6.3 LogCat使用... 23
6.4 LogCat常用命令汇总... 24
七 Android HAL总结... 25
7.1 HAL结构... 25
7.2 HAL Android引入HAL. 25
八 Android Camera架构总结... 27
8.1 概述... 27
8.2 层次解析... 27
8.3 Android Camera Request概念解析... 28
8.4 Android Camera Request流程... 28
8.5 request在HAL的处理方式... 29
三 Android Camer2 Pipeline总结
3.1 Pipeline架构
从 Android 5.0 开始,Google 引入了一套全新的相机框架 Camera2(android.hardware.camera2)并且废弃了旧的相机框架 Camera1(android.hardware.Camera), Camera2 的出现给相机应用程序带来了巨大的变革,因为它的目的是为了给应用层提供更多的相机控制权限,从而构建出更高质量的相机应用程序。Android设备和Camera设备是通过管道pipeline的概念将两者进行串联的,pipeline即一套camera处理流程,可抽象为一个CaptureRequestSession,在一个CaptureRequestSession过程中由Android系统发送CaptureRequest,Camera返回元数据MetaData进行来回交互,预览和拍照等数据的传递是通过Surface进行,其架构如下所示:
正在上传…重新上传取消
处理流程总结如下:
- 应用程序构建一个包含capture具体属性集的请求CaptureRequest,并将用于保存拍照结果数据的内存区域Surface加入到CaptureRequest中;
- CaptureRequest会在capture会话CameraCaptureSession中被加入拍照设备CameraDevice的请求队列Pending Request Queue中,等待Camera处理;
- In-Flight Capture Queue是Camera的工作队列,当此队列空闲时,Android系统就会将拍照请求加入其中,等待capture执行;
- capture完成后,其处理结果会以回调函数形式在CameraCaptureSession通知到应用程序处理,拍照数据会根据配置输出到Surface或ImageReader。
3.2 关键组件
- Capture
相机的所有操作和参数配置最终都是服务于图像捕获,因此Camera2 中相机所有操作和参数配置都被抽象成Capture(捕获),其更像是一个相机类,可配置参数,完成拍照,调节曝光补偿,对焦等行为。Capture 从执行方式上可总结如下模式:
模式 | 英文术语 | 含义描述 |
单次模式 | One-shot | 只执行一次的 Capture 操作,例如设置闪光灯模式、对焦模式和拍一张照片等,多个一次性模式的 Capture 会进入队列按顺序执行。 |
多次模式 | Burst | 连续多次执行指定的 Capture 操作,在此模式执行期间不允许插入其他任何 Capture 操作,例如连续拍摄 100 张照片,在拍摄这 100 张照片期间任何新的 Capture 请求都会排队等待,直到拍完 100 张照片。多组多次模式的 Capture 会进入队列按顺序执行。 |
重复模式 | Repeating | 不断重复执行指定的 Capture 操作,但当有其他模式的 Capture 提交时会暂停该模式,转而执行其他被模式的 Capture,当其他模式的 Capture 执行完毕后又会自动恢复继续执行该模式的 Capture。 |
- CameraManager
CameraManager是一个用于检测、连接和描述相机设备的系统服务,负责管理所有的CameraDevice相机设备。可以通过调用Context.getSystemService(java.lang.String)方法来获取一个CameraManager的实例,其关键功能:
- 将相机信息封装到 CameraCharacteristics 中,并提获取 CameraCharacteristics 实例的方式;
- 根据指定的相机 ID 连接相机设备;
- 提供将闪光灯设置成手电筒模式的快捷方式。
- CameraCharacteristics
CameraCharacteristics 是描述相机设备的属性类,包含大量的相机信息,其继承了CameraMetadata 类。CameraCharacteristic常用属性包括如下所示:
属性 | 英文术语 |
曝光补偿 | Exposure compensation |
自动曝光/自动对焦/自动白平衡模式 | AE / AF / AWB mode |
自动曝光/自动白平衡锁 | AE / AWB lock |
自动对焦触发器 | AF trigger |
拍摄前自动曝光触发器 | Precapture AE trigger |
测量区域 | Metering regions |
闪光灯触发器 | Flash trigger |
曝光时间 | Exposure time |
感光度 | ISO Sensitivity |
帧间隔 | Frame duration |
镜头对焦距离 | Lens focus distance |
色彩校正矩阵 | Color correction matrix |
JPEG 元数据 | JPEG metadata |
色调映射曲线 | Tonemap curve |
裁剪区域 | Crop region |
目标 FPS 范围 | Target FPS range |
拍摄意图 | Capture intent |
硬件视频防抖 | Video stabilization |
- CameraDevice
CameraDevice 代表当前连接的相机设备,相当于pipeline的终端,它的职责有以下四个:
- 根据指定的参数创建CameraCaptureSession;
- 根据指定的模板创建CaptureRequest;
- 关闭相机设备;
- 监听相机设备的状态,例如断开连接、开启成功和开启失败等。
CameraDevice 的功能则十分的单一,就是只负责建立相机连接的事务,而更加细化的相机操作则交给CameraCaptureSession。
- CameraCaptureSession
CameraCaptureSession 实际上就是配置了目标 Surface 的 Pipeline 实例,一个 CameraDevice 一次只能开启一个 CameraCaptureSession,绝大部分的相机操作都是通过向 CameraCaptureSession 提交一个 Capture 请求实现的,例如拍照、连拍、设置闪光灯模式、触摸对焦、显示预览画面等。
- Surface
Surface 是一块用于填充图像数据的内存空间,例如APP可以使用 SurfaceView 的 Surface 接收每一帧预览数据用于显示预览画面,也可以使用 ImageReader 的 Surface 接收 JPEG 或 YUV 数据。每一个 Surface 都可以有自己的尺寸和数据格式,应用程序从 CameraCharacteristics 获取某一个数据格式支持的尺寸列表。
- CaptureRequest
CaptureRequest 是向 CameraCaptureSession 提交 Capture 请求时的信息载体,其内部包括了本次 Capture 的参数配置和接收图像数据的 Surface。CaptureRequest 可以配置的信息非常多,包括图像格式、图像分辨率、传感器控制、闪光灯控制、3A 控制等等,可以说绝大部分的相机参数都是通过 CaptureRequest 配置的。
注意:每一个 CaptureRequest 表示一帧画面的操作,这表示可以精确控制每一帧的 Capture 操作。
- CaptureResult
CaptureResult 是每一次 Capture 操作的结果,里面包括了很多状态信息,包括闪光灯状态、对焦状态、时间戳等等。例如应用程序可以在拍照完成的时候,通过 CaptureResult 获取本次拍照时的对焦状态和时间戳信息等。
注意: CaptureResult 并不包含任何图像数据。
四 Android Camer2 相机开发流程总结
4.1 开发流程综述
1.检测并访问相机资源:检查手机是否存在相机资源,如果存在则请求访问相机资源。
2.创建预览界面:创建继承自SurfaceView并实现SurfaceHolder接口的拍摄预览类。有了拍摄预览类,即可创建一个布局文件,将预览画面与设计好的用户界面控件融合在一起,实时显示相机的预览图像。
3.设置拍照监听器:给用户界面控件绑定监听器,使其能响应用户操作, 开始拍照过程。
4.拍照并保存文件:将拍摄获得的图像转换成位图文件,最终输出保存成各种常用格式的图片。
5.释放相机资源:相机是一个共享资源,当相机使用完毕后,必须正确地将其释放,以免其它程序访问使用时发生冲突。
4.2 Camera2消息流转
正在上传…重新上传取消
- 由SystemService创建CameraManager;
- 整个camera2由CameraManager来进行统一管理;
- CameraManager通过CameraDevice、CameraCharacteristic和CameraCaptureSession对Camera进行操作;
- CameraDevice和CameraCaptureSession都有回调函数完成相关操作,包括相机打开,capture过程处理,capture完成处理等。
- Android设备发送CameraCaptureRequest给Camera,而Camera处理完后发送元数据CameraMetaData给Android设备。
4.3 开关相机流程及API调用
1. 创建相机项目
使用Android Studio创建Blank Activity的android项目
2. 注册相关权限
使用相API 之前,必须在 AndroidManifest.xml 注册相机权限 android.permission.CAMERA,此外如果APP有保存照片的需求,则读写 SD 卡的权限也是必要的,常用权限如下所示:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Android6.0 以上的系统需要APP在运行的时候进行动态权限申请,因此可设计checkPermissions在相机打开时检查相关权限:
List<String> requiredPermissions = Arrays.asList(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE);
private void checkPermissions() {
List<String> unGrantedPermissions = new ArrayList<>();
for (String permission : requiredPermissions) {
if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(permission)) {
unGrantedPermissions.add(permission);
}
}
if (unGrantedPermissions.size() != 0) {
requestPermissions(unGrantedPermissions.toArray(new String[unGrantedPermissions.size()]), 0);
}
- 获取 CameraManager 实例
CameraManager是一个负责查询和建立相机连接的系统服务,可以说 CameraManager是Camera2使用流程的起点,所以APP要通过 getSystemService() 获取 CameraManager 实例,如下所示:
CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
- 获取相机 ID 列表
使用的API 是CameraManager.getCameraIdList(),它会返回一个包含所有可用相机ID的字符串数组,如下所示:
try {
String[] cameraLis= cameraManager.getCameraIdList();
} catch (CameraAccessException e) {
e.printStackTrace();
}
- 根据相机 ID 获取 CameraCharacteristics
CameraCharacteristics 是相机属性的信息库,通过它APP可以获取所有相机信息,涉及的 API 是CameraManager.getCameraCharacteristics(),它会根据你指定的相机 ID 返回对应的相机信息,如下所示:
String[] cameraIdList;
try {
cameraIdList= cameraManager.getCameraIdList();
CameraCharacteristics characteristics;
for (String cameraId :cameraIdList) {
characteristics = cameraManager.getCameraCharacteristics(cameraId);
int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
int level = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
Log.e(TAG, "facing = " + facing + ", level = " + level);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
- 开启相机
开启相机调用CameraManager.openCamera(),该方法要求我们传递两个参数,相机 ID和监听相机状态的回调函数 CameraStateCallback。当相机被成功开启的时候会通过回调函数CameraStateCallback.onOpened() 方法回调一个 CameraDevice 实例,否则的话会通过 CameraStateCallback.onError() 方法回调一个 CameraDevice 实例和一个错误码,其API用例如下所示:
private String getBackCameraId(CameraManager cameraManager) {
try {
String[] cameraIdList = cameraManager.getCameraIdList();
CameraCharacteristics characteristics;
for (String cameraId : cameraIdList) {
characteristics = cameraManager.getCameraCharacteristics(cameraId);
int facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (CameraCharacteristics.LENS_FACING_BACK == facing) {
return cameraId;
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
return null;
}
private void openCamera(CameraManager cameraManager, String cameraId) {
if (checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
try {
cameraManager.openCamera(cameraId, callback, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private CameraDevice.StateCallback callback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
Toast.makeText(MainActivity.this, "相机已开启", Toast.LENGTH_LONG).show();
}
@Override
public void onDisconnected(@NonNull CameraDevice camera) {
}
@Override
public void onError(@NonNull CameraDevice camera, int error) {
camera.close();
}
};
- 关闭相机
关闭相机至关重要,其API是CameraDevice.close(),当相机被完全关闭的时候会通过 CameraStateCallback.onCllosed() 方法通知APP已经被关闭。关闭相机除了上述onError外还应该在 onPause() 的时候关闭相机,因为此时Activity已经不是用户关注的焦点,通常需要关闭相机,其API调用如下:
@Override
protected void onPause() {
super.onPause();
if (cameraDevice != null) {
cameraDevice.close();
}
}
4.4 SurfaceView与TextView
1.区别
(1)SurfaceView是一个有自己Surface的View。界面渲染可以放在单独线程而不是主线程中。它更像是一个Window,自身不能做变形和动画。
(2)TextureView同样也有自己的Surface。但是它只能在拥有硬件加速层的Window中绘制,它更像是一个普通View,可以做变形和动画。
2.应用场景
正在上传…重新上传取消
五 BasicCaptureDemo设计优化
5.1 优化目标
1.UI界面优化,包括定制APP图片,拍照显示界面等;
2.实现连续多张照片拍摄,之前demo出现拍照连续拍照崩溃现象;
3.合理适配预览比例,为了避免照片失真(照片被拉长或者压扁),需要保证预览的长宽比例、照片的长宽比例和相机输出格式的长宽比例三者保持一致,之前demo没有做该功能;
4.矫正图像数据方向,Android设备的屏幕方向,与摄像头的原始方向并不一致,需要做方向转换。一般而言,当Android设备横着放时,与摄像头的方向是一致的,之前demo没有做该功能;
5.代码结构优化与调整,参考google camera2程序对原代码结构做调整与优化。
5.2 优化效果展示
1.APP UI
正在上传…重新上传取消
2.拍照界面
正在上传…重新上传取消
3.拍照效果
(1)竖屏拍照
正在上传…重新上传取消
(2)横屏拍照
正在上传…重新上传取消
(3)拍照结果存盘
正在上传…重新上传取消
5.3 界面布局调整
1.activity_main.xml使用FrameLayout;
2. FrameLayout内嵌RelativeLayout;
3. RelativeLayout内嵌AutoFitTextureView和FrameLayout,AutoFitTextureView用于相机预览数据;
4. FrameLayout内嵌Button和ImageButton,Button用于拍照按钮,ImageButton是提升按钮。
效果如下所示:
正在上传…重新上传取消
5.4 APP主入口
MainActivity在onCreate方法中装载UI框架
正在上传…重新上传取消
5.5 主流程设计
MainActivity在onCreate方法中装载UI框
正在上传…重新上传取消
整个代码流程用一个activity承载一个fragment,所有的代码都写在fragment里面,重写了fragment的生命周期函数:
1.onCreateView:加载fragment的布局文件;
2.onViewCreated:实例化布局控件;
3.onActivityCreated:在SD卡的目录下建立jpg文件等待待将拍到的照片写进去;
4.onResume:开始照相机线程,执行一些逻辑判断;
5.onPause:关闭照相机,停止照相机线程。
5.5 AutoFitTextureView设计
public class AutoFitTextureView extends TextureView {
// 设置预览的宽度和高度
// width:预览宽度
// height:预览高度
public void setAspectRatio(int width, int height);
// 根据预览尺寸调节TextView的尺寸
// 预览尺寸的高宽比和TextView的高宽比一致
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);
}
AutoFitTextureView是保存预览数据,核心方法是onMeasure,即它可根据预览尺寸动态调整TextView的尺寸,使得预览尺寸高/宽比与TextView尺寸高/宽比一致。
5.6 Camera2BasicFragment设计
Camera2BasicFragment利用camer2 pipeline将capture过程组合在一起,使用mState
public class Camera2BasicFragment extends Fragment implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
…
}
1.主流程:
(1)由于camera是共享资源,使用信号量作为锁机制,对多个activity的onPause事件进行加锁处理;
(2)使用全局状态state表示capture状态,根据CaptureResult状态进行相应的动作,包括拍照,预拍照;
2.关键属性和方法
(1)TextureView.SurfaceTextureListener mSurfaceTextureListener
TextView回调函数,当TextView可用时,打开Camera,当预览尺寸发生变化,重新调整TextView尺寸
(2)CameraDevice.StateCallback mStateCallback
当CameraDevice打开时,该回调函数中可获取相机及相机状态。在onOpen方法中获取相机和创建预览会话,在onError中关闭相机,如下所示:
正在上传…重新上传取消
(3)ImageReader.OnImageAvailableListener mOnImageAvailableListener
ImageReader回调函数,当ImageReader获取相机拍照数据,即在onImageAvailable方法中,让后台线程保存图片数据,如下所示:
正在上传…重新上传取消
(4)CameraCaptureSession.CaptureCallback mCaptureCallback
CameraCaptureSession回调函数,提供onCaptureProgressed用于capture处理和onCaptureCompleted用于capture善后处理,如下所示:
正在上传…重新上传取消
prorcess类似状态机处理,它根据capture状态mState进行状态切换
附源码:
正在上传…重新上传取消
六 Android LogCat采集日志
6.1 Log API及等级
Android Log定义在android.util.Log,常用的方法及等级如下:
1.Log.v:v代表Verbose日志的详细信息,对应的log等级为VERVOSE。采用该等级的log,任何消息都会输出;
2.Log.d:这里的d表示调试,对应的log等级为DEBUG。采用该等级的log,除了VERBOSE级别的log外,其余4个等级的log都会被输出。
3.Log.i:i代表information,为信息日志,对应的log等级为INFO。采用该等级的log,不会输出VERBOSE和DEBUG信息,只会输出其余3个等级的信息。
4.Log.w:w代表warning警告信息,一般用于系统提示开发者需要优化android代码等场景,对应的等级为WARN。该级别log,只会输出WARN和ERROR的信息。
5.Log.e:e代表error错误信息,一般用于输出异常和报错信息。该级别的log,只会输出该级别信息。一般Android系统在输出crash等致命信息的时候,都会采用该级别的log。
6.2 LogCat打开方式
1.方法一:使用Android Studio的LogCat
正在上传…重新上传取消
2.方法二:使用cmd命令行
正在上传…重新上传取消
3.方法三:使用android studio的Terminal
正在上传…重新上传取消
6.3 LogCat使用
1.代码
(1)导入包:
import android.util.Log;
(2)定义TAG
private static final String TAG = "Camera5BasicFragment";
(3)按级别打印日志
Log.e(TAG, "OPENCAMERA");
2.使用Logcat过滤日志
(1)方法1:使用android studio日志过滤功能
正在上传…重新上传取消
如图所示,新建过滤器,然后启动设备调试后可输出日志信息。
(2)方法2:在cmd或者android studio终端输入命令
logcat -v time *:E>d:\11.txt
以上命令将错误日志重定向到11.txt文件,打开文件可查看日志信息,如下所示:
正在上传…重新上传取消
6.4 LogCat常用命令汇总
1.格式1:打印默认日志数据
adb logcat
2.格式2:需要打印日志详细时间的简单数据
adb logcat -v time
3.格式3:需要打印级别为Error的信息
adb logcat *:E
4.格式4:需要打印时间和级别是Error的信息
adb logcat -v time *:E
5.格式5:将日志保存到固定的位置,比如D:\log.txt
adb logcat -v time >D:\log.txt
七 Android HAL总结
7.1 HAL结构
硬件抽象层HAL(HardWare Abstraction Layer)在 Linux和Windows有着不同的实现方式,Windows下的HAL位于操作系统的最底层,它直接操作物理硬件设备,使用抽象接口来隔离不同硬件的具体实现,为上层的操作系统和设备驱动程序提供一个统一接口,起到对硬件抽象作用。这样更换硬件时,编写硬件的驱动只要实现符合HAL定义的标准接口就可以顺利进行硬件更换,而对上层的应用没有影响。Linux下的HAL与Windows不同,HAL层并不位于操作系统的最底层直接操作硬件,而是在操作系统内核层和驱动程序之上,是一个运行在User Space(用户空间)的服务程序。
正在上传…重新上传取消
如上图所示,HAL位于操作系统和驱动程序之上,运行在用户空间中的服务程序。其目的是为上层的应用提供一个统一的查询硬件设备的接口。有了HAL接口,就可以将硬件开发和上层的应用开发分离开,上层的应用开发不必关系具体实现是什么硬件,同样地,如果硬件厂家需要改变硬件设备,只需要按照HAL接口的规范和标准提供对应的硬件驱动,而不必更改应用,HAL层并不提供对硬件的实际操作,对硬件的实际操作仍然由具体的驱动程序来完成。
7.2 HAL Android引入HAL
- 引入原因
Linux HAL能够屏蔽底层硬件差异,为应用层提供访问硬件统一接口,除此之外,Android引入HAL另一个重要的原因就是为了保障在Android 平台基于Linux开发的硬件驱动和应用程序不必遵循GPL(General Public License)许可而保持封闭,保证硬件厂家的利益。
- Android中HAL的运行机制
Android源码中已经实现了一部分的HAL,包括Wi-Fi、GPS、RIL、Sensor等。老式的HAL结构,采用直接调用so动态链接库方式,新式HAL结构,采用Stub代理方式调用,如下所示:
正在上传…重新上传取消
在老式的HAL结构中,应用通过so动态链接库调用而达到对硬件驱动的访问。在so动态链接库中,实现了对驱动的访问逻辑处理。新式HAL结构采用Stub的代理模式,Stub虽然仍是以*.so的形式存在,但是HAL已经将动态链接库的具体实现隐藏了起来。Stub向HAL提供operations方法,Runtime通过对Stub提供的so获取它的operations方法,并告知Runtime的callback方法。这样,Runtime和Stub都有对方调用的方法,一个应用的请求通过Runtime调用Stub的operations方法,而Stub响应operations方法并完成后,再调用Runtime的callback方法进行返回。
- 源码目录
(1)/hardware/libhardware_legacy/:旧的架构、采取链接库模块的方式;
(2)/hardware/libhardware:HAL stub;
(3)/hardware/ril:无线电抽象层
除此之外是硬件厂商相关的hal目录。
- 调用过程
(1)概述:android frameworks中JNI调用hardware.c中定义的hw_get_module函数来获取硬件模块,然后调用硬件模块中的方法,硬件模块中的方法直接调用内核接口完成相关功能。
(2)hw_get_module函数原型:
int hw_get_module(const char *id, const struct hw_module_t **module);
参数id为模块标识,定义在/hardware/libhardware/include/hardware录下的硬件模块头文件中
参数module是硬件模块地址,定义在/hardware/libhardware/include/hardware/hardware.h中
八 Android Camera架构总结
8.1 概述
正在上传…重新上传取消
Android Camera整体框架主要包括三个进程:app进程、camera server进程、hal进程(provider进程)。进程之间的通信都是通过IPC binder实现,其中app和camera server通信使用 AIDL(Android Interface Definition Language) ,camera server和hal(provider进程)通信使用HIDL(HAL interface definition language) 。
8.2 层次解析
1. Application framework
这一层是用于给APP提供访问hardware的Camera API2,通过IPC binder来访问camera service。有两个主要的类:
(1)CameraManager:一个独一无二地用于检测、连接和描述相机设备的系统服务,负责管理所有的CameraDevice相机设备。通过ICameraService调用到CameraService。
(2)CameraDevice:单个相机的抽象表示,通过ICameraDeviceUser调用到CameraDeviceClient。
2. Native framework:代码路径位于:frameworks/av/camera/。提供了ICameraService、ICameraDeviceUser、ICameraDeviceCallbacks、ICameraServiceListener等aidl接口的实现。
(1) ICameraService 是相机服务的接口。用于请求连接、添加监听等。
(2) ICameraDeviceUser 是已打开的特定相机设备的接口。应用框架可通过它访问具体设备。
(3) ICameraServiceListener 和 ICameraDeviceCallbacks 分别是从 CameraService 和 CameraDevice 到应用框架的回调。
3.HAL
Google的HAL定义了可以让Camera Service访问的标准接口。有关这些接口的具体实现则交由硬件厂商,代码路径:/hardware/interfaces/camera。
8.3 Android Camera Request概念解析
1. request特征
应用框架是通过向camera子系统发送request来获取其想要的result,其特征如下:
(1)一个request可以对应一系列的result;
(2)request应当包含所有必要的配置信息,存放于metadata中。如:分辨率和像素格式;sensor、镜头、闪光等的控制信息;3A 操作模式;RAW 到 YUV 处理控件;以及统计信息的生成等;
(3)request需要携带对应的surface(也就是框架里面的stream),用于接收返回的图像;
(4)多个request可以同时处于in-flight状态,并且submit request是non-blocking方式的。也就是说,上一个request没有处理完,也可以submit新的request。但队列中request的处理总是按照FIFO的形式;
(5)snapshot的request的preview的request拥有更高的优先级。
8.4 Android Camera Request流程
正在上传…重新上传取消
1.open 流程(黑色箭头线条)
(1)CameraManager注册AvailabilityCallback回调,用于接收相机设备的可用性状态变更的通知。
(2)CameraManager通过调用getCameraIdList()获取到当前可用的camera id,通过getCameraCharacteristcs()函数获取到指定相机设备的特性。
(3)CameraManager调用openCamera()打开指定相机设备,并返回一个CameraDevice对象,后续通过该CameraDevice对象操控具体的相机设备。
(4)使用CameraDevice对象的createCaptureSession()创建一个session,数据请求(预览、拍照等)都是通过session进行。在创建session时,需要提供Surface作为参数,用于接收返回的图像。
2.configure stream流程(蓝色箭头线条)
(1)申请Surface,如上图的OUTPUT STREAMS DESTINATIONS框,用于在创建session时作为参数,接收session返回的图像。
(2)创建session后,surface会被配置成框架的stream。在框架中,stream定义了图像的size及format。
(3)每个request都需要携带target surface用于指定返回的图像是归属到哪个被configure的stream的。
3.request处理流程(橙色箭头线条)
(1)CameraDevice对象通过createCaptureRequest()来创建request,每个reqeust都需要有surface和settings(settings就是metadata,request包含的所有配置信息都是放在metadata中的)。
(2)使用session的capture()、captureBurst()、setStreamingRequest()、setStreamingBurst()等api可以将request发送到框架。
(3)预览的request,通过setStreamingRequest()、setStreamingBurst()发送,仅调用一次。将request set到repeating request list里面。只要pending request queue里面没有request,就将repeating list里面的request copy到pending queue里面。
(4)拍照的request,通过capture()、captureBurst()发送,每次需要拍照都会调用。每次触发,都会直接将request入到pending request queue里面,所以拍照的request比预览的request的优先级更高。
(5)in-progress queue代表当前正在处理的request的queue,每处理完一个,都会从pending queue里面拿出来一个新的request放到这里。
4.数据返回流程(紫色箭头线条)
硬件层面返回的数据会放到result里面返回,会通过session的capture callback回调响应。
8.5 request在HAL的处理方式
1.流程总结
(1)framework发送异步的request到hal;
(2)hal必须顺序处理request,对于每一个request都要返回timestamp(shutter,也就是帧的生成时间)、metadata、image buffers;
(3)对于request引用的每一类steam,必须按FIFO的方式返回result。比如:对于预览的stream,result id 9必须要先于result id 10返回。但是拍照的stream,当前可以只返回到result id 7,因为拍照和预览用的stream不一样;
(4)hal需要的信息都通过request携带的metadata接收,hal需要返回的信息都通过result携带的metadata返回。
2.流程分析:
正在上传…重新上传取消
1.request处理流程(黑色箭头线条)
(1)framework异步地submit request到hal,hal依次处理,并返回result;
(2)每个被submit到hal的request都必须携带stream。stream分为input stream和output stream:input stream对应的buffer是已有图像数据的buffer,hal对这些buffer进行reprocess;output stream对应的buffer是empty buffer,hal将生成的图像数据填充的这些buffer里面。
2.input stream处理流程(图像的INPUT STREAM 1)
(1)request携带input stream及input buffer到hal;
(2)hal进行reprocess,然后新的图像数据重新填充到buffer里面,返回到framework。
3.output stream处理流程(图像的OUTPUT STREAM 1…N)
(1)request携带output stream及output buffer到hal;
(2)hal经过一系列模块的的处理,将图像数据写到buffer中,返回到frameowork。