我是靠谱客的博主 英勇黑夜,最近开发中收集的这篇文章主要介绍【Camera专题】Sprd-基于log的Camera流程分析1-【Open流程】Stay Hungry,Stay Foolish!,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、前言

天苍苍,野茫茫,风吹草低见牛羊!
高通的旗舰机项目基本搞定,就等6月底上市了,期望能卖得不错吧!
这半年做高通项目,学习到许多关于Camera的知识,当然还需要深入去学习!
不过,下半年要做展讯旗舰机器,又要开始踩展讯的坑!
前段时间写了一下Sprd的Camera流程分析,感觉之前写得不太详细,
因此,打算基于log分析源码,对整个架构更加深入的学习!

二、Open流程

1.整体架构

在这里插入图片描述

整体架构图可知,这个流程

APP层->Framework层->通过Binder机制与Service进程通信
->CameraService->通过JNI->调用到HAL层->Kernel层

这也是本文的分析思路!
PS:由于CameraService会在开机的时候就初始化,因此我们优先简单分析!

2.log分析-【开机第一次启动Camera:冷启动】

2.1 CameraService的启动-开机初始化
开机时,就会初始化CameraService,这里就是你可以看到的跟Camera相关的第一行log

  • 2.1.1 log
    在这里插入图片描述

  • 2.1.2源码
    frameworks/av/services/camera/libcameraservice/CameraService.cpp

CameraService::CameraService()
    :mSoundRef(0), mModule(0)
{
    //这里就是我们开机时,打印的Cameralog,getpid获取进程号:223
    ALOGI("CameraService started (pid=%d)", getpid());
    gCameraService = this;

    for (size_t i = 0; i < MAX_CAMERAS; ++i) {
        mStatusList[i] = ICameraServiceListener::STATUS_PRESENT;
    }    

    this->camera_device_status_change = android::camera_device_status_change;
}

开机时,CameraService就会启动,进行初始化,具体的细节就不去追究。
流程:
CameraService: CameraService started (pid=223)//进程号:223
CameraService: CameraService::onFirstRef //第一次启动,执行以下动作

  • 1.CameraService: Loaded “Sprd Camera HAL3” camera module //加载HAL3 module
  • 2.CameraService: setCameraFree cameraId=0和cameraId=1 //设置camera当前的状态
  • 3.CameraDeviceFactory::registerService(this) 注册服务
void CameraService::onFirstRef()
{
    LOG1("CameraService::onFirstRef");

    BnCameraService::onFirstRef();

    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
                (const hw_module_t **)&mModule) < 0) {
        ALOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }
    else {
        //加载HAL3 module
        ALOGI("Loaded "%s" camera module", mModule->common.name);
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        //设置camera当前状态为空闲
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }

        if (mModule->common.module_api_version >=
                CAMERA_MODULE_API_VERSION_2_1) {
            mModule->set_callbacks(this);
        }

        getVendorTagOps();
        //注册Camera服务
        CameraDeviceFactory::registerService(this);
    }
}

这里为什么要设置camera的状态呢?

void CameraService::setCameraFree(int cameraId) {
    //写入0表示camera处于空闲状态  
    android_atomic_write(0, &mBusy[cameraId]);
    ALOGV("setCameraFree cameraId=%d", cameraId);
}
void CameraService::setCameraBusy(int cameraId) {
    //写入1表示camera处于繁忙状态
    android_atomic_write(1, &mBusy[cameraId]);
    ALOGV("setCameraBusy cameraId=%d", cameraId);
}

我们需要这个busy位的原因是一个新的CameraService::connect()请求
可能在前一个客户端析构函数尚未运行或正在运行时进入仍在运行。
如果前一个client(客户端)的最后一个强引用已经消失,
但是析构函数还没有完成,我们不应该允许new Client
因为我们需要等待前面的客户端首先销毁硬件。

因此:
CameraService: setCameraFree cameraId=1
CameraService: setCameraBusy cameraId=1
会成对出现,初始化的时候,会设置成free,
打开摄像头时,会设置成busy,
关闭摄像头时,状态又会设置成free。

另外:说一下 getNumberOfCameras()函数
在这里插入图片描述
在这里插入图片描述

getNumberOfCameras=2表示的是系统支持前摄和后摄,2个摄像头

