Android Camera fw学习(一)-类之间的关系和作用

感兴趣可以加QQ群85486140,大家一起交流相互学习下!


备注:本文基于Android 5.1分析,可能已经过时了,不过里面的原理和现在7.0基本一样。博文为个人看代码笔记,如有问题,请发表意见大家一起学习,进步。后续的博文会沿着下面几步来走,把自己对Camera分析总结一下。

  • 1.简单介绍Camera几大接口类,以及相关类的继承关系(也就当前博文)
  • 2.app->jni->native详细分析open camera操作过程中发生了什么
  • 3.startPreview详细过程分析
  • 4.生产者消费者,bufferqueue模型介绍,以及详细介绍preview buffer的生产消费过程
  • 5.takepicture详细过程分析
  • 6.Recording详细过程分析
  • 7.由添加一个CameraMetadata tag引发的实战分析
  • 8.v4l2 架构详细分析

Android Camera中的类很多,刚开始看的时候,感觉各个类之间的关系相当复杂。不过在学习过Binder后,它们的关系就渐渐浮出水面。在开始学习类之间关系时,我们先从整体上了解Camera在工作时,都有哪些对象在作用。

图一、工作时存在的3个鲜活对象

学过binder之后,我们就会知道服务端和客户端需要实现公共的接口,彼此才能默契的工作,要不然是没法友好沟通的。如上图一我们发现各个代理对象和本地对象都实现了相应的接口,各接口的作用下面做简要介绍。

  • 1.ICameraClient: 这主要是一些消息发送的接口,包括帧可用通知,回调一些信息给client等消息。不过这里要注意的是,BnCameraClient对象其实是在client这端,不在CameraService端。
  • 2.ICamera:camera的一些标准操作接口,比如startpreview,takepicuture,autofocus,所有的操作动作都是用的这一套接口。
  • 3.ICameraService: 链接Camera服务,Camera device,获取Camera数量,Camera硬件信息,视厂角,镜头等信息。

下面分别介绍实现这些接口各个类的关系。

一、ICameraClient接口

1.类关系和一些接口宏说明

继承IcameraClient各类的继承关系如下图所示。

图二、ICameraClient相关类继承关系

看过源代码的同学可能比较好奇,为什么camera类没有继承ICamera类呢,但是camera类中也实现了ICamera接口。其实这里Camera类没有直接继承ICamera接口类,而是直接实现了ICamera的接口,在各个接口中调用ICamera代理对象相应的接口就行了。这里只是打了个幌子。大家看看下面的代码就知道了

路径:frameworks/av/include/camera.h
//Camera的继承的类,可以看到模板参数就是Camera类。
class Camera :
    public CameraBase<Camera>,
    public BnCameraClient
{
//......
}

//路径:frameworks/av/include/cameraBase.h
//CameraBase类继承了IBinder::DeathRecipient
template <typename TCam, typename TCamTraits = CameraTraits<TCam> >
class CameraBase : public IBinder::DeathRecipient
{
public: //下面几个类型请看下面类的CameraTraits声明
    typedef typename TCamTraits::TCamListener       TCamListener;
    //由下面的CameraTraits类可以发现TCamUser就是ICamera的强指针类型。TCamCallbacks就是ICameraClient类型,我们这里留个心眼。
    typedef typename TCamTraits::TCamUser           TCamUser;
    typedef typename TCamTraits::TCamCallbacks      TCamCallbacks;
    typedef typename TCamTraits::TCamConnectService TCamConnectService;
//......
    sp<TCamUser>                     mCamera;
    status_t                         mStatus;
    sp<TCamListener>                 mListener;
    const int                        mCameraId;
    typedef CameraBase<TCam>         CameraBaseT;
};

//CameraTraits该类是已结构体的形式展现出来的,不过在C++中的结构体也是类。可以看到模板参数还是Camera类。
struct CameraTraits<Camera>
{ //下面声明的几个宏,会在其他地方用到。
    typedef CameraListener        TCamListener;
    typedef ICamera               TCamUser;
    typedef ICameraClient         TCamCallbacks;
    typedef status_t (ICameraService::*TCamConnectService)(const     sp<ICameraClient>&,                                                           int, const String16&, int,                                        /*out*/ sp<ICamera>&);
    //下面这个静态函数指针,执行的是CameraService类中的Connect函数。
    static TCamConnectService     fnConnectService;
};

