camera2 简单总结

写在开头:本文为学习 camera2 过程中的知识点归纳总结。

1. camera2 相机体系结构

https://blog.csdn.net/u012596975/article/details/107136568

https://blog.csdn.net/u012596975/article/details/107138177
对于Camera Api v2的实现,是通过Camera Framework来完成的,而该层也有着一次不小的演变,刚开始Framework层并不是直接通过AIDL接口与Camera Service进行通信,而是通过一个JNI层来完成从Java到Native的转换,而Native部分作为客户端,保持对Service的通信。这种设计,很显然会比较臃肿,并且代码难以维护,所以之后由于AIDL接口的提出,谷歌直接将其加入到相机框架中,用于保持Framework与Service的通信,进而摈弃了JNI层,进一步减少了不必要的层级结构,保持了整个体系简洁性。

更多可参考 深入理解Android相机体系结构 系列。

2. camera1和camera2的使用简单对比

先回顾一下,camera1和camera2的简单使用。
这两篇camera1和camera2的预览demo,十分简洁,功能单一,可供对比。
Android Camera1最简单的预览框显示
Android Camera2最简单的预览框显示

下面这两张思维导图,较为详细得说明了camera的使用流程和API。这不是本篇的重点。


https://www.jianshu.com/p/f63f296a920b
https://www.jianshu.com/p/f63f296a920b

camera1 的 open 简单代码流程可参考这篇:
Android Camera open 从上到下代码流程
camera2 的 open 简单代码流程可参考这篇:
Android CameraManager open 从上到下代码流程

如果需要更详细的demo,可参考官方的 demo:cameraview

camera1和camera2 的调用流程对比,可参考这张图。可以看到,API V2是没有通过JNI的api的,这里是直接调用的service。


https://source.android.google.cn/docs/core/camera

https://blog.csdn.net/u012596975/article/details/107137110

谷歌在Andorid 5.0(API Level 21)便重新对Camera进行了设计,摒弃了Camera Api v1的设计逻辑,提出了一个全新的API – camera2,引入了Session以及Request概念,将控制逻辑统一成一个视图,因此在使用上更加复杂,同时也支持了更多特性,比如逐帧控制曝光、感光度以及支持Raw格式的输出等。并且由于对控制逻辑的高度抽象化,使得该接口具有很高的灵活性,可以通过简单的操作实现30fps的全高清连拍的功能,总得来说,该接口极大地提高了对于相机框架的控制能力,同时也进一步大幅度提升了其整体性能。
camera2的应用层与framework层之间的流程如下:


https://blog.csdn.net/u012596975/article/details/107137110

简单来说就是,引入了Session以及Request,使用更加复杂,功能多,更加灵活了。

注意,虽然新增了camera2的api,camera1的代码依然在android源码中。分析的时候要注意。
frameworks/base/core/java/android/hardware/camera2/这个目录下的是camera2的framework层代码。

Camera整体架构简述


https://blog.csdn.net/TaylorPotter/article/details/105387109

忽略掉驱动层,就是这张图。


https://source.android.google.cn/docs/core/camera

了解完Android Camera工作大体流程后,来看看部分细节。

2. 源码简单分析

本篇源码分析,不会涉及驱动层及以下(最多一点点)。另由于MTK和高通camera,还有android原生的,在camera这块差异很大,流程分析查找资料的时候要注意下。

Android Camera工作大体流程:


https://blog.csdn.net/TaylorPotter/article/details/105387109