也许你的系统还可能支持前副摄像、后副摄像
那么应该在** kCameraInfo数组**再添加2个

这里CameraService开机的初始化就简单分析完了
既然是开机,所以接下来第一次打开Camera属于冷启动
需要初始化很多东西,这就是为啥冷启动会慢的原因!

2.2 APP层 和 Framwork层

  • 2.2.1 log
    在这里插入图片描述

  • 2.2.2 源码
    APP这一块,懂得一些基本知识,
    由于学的不够深,Framwork也没研究过,
    因此就不做深入分析,以免误人子弟。
    以上就是你能看到的log!
    最后这里可以看到调用到getSensorStaticInfo这个Hal层的方法!

2.3 Hal层

  • 2.3.1 log
    在这里插入图片描述

getSensorStaticInfo函数主要用来读取Sensor的信息,看源码分析!
由于是开机第
一次启动时,调用getSensorStaticInfo失败了,why?

先打开后摄,因为没有后摄,所以获取信息失败了

后面又重新调用一次getSensorStaticInfo,然后获取到sensor info

然后打开前摄,有摄,能获取到sensor信息

  • 2.3.2 源码
    vendor/sprd/modules/libcamera/hal3_2v1/SprdCamera3Setting.cpp
int SprdCamera3Setting::getSensorStaticInfo(int32_t cameraId) {
    struct sensor_drv_context *sensor_cxt = NULL;
···省略源码
    //因为是开机第一次运行,这里肯定是失败的,不会跑进去
    if (alreadyGetSensorStaticInfo[cameraId] != 0) { 
        HAL_LOGI("already get sensor info");
        return 0;
    }    

    HAL_LOGI("E");//可以看到这个log打印了
···省略源码
    ret = sensor_open_common(sensor_cxt, cameraId, 0);
    if (ret) {
        //这里的log打印了,我们跟进sensor_open_common函数去看
        HAL_LOGE("open camera (%d) failed", cameraId);
        setLargestSensorSize(cameraId, default_sensor_max_sizes[cameraId].width,
                             default_sensor_max_sizes[cameraId].height);
        goto exit;
    }
···后面先这些省略不看
}

这里我们继续跟进sensor_open_common函数去看
vendor/sprd/modules/libcamera/sensor/sensor_drv_u.c
打开Camera的步骤
NOTE:when open camera,you should do the following steps.
步骤1.register all sensor for the following first open sensor.
第一次打开摄像头的时候,注册所有的sensor

步骤2.if first open sensor failed, identify module list to save sensor index.
如果第一次打开失败,重新identify 所有的sensor并保存起来
步骤3.try open sensor second time.
尝试重新打开sensor
步骤4.if 3 steps failed,sensor open failed.
如果步骤3失败了,那么sensor打开失败

来看源码:

cmr_int sensor_open_common(struct sensor_drv_context *sensor_cxt,
                           cmr_u32 sensor_id, cmr_uint is_autotest) {
    ATRACE_BEGIN(__FUNCTION__);
···
    //这条log打印了
    SENSOR_LOGI("0, start,id %d autotest %ld", sensor_id, is_autotest);

    /* init ctx, exif, load sensor file, open hw driver with sensor id.*/
    ret_val = sensor_context_init(sensor_cxt, sensor_id, is_autotest);
···
    /* create sensor process thread. */
    ret_val = sensor_create_ctrl_thread(sensor_cxt);
    /*这个函数会 打印 sns_drv_u: 1593, sensor_create_ctrl_thread: is_inited 0*/
···
    /* create the hw obj of kernel driver. */
···
    /*该函数 打印 hw_sensor: 107, hw_sensor_drv_create: sensor_id:0*/
    fd_sensor = hw_sensor_drv_create(&input_ptr, &hw_drv_handle);
     /*该函数会继续调用_hw_sensor_dev_init函数 */
    sensor_cxt->fd_sensor = fd_sensor;
    sensor_cxt->hw_drv_handle = hw_drv_handle;
    sensor_cxt->sensor_hw_handler = hw_drv_handle;

    /*load all the sensor ICs' info according the indexs stored in sensor idx file*/
    /*根据存储在sensor idx文件中的索引 加载传感器ICs的所有信息*/
    sensor_load_idx_inf_file(sensor_cxt);
    if (sensor_cxt->sensor_identified) {
        //这里调用sns_load_drv -> 里面继续调用sensor_get_match_info -> sensor_get_module_tab
        if (SENSOR_SUCCESS == sns_load_drv(sensor_cxt, SENSOR_MAIN)){
            sensor_num++;
        }
    if (SENSOR_SUCCESS == sns_load_drv(sensor_cxt, SENSOR_SUB)) {
            sensor_num++;
        }
···
        SENSOR_LOGI("1 is identify, register OK");
        /*first open sensor*/
        ret_val = sensor_open(sensor_cxt, sensor_id);
        if (ret_val != SENSOR_SUCCESS) {
            SENSOR_LOGI("first open sensor failed,start identify");
        }

    /* scan the devices in cfg list and find out the correct sensor driver */
    if ((!sensor_cxt->sensor_identified) || (ret_val != SENSOR_SUCCESS)) {
        sensor_num = 0;
        SENSOR_LOGI("register sensor fail, start identify");
        if (sensor_identify(sensor_cxt, SENSOR_MAIN))
            sensor_num++;
        if (sensor_identify(sensor_cxt, SENSOR_SUB))
            sensor_num++;
···
        /*再一次打开*/
        ret_val = sensor_open(sensor_cxt, sensor_id);
    }
    sensor_cxt->sensor_identified = SCI_TRUE;
    //保存识别到的摄像头信息,后续再打开摄像头,直接读idx文件即可
    sensor_save_idx_inf_file(sensor_cxt);
    sensor_rid_save_sensor_info(sensor_cxt);

···
    SENSOR_LOGI("total camera number %d", sensor_num);

init_exit:
    if (SENSOR_SUCCESS != ret_val) {
        //打开摄像头失败,删除相关资源
        sensor_destroy_ctrl_thread(sensor_cxt);
        hw_sensor_drv_delete(hw_drv_handle);
        sensor_cxt->hw_drv_handle = NULL;
        sensor_cxt->sensor_hw_handler = NULL;
    }
    return ret_val;
}

加了很多注释,就不在赘述。
根据源码,我们继续看具体的log
在这里插入图片描述

在这里插入图片描述

这份log执行的就是步骤1和步骤2
步骤1.register all sensor for the following first open sensor.
第一次打开摄像头的时候,注册所有的sensor

步骤2.if first open sensor failed, identify module list to save sensor index.
如果第一次打开失败,重新identify 所有的sensor并保存相关信息
在这里插入图片描述

加载的cfg表格源码
vendor/sprd/modules/libcamera/sensor/sensor_cfg.c
在这里插入图片描述
sp2609宏定义的位置
device/sprd/sharkle/sp9820e_xtc_i17/BoardConfig.mk

#camera sensor type
#CAMERA_SENSOR_TYPE_BACK := "SP2609"
CAMERA_SENSOR_TYPE_FRONT := "SP2609"
#CAMERA_SENSOR_TYPE_BACK_EXT :=
#CAMERA_SENSOR_TYPE_FRONT_EXT :=

接下来调用
sns_ops->create_handle(&sns_init_para,&sensor_cxt->sns_ic_drv_handle);
这个函数如下

在这里插入图片描述
继续看log

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

步骤3.try open sensor second time.
尝试重新打开sensor
步骤4.if 3 steps failed,sensor open failed.
如果步骤3失败了,那么sensor打开失败

第一次Camera启动分析就结束了

3.log分析-【第二次启动分析】

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结

对比第一次冷启动热启动
第一次冷启动主要是多了CameraService的创建,
还有getSensorStaticinfo时,先去search所有的camera信息,保存起来,
后续再次打开Camera,直接从缓存读取信息,因此冷启动慢,热启动快。

其他的调用流程都是一致的!

Stay Hungry,Stay Foolish!

最后

以上就是英勇黑夜为你收集整理的【Camera专题】Sprd-基于log的Camera流程分析1-【Open流程】Stay Hungry,Stay Foolish!的全部内容,希望文章能够帮你解决【Camera专题】Sprd-基于log的Camera流程分析1-【Open流程】Stay Hungry,Stay Foolish!所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(94)

评论列表共有 0 条评论

立即
投稿
返回
顶部