上面这些类继承关系,以及模板类的一些信息,如果有些C++基础的同学一看就明白了。如果不明白,最好去看看C++中模板的介绍,再过来看博文会有事半功倍的效果。上面几个类中有几个声明需要我们知道。

  • 1.fnConnectService:指向ICameraService::connect函数指针,这在camera.h文件开始位置已经严重声明了。
 CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService = &ICameraService::connect;
  • 2.几个用的比较多的宏,要暂时记在心里
 ICamera = TCamUser,
 ICameraClient = TCamCallbacks,
 typedef CameraBase<TCam>         CameraBaseT;
2.ICameraClient创建过程发生了什么
  • 1.android_hardware_Camera_native_setup()
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
    // Convert jstring to String16
    const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName, rawClientName);

    sp<Camera> camera;
    if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
        // Default path: hal version is don't care, do normal camera connect.
        //这里调用Camera静态方法connect.请看下面代码
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID);
    } else {
    //......
}

当我们打开Camera时,第一个调用的就是native_setup(),它会找到包名,CameraID,UID宏与CameraService进行链接获取到camera对象。

  • 2.camera对象创建过程
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
        int clientUid)
{ //下面发现直接调用的是CameraBaseT::connect方法,大家应该还记得,前面说过
 //CameraBaseT就是带了camera模板参数的CameraBase类。请看下面CameraBase类。
    return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
//CameraBase类,这里TCam = camera,TCamTraits = CameraTraits<camera>,要记住
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
           const String16& clientPackageName, int clientUid)
{
    ALOGV("%s: connect", __FUNCTION__);
    sp<TCam> c = new TCam(cameraId); //这里直接new Camera()
    sp<TCamCallbacks> cl = c;//这里非常要强调一下,由于camera实现了ICameraClient的接口,所以这里cl,就是callback对象的引用了,实际都是同一个对象。
    status_t status = NO_ERROR;
    const sp<ICameraService>& cs = getCameraService();//这里获取CameraService代理对象,后续在继续分析binder getservice时,会详细分析这一流程。

    if (cs != 0) {//
        TCamConnectService fnConnectService = TCamTraits::fnConnectService;
//这里只需记着fnConnectService = ICameraService::connect,而参数c->mCamera是指向ICamera代理对象的强引用。连接成功后CameraService中会创建一个实现ICamera接口的Camera2Client类对象。这就具备友好通信的前提了。后续都是通过匿名binder实现直接通信的。
        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera);
    }
    if (status == OK && c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        ALOGW("An error occurred while connecting to camera: %d", cameraId);
        c.clear();
    }
    return c;
}

这里我们不做深入追究,后续的博文会深入介绍的。这里connect连接成功后,会有下面几个新对象生成。

  • (1).camera,显而易见在进行connect之前,就已经new出来一个camera对象了,然后定义TCamCallbacks强引用指针cl,用于conect时传给CameraService的BnCameraClient本地对象(这里的camera对象就是BnCameraClient本地对象)。注意在CameraService代理对象中,通过writeStrongBinder将该BnCameraClient注册到了当前camera客户端进程的binder_proc的refs_by_node链表中,同时会定义一个binder_ref对象传给CameraService中(这里就是匿名binder通信了,会在后续的binder学习中好好分析)。
  • (2).bnCameraClient 该对象就是上面new出来的camera对象的引用,以匿名binder通信方式,注册给camera client进程中,然后将binder_ref传给mediaServer中的CameraService对象中。
  • (3).Camera2Client,该对象为本地对象会在CameraService中诞生,引用对象会在connect返回时传给camera对象中ICamera强引用对象mCamera中,如下。
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera);//最后一个参数。

到这个时候,Camera运行需要的主要对象,都创建完毕。

二、ICamera接口

图三、ICamera相关类继承关系

该类是Camera控制的主要接口类,客户端和Service端都会实现ICamera接口类。客户端进程以匿名binder的形式,与mediaServer进程的CameraService进行通信。下面列举一些我个人认为有必要深入了解的接口。