出处: https://blog.csdn.net/TaylorPotter/article/details/105387109
绿色框中是应用开发者需要做的操作,蓝色为AOSP提供的API,黄色为Native Framework Service,紫色为HAL层Service.
描述一下步骤:

  • 1.App一般在MainActivity中使用SurfaceView或者SurfaceTexture + TextureView或者GLSurfaceView等控件作为显示预览界面的控件,共同点都是包含了一个单独的Surface作为取相机数据的容器.
  • 2.在MainActivity onCreate的时候调用API 去通知Framework Native Service CameraServer去connect HAL继而打开Camera硬件sensor.
  • 3.openCamera成功会有回调从CameraServer通知到App,在onOpenedCamera或类似回调中去调用类似startPreview的操作.此时会创建CameraCaptureSession,创建过程中会向CameraServer调用ConfigureStream的操作,ConfigureStream的参数中包含了第一步中空间中的Surface的引用,相当于App将Surface容器给到了CameraServer,CameraServer包装了下该Surface容器为stream,通过HIDL传递给HAL,继而HAL也做configureStream操作
  • 4.ConfigureStream成功后CameraServer会给App回调通知ConfigStream成功,接下来App便会调用AOSP setRepeatingRequest接口给到CameraServer,CameraServer初始化时便起来了一个死循环线程等待来接收Request.
  • 5.CameraServer将request交到Hal层去处理,得到HAL处理结果后取出该Request的处理Result中的Buffer填到App给到的容器中,
    SetRepeatingRequest 为了预览,则交给Preview的Surface容器,如果是Capture Request则将收到的Buffer交给ImageReader的Surface容器.
  • 6.Surface本质上是BufferQueue的使用者和封装者,当CameraServer中App设置来的Surface容器被填满了BufferQueue机制将会通知到应用,此时App中控件取出各自容器中的内容消费掉,Preview控件中的Surface中的内容将通过View提供到SurfaceFlinger中进行合成最终显示出来,即预览;而ImageReader中的Surface被填了,则App将会取出保存成图片文件消费掉.

简单图如下:


https://blog.csdn.net/TaylorPotter/article/details/105387109

https://blog.csdn.net/TaylorPotter/article/details/105387109
通过AIDL binder调用向Framework层的CameraServer进程下指令,从CameraServer进程中取的数据.
基本过程都如下:

  • 1.openCamera:Sensor上电
  • 2.configureStream: 该步就是将控件如GLSurfaceView,ImageReader等中的Surface容器给到CameraServer.
  • 3.request: 预览使用SetRepeatingRequest,拍一张可以使用Capture,本质都是setRequest给到CameraServer
  • 4.CameraServer将Request的处理结果Buffer数据填到对应的Surface容器中,填完后由BufferQueue机制回调到引用层对应的Surface控件的CallBack处理函数,接下来要显示预览或保图片App中对应的Surface中都有数据了

着重看看以下几点

  • CameraService和CameraProvider服务启动
  • open
  • configure
  • request

2.1 CameraService和CameraProvider服务启动

层级架构概览


https://blog.csdn.net/weixin_41678668/article/details/88620265

总体逻辑顺序计
(1) CameraProvider进程启动、注册
(2) CameraServer进程启动、注册、初始化
(3) CameraServer初始化过程中通过HIDL通信获取CameraProvider,并对 CameraProvider进行初始化

CameraService和CameraProvider初始化


https://blog.csdn.net/qq_16775897/article/details/81240600

CameraServer初始化


https://blog.csdn.net/TaylorPotter/article/details/105387109

具体代码流程可参考:
Android 8.1 Camera2架构解析(1) CameraService和CameraProvider服务启动流程
[Android O] Camera 服务启动流程简析

2.2 open

可直接参考这篇:

camera framework open流程
有道笔记上排版更好。
camera2 open流程

最后来张时序图加深下印象。


https://blog.csdn.net/TaylorPotter/article/details/105387109

2.3 configure

以下代码出自这篇Android Camera2最简单的预览框显示

/**
     * 打开相机,预览是在回调里面执行的。
     */
    private void openCamera() {
        try {
            // 4.权限检查
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
                    != PackageManager.PERMISSION_GRANTED) {
                requestCameraPermission();
                return;
            }

            // 5.真正打开相机
            Log.i(TAG, "openCamera");
            mCameraManager.openCamera(mCameraId, mStateCallback, null);
        } catch (CameraAccessException e) {
            Log.e(TAG, "openCamera error = " + e.getMessage());
        }

     /**
     * 相机状态监听对象
     */
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(CameraDevice camera) {
            Log.i(TAG, "StateCallback! onOpened");
            mCameraDevice = camera; // 打开成功,保存代表相机的CameraDevice实例
            SurfaceTexture surfaceTexture = mTextureView.getSurfaceTexture();
            surfaceTexture.setDefaultBufferSize(mTextureView.getWidth(), mTextureView.getHeight());
            Surface surface = new Surface(surfaceTexture);
            ArrayList<Surface> previewList = new ArrayList<>();
            previewList.add(surface);
            try {
                // 6.将TextureView的surface传递给CameraDevice
                mCameraDevice.createCaptureSession(previewList, new CameraCaptureSession.StateCallback() {
                    @Override
                    public void onConfigured(@NonNull CameraCaptureSession session) {
                        try {
                            CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                            builder.addTarget(surface); // 必须设置才能正常预览
                            CaptureRequest captureRequest = builder.build();

                            // 7.CameraCaptureSession与CaptureRequest绑定(这是最后一步,已可显示相机预览)
                            session.setRepeatingRequest(captureRequest, mSessionCaptureCallback, null);
                        } catch (CameraAccessException e) {
                            Log.e(TAG, "createCaptureRequest error = " + e.getMessage());
                        }
                    }

                    @Override
                    public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                        Log.e(TAG, "onConfigureFailed");
                    }
                }, null);
            } catch (CameraAccessException e) {
                Log.e(TAG, "createCaptureSession error = " + e.getMessage());
            }
        }


