camera2 简单总结

作者: 梧叶已秋声 | 来源:发表于2022-09-26 16:37 被阅读0次

    写在开头:本文为学习 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流程分析

    相关文章

      网友评论

        本文标题:camera2 简单总结

        本文链接:https://www.haomeiwen.com/subject/jvpzortx.html