函数名功能介绍
virtual status_t setPreviewTarget(const sp& bufferProducer) = 0;“pass the buffered IGraphicBufferProducer to the camera service”,这个就是设置buffer的地方,参数我们可以看到设下去的是buffer producer对象(这里的生产者-消费者模型我们后面介绍),其实preview申请一个Surface对象后,Sureface就对应一个buffer producer对象,应用是生产者,底层是消费者
virtual status_t startPreview() = 0;“start preview mode, must call setPreviewTarget first”,官方给的解释是在startpreview时,一定要先设置buffer
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;" send command to camera driver",google介绍简单直接,就是向sensor驱动发送命令,其实这个函数最终的是传给Camera hal 的CameraMetadata,进而间接就影响到了Camera driver
virtual void releaseRecordingFrame(const sp& mem) = 0;“release a recording frame”,官方解释就是释放录像帧,等后面我们分析了录像,在来这里把这个补充好吧

上面我只列举了部分函数,大家可以结合源码看看其它函数都有什么用,反正都是有很大用处的。

三、ICameraService接口

图四、ICameraService相关类继承关系

这里是CameraService的继承关系,右侧是我列举的一些个人认为比较重要的函数。ICameraService中总共有12接口,我们只介绍下面几个。

函数名函数介绍
virtual int32_t getNumberOfCameras() = 0;这个在CameraService起来是会调用这个接口,来探测Camera硬件上有几个Camera,进而会不会有前设旋转开关,在每次Open Camera时也会调用一次
virtual status_t getCameraInfo(int cameraId,/out/struct CameraInfo* cameraInfo) = 0;获取Camera的信息,包括FOV,LENS,等信息
virtual status_t addListener(const sp& listener) = 0;目前发现没用这个函数,这里就先放这吧
virtual status_t connect(const sp& cameraClient,int cameraId, const String16& clientPackageName,intclientUid, /out/sp& device) = 0;这个函数是非常重要的,当Open Camera时,客户端会传过来一个bpCameraClientde代理对象。然后CameraService会创建一个实现ICamera接口的Camera2client类对象,紧接着就把这个Camera2Client的代理返回到客户端进程中,用于频繁的操作Camera

四、总结

博文介绍了操作Camera的三大接口类之间的类继承关系和常用的接口分析。还没开始去分析preview,takepicture,recording等流程,后续的博文会一一展开,一起进步。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
在三星 Android Camera 驱动中,is-device-ischain.c 文件是一个用于实现图像链(Image Chain)功能的源代码文件。该文件包含了一些函数和数据结构,用于处理图像链模式下的图像稳定算法,并在驱动程序中完成相关的初始化、配置和控制操作。 具体来说,is-device-ischain.c 文件中包含了以下几个主要部分: 1. 宏定义和数据结构:该部分定义了一些常量和数据结构,包括了图像链模式的枚举型 IS_ISCHAIN,图像链模式的状态结构体 is_chain_state,以及一些相关的宏定义和函数声明。 2. 初始化函数:该部分包含了一个用于初始化图像链模式的函数 is_device_ischain_init(),该函数会在驱动程序初始化时被调用。初始化函数会读取配置文件中的参数,为图像链模式的状态结构体 is_chain_state 分配内存,并对其进行初始化。 3. 控制函数:该部分包含了一些用于控制图像链模式的函数,包括 is_device_ischain_config()、is_device_ischain_start()、is_device_ischain_stop() 和 is_device_ischain_release()。这些函数分别用于配置图像链模式的参数、启动和停止图像链模式、以及释放相关资源。 4. 图像稳定算法:该部分包含了一些用于实现图像稳定算法的函数,包括 is_device_ischain_process_frame() 和 is_device_ischain_update_state()。这些函数会根据当前帧的图像数据,以及之前的图像链状态,计算出当前帧的图像稳定结果,并更新图像链状态。 总体来说,is-device-ischain.c 文件是三星 Android Camera 驱动中一个重要的源代码文件,用于实现图像链模式下的图像稳定算法,并为驱动程序提供相关的控制和配置接口。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值