• 虚拟摄像头之五: 详解 android8 的 Camera 子系统框架


    前言

    由于 android 版本差异、 camera子系统框架也有不同调整,本文是采用 android8 源码作为参考对象,对 camera 子系统进行框架梳理,
    建立起框架性认知后、在进一步分析各模块实现时、就如同有了地图和指南针功用。
    网上有不同版本摄像头框架描述,笔者为给看客们以简明扼要框架概念、特在文章尾部绘制了该框架图。

    Camera 系统框架分层描述

    App 应用

    APP代码位置:@packages/apps/Camera2/

    主要对 Framework中 android.hardware.Camera类的调用,并且实现 Camera 应用的业务逻辑和 UI 显示。
    Camera 的应用层在 Android 上表现为直接调用SDK API 开发的一个Camera 应用APK包。

    一个Android 应用中若要使用frameworks中的android.hardware.Camera类,需要在Manifest 文件声明Camera的权限,
    另外还 需要添加一些 元素来声明应用中的Camera 特性,如自动对焦等。

    framework层

    代码路径:@frameworks/base/core/java/android/hardware/Camera.java
    此类是提供给用户空间app端引用的封装、该类调用 android_hardware_Camera.cpp 中的注册的 JNI 本地方法,来管理摄像头设备、设置 camera 事件回调;
    从而让用户的App 与 Camera 驱动连接起来形成完整数据链路。

    JNI

    代码路径:@frameworks/base/core/jni/android_hardware_Camera.cpp
    与Camera有关的本地方法封装与注册,向上供java空间程序引用,向下调用原生代码以获得物理camera的访问权,
    然后返回用于在framework层创建android.hardware.Camera对象的数据。

    Camera Client

    源码路径: @frameworks/av/camera/Camera.cpp
    程序编译生成 libcamera_client.so 库,是摄像头 Client 端的实现,android系统管理 Camera 是采用 C/S 模式。
    JNI 封装的本地方法都是 client 端方法, Client调用IPC binder与camera service 服务端通讯、实现调用Servcie管理
    物理摄像头目的。

    IPC Binder

    源码路径:@frameworks/av/camera/ICameraClient.cpp
    IPC binder代理实现client与service进程间通信,类继承关系主要在 ICamera.h、 ICameraClient.h 和 Camera.h 文件中,内容如下:
    @frameworks/av/camera/include/camera/android/ICamera.h

    class ICamera: public android::IInterface
    {
    public:
        enum {
            // Pass real YUV data in video buffers through ICameraClient.dataCallbackTimestamp().
            VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV = 0,
            // Pass metadata in video buffers through ICameraClient.dataCallbackTimestamp().
            VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA = 1,
            // Pass video buffers through IGraphicBufferProducer set with setVideoTarget().
            VIDEO_BUFFER_MODE_BUFFER_QUEUE = 2,
        };
        // set a buffer interface to use for client-received preview frames instead
        // of preview callback buffers. Passing a valid interface here disables any
        // active preview callbacks set by setPreviewCallbackFlag(). Passing NULL
        // disables the use of the callback target.
        virtual status_t        setPreviewCallbackTarget(
                const sp<IGraphicBufferProducer>& callbackProducer) = 0;
    
        // start preview mode, must call setPreviewTarget first
        virtual status_t        startPreview() = 0;
    
        /*
         * take a picture.
         * @param msgType the message type an application selectively turn on/off
         * on a photo-by-photo basis. The supported message types are:
         * CAMERA_MSG_SHUTTER, CAMERA_MSG_RAW_IMAGE, CAMERA_MSG_COMPRESSED_IMAGE,
         * and CAMERA_MSG_POSTVIEW_FRAME. Any other message types will be ignored.
         */
        virtual status_t        takePicture(int msgType) = 0;
    
    }
    
    class BnCamera: public android::BnInterface<ICamera>
    {
    public:
        virtual status_t    onTransact( uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0);
    };
    
    • 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
    • 37
    • 38
    • 39
    • 40

    @frameworks/av/camera/include/camera/android/ICameraClient.h

    class ICameraClient: public android::IInterface
    {
    public:
        DECLARE_META_INTERFACE(CameraClient);
    
        virtual void            notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
        virtual void            dataCallback(int32_t msgType, const sp<IMemory>& data,
                                             camera_frame_metadata_t *metadata) = 0;
        virtual void            dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
    
        // Invoked to send a recording frame handle with a timestamp. Call
        // ICamera::releaseRecordingFrameHandle to release the frame handle.
        virtual void            recordingFrameHandleCallbackTimestamp(nsecs_t timestamp,
                                             native_handle_t* handle) = 0;
    
        // Invoked to send a batch of recording frame handles with timestamp. Call
        // ICamera::releaseRecordingFrameHandleBatch to release the frame handles.
        // Size of timestamps and handles must match
        virtual void            recordingFrameHandleCallbackTimestampBatch(
                                            const std::vector<nsecs_t>& timestamps,
                                            const std::vector<native_handle_t*>& handles) = 0;
    };
    
    // ----------------------------------------------------------------------------
    
    class BnCameraClient: public android::BnInterface<ICameraClient>
    {
    public:
        virtual status_t    onTransact( uint32_t code,
                                        const Parcel& data,
                                        Parcel* reply,
                                        uint32_t flags = 0);
    };
    
    • 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

    上面贴出源码头文件中已经把类之间关系描述很清晰了,我们看一下 BnCameraClient 类是如何与 Camera 间关联的,如下:
    @frameworks/av/camera/Camera.h

    
    class Camera :
        public CameraBase<Camera>,
        public ::android::hardware::BnCameraClient
    {
    public:
        enum {
            USE_CALLING_UID = ::android::hardware::ICameraService::USE_CALLING_UID
        };
        enum {
            USE_CALLING_PID = ::android::hardware::ICameraService::USE_CALLING_PID
        };
    
                // construct a camera client from an existing remote
        static  sp<Camera>  create(const sp<::android::hardware::ICamera>& camera);
        static  sp<Camera>  connect(int cameraId,
                                    const String16& clientPackageName,
                                    int clientUid, int clientPid);
    
        static  status_t  connectLegacy(int cameraId, int halVersion,
                                         const String16& clientPackageName,
                                         int clientUid, sp<Camera>& camera);
        
        // start preview mode, must call setPreviewTarget first
        status_t    startPreview();
        ...... //省略部分源码
        // ICameraClient interface
        virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
        virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                                         camera_frame_metadata_t *metadata);
        ...... //省略部分源码
    }
    
    • 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

    Camera 类直接继承 BnCameraClient 类,所以构建出来的 Camera 对象的 client 角色也就确认下来,此处是 Camera 摄像头 C/S 模式结合点,
    梳理清晰框架关键节点非常关键。

    Camera Service

    源码路径:@frameworks/av/services/camera/libcameraservice/CameraService.cpp

    此源码编译生成 libcameraservice.so 库文件,主要实现两个功能:
    (1). 实现 Camera 服务端功能,通过 BinderService 实现与 libcamera_client.so 库进行通讯;
    (2). 在 CameraProviderManager.cpp 中以服务方式来管理 v4l1_camera_hal 驱动接口,实现物理摄像头管理功能;

    此部分内容暂时不过多描述,笔者将在下一篇《详解 CameraService 都做了什么》文章中,详细梳理和分析。暂时简单介绍呢,
    就是 CameraProviderManager.cpp 中获取 “legacy/0” 系统服务,通过系统服务的方式、调用 CameraProvider 服务中的功能.

    CameraProvider

    源码路径:@hardware/interfaces/camera/2.4/default/service.cpp

    主要功能:管理安卓系统的物理摄像头、作为独立系统服务存在于android系统中,给 CameraService 提供支持;我们可以理解该模块就是物理摄像头代理服务机构。
    CameraProvider 服务启动时在系统服务中注册了 “legacy/0” 服务,使用者通过该名称可以获取到 CameraProvider 服务。 详细梳理请看官参考
    上一篇 《谁在调用 v4l2_camera_HAL 摄像头驱动》文章内容。

    HAL

    源码路径: @hardware/libhardware/modules/camera/3_4/

    硬件抽象层定义了一套标准接口,HAL内容开放给各个厂家去实现,因此实现风格各异。
    我们上一篇《重构android8.1 的 v4l2_camera_HAL 支持虚拟摄像头》 文章中,详细梳理CameraHal-3.4程序框架,及实现逻辑。

    Kernel Driver

    内核中摄像头驱动有各厂家实现的驱动,笔者使用的是NXP的硬件平台,
    源码路径:@kernel/drivers/media/platform/imx8/ov5640_mipi_v3.c & ov5640_v3.c
    Camera驱动向下与真实的camera硬件进行交互,向上与HAL实现进行交互。

    内核中除了有真实的摄像头驱动也有虚拟机摄像头驱动,如: v4l2loopback 、vivi等,笔者的虚拟摄像头实现就是通过v4l2loopback
    作为基础的技术框架来实现。

    总结

    本篇文章是从 camera 子系统框架入手、先建立整体框架概念;此源码版本是 android8.1 版本,因源码版本差异、框架实现也也会有差别。

    在这里插入图片描述这个子系统框图、可清晰指引 android8 camera 学习路标之功效,如果看官你认为本篇文章对你有所启发或帮助、请点赞一下哦,谢谢。

  • 相关阅读:
    全面理解云上网络技术
    3. 文档概述(Documentation Overview)
    windows快捷方式图标变成空白
    posix定时器的使用
    Sentinel的流控与熔断降级规则详解
    生成学习全景:从基础理论到GANs技术实战
    赛后补题L - Non-Prime Factors
    linux重要的目录之proc和dev目录
    文件包含漏洞(2), 伪协议, php://filter, php://input
    【考研数学】高等数学第五模块 —— 级数(2,幂级数)
  • 原文地址:https://blog.csdn.net/weixin_38387929/article/details/126179757