应用层在openCamera之后,会调用createCaptureSession。


image.png

createCaptureSession之后的流程可参考这篇:
camera framework configure流程分析

涉及到的主要类:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java#632

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

出处:https://blog.csdn.net/haodada1226/article/details/121719939

总结一下:

① configure为app传入的surface配置相应的stream,然后将gbp、streamid、surfaceid进行绑定,以便于发送request请求的时候去获取;
② 告诉hal层,需要从camera中获取什么样格式的buffer

简单版时序图


https://www.jianshu.com/p/26d4b781a14d

复杂版时序图


https://blog.csdn.net/TaylorPotter/article/details/105387109

2.4 request

在 Android Camera2最简单的预览框显示 这篇文的代码中可以看到,
调用createCaptureRequest之后通过build创建CaptureRequest,然后session.setRepeatingRequest,然后就可以预览了。

https://blog.csdn.net/TaylorPotter/article/details/105387109

然后接下来的流程可直接参考这篇:
camera framework request流程

涉及到的主要类如下:
http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java#121

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java#submitCaptureRequest

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

http://aosp.opersys.com/xref/android-9.0.0_r61/xref/hardware/interfaces/camera/device/3.4/default/ExternalCameraDeviceSession.cpp#400

出处: https://blog.csdn.net/haodada1226/article/details/121848769

这里总结一下:

configure的时候为每个surface创建相应的Camera3OutputStream,然后将相应的信息保存起来(注意CameraDeviceClient中的mStreamMap、mConfiguredOutputs以及Camera3Device中的mOutputStreams等),然后告诉hal层需要配置什么格式、分辨率等的流。request中会将上述的surfaces和outputStreams填充进request请求中,然后在Camera3Device中起一个thread,一直向hal层发送request请求。

最后来张时序图


https://blog.csdn.net/TaylorPotter/article/details/105387109

3.camera中的BufferQueue

https://www.jianshu.com/p/05a8d6f5b4df
BufferQueue可以理解为一个生产者-消费者”模型,对GraphicBuffer管理的一种机制。
需注意的是,可以将BufferQueue当作是一个算法结构,并不是只有Surfaceflinger会使用到,其他进程只要有GraphicBuffer的消费地方都会使用到。

BufferQueue结构


https://www.jianshu.com/p/05a8d6f5b4df

https://www.jianshu.com/p/05a8d6f5b4df

https://www.jianshu.com/p/05a8d6f5b4df
图形生产者(如相机,View绘制等)先向BufferQueue申请GraphicBuffer,填充完GraphicBuffer后,将GraphicBuffer移交给BufferQueue,BufferQueue会通知图形消费者(如Surfaceflinger,ImageReader,GLConsumer等)
相机中preview使用到的TextureView中的成员SurfaceTexture就是个自带BufferQueue的组件。

https://www.jianshu.com/p/05a8d6f5b4df

框架流程汇总


https://www.jianshu.com/p/26d4b781a14d

参考链接:
深入理解Android相机体系结构之二
深入理解Android相机体系结构之三
深入理解Android相机体系结构之十

官方文档

Android Camera简单整理(一)-Camera Android架构(基于Q)
Android Camera简单整理(三)-Mtk Camera MtkCam3架构学习

[Android O] Camera 服务启动流程简析

CameraService启动流程
Android 8.1 Camera2架构解析(1) CameraService和CameraProvider服务启动流程
Camera service服务启动流程

BufferQueue详解 原理
Android-Fk:BufferQueue学习整理
Android Camera2 Framwork+Hal+Surface整体数据流程

Android Camera 打开预览流程分析(三)-- Camera 连接到CameraService 过程分析
camera framework configure流程分析
Camera2 API -- OutputConfiguration
camera framework configure流程分析

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容