Mtk Camera Hal到驱动的流程(一)_mtk imageio-程序员宅基地

技术标签: Android Camera专项  Hal到驱动流程  

(1)架构介绍

(A)Camera的框架分为Kernel部分和Hal部分

Kernel部分:

  • image sensor driver——负责具体型号的sensor的id检测,上电,以及在preview、capture、初始化、3A等等功能设定时的寄存器配置;
  • ISP driver——通过DMA将sensor数据流上传;

Hal部分:

  • imageio——主要负责数据buffer上传的pipe;
  • drv——包含imgsensor和isp的hal层控制;
  • feature io——包含各种3A等性能配置;

来看一张图,大致来了解一下Camera的整体架构。

在这里插入图片描述
(B)MiddleWare(MW)层

  • ICameraProvider——向上暴露的接口调用,实现是在CameraProvider中;
  • [email protected]——用于Camera Service去操作各个Camera device的操作,实现在CameraDevice3中;
  • [email protected]——Camera会话的接口;
  • ICameraDeviceCallBack——底层对上层的CallBack接口;
  • CameraDeviceManager——用于管理CameraDevice,包括查找,打开,关闭等。

(C)Pipeline介绍

PipelineModel是HAL3核心架构,对上需要开放对Pipeline创建 / 操作的API,对下需要建立Pipeline / 管理Pipeline的生命周期。
PipelineModel会针对不同的场景创建不同的Pipeline和HWNode,HWNode向下传输APP层的命令,向上传递图形数据。

  • P1Node——pipeline的root node,input app命令,output raw data to P2CaptureNode and P2StreamNode;
  • P2CaptureNode——转换raw data to yuv,Support scale/crop;
  • P2StreamingNode——和P2CaptureNode功能类似;
  • JPEGNode——Convert YUV to Jpeg;
  • FDNode——Generate the FD information;

(2)Camera Open流程(Hal-Sensor)

在APP层调用openCamera后会调用的CameraDevice层,最后调用到driver中,整体的调用流程如下:

在这里插入图片描述
先从CameraDevice3SessionImpl的open函数分析。

//vendor/mediatek/proprietary/hardware/mtkcam3/main/hal/device/3.x/device/CameraDevice3SessionImpl.cpp

auto ThisNamespace::open(
    const ::android::sp<V3_4::ICameraDeviceCallback>& callback) -> ::android::status_t
{
    
    auto pDeviceManager = mStaticInfo.mDeviceManager;
    auto const& instanceName = mStaticInfo.mStaticDeviceInfo->mInstanceName;
     
    status = pDeviceManager->startOpenDevice(instanceName);
     
    err = onOpenLocked(callback);
    pDeviceManager->updatePowerOnDone();
    status = pDeviceManager->finishOpenDevice(instanceName, false/*cancel*/);
}
     
auto ThisNamespace::onOpenLocked(
    const ::android::sp<V3_4::ICameraDeviceCallback>& callback
) -> ::android::status_t
{
    
    //--------------------------------------------------------------------------
    {
    
        Mutex::Autolock _l(mPipelineModelLock);
        auto pPipelineModelMgr = IPipelineModelManager::get();
        auto pPipelineModel = pPipelineModelMgr->getPipelineModel( getInstanceId() );
        ::android::status_t err = OK;
        err = pPipelineModel->open(getInstanceName().c_str(), this);
        mPipelineModel = pPipelineModel;
    }
    //--------------------------------------------------------------------------
    return OK;
}
//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/model/PipelineModelImpl.cpp

auto PipelineModelImpl::open(
    std::string const& userName,
    android::wp<IPipelineModelCallback> const& callback) -> int
{
    
    {
    
        std::lock_guard<std::timed_mutex> _l(mLock);
        mUserName = userName;
        mCallback = callback;
        mvOpenFutures.push_back(
            std::async(std::launch::async,
                [this]() {
    
                    return CC_LIKELY( mHalDeviceAdapter!=nullptr )
                        && CC_LIKELY( mHalDeviceAdapter->open() ) 
                        //android::sp<IHalDeviceAdapter> const    mHalDeviceAdapter;
                        && CC_LIKELY( mHalDeviceAdapter->powerOn() );
                }
            )
        ); 
    }
    return OK;
}

调用mHalDeviceAdapter的open用于初始化DeviceAdapter,这里重点看powerOn函数,这里的powerOn有另起一个线程去操作sensor,等待sensor上电完成后对3A进行powerOn操作。

//vendor/mediatek/proprietary/hardware/mtkcam3/pipeline/model/adapter/HalDeviceAdapter.cpp

virtual auto powerOn() -> bool override
{
    
    //1.调用HalSensor的powerOn
    std::future<bool> future_initSensor =
        std::async(std::launch::async,
            [ this ]() {
    
                    if (CC_UNLIKELY( !mvHalSensor[i]->powerOn(mName.c_str(), 1, &sensorIndex) ))
        }
     
    //2.init 3A and poweron 3A
    bool success_sensorPowerOn = false;
    bool success_init3A = true;
    for (size_t i = 0; i < mvPhySensorId.size(); i++)
    {
    
        mvHal3A.push_back(IHal3AAdapter::create(mvPhySensorId[i], mName.c_str()));
        mvHalIsp.push_back(MAKE_HalISP(mvPhySensorId[i], mName.c_str()));
    }
     
    //3.Wait for Sensor PowerOn
    {
    
        success_sensorPowerOn = future_initSensor.get();
        if  ( ! success_sensorPowerOn ) {
    
            return false;
        }
    }
        
    //4.Notify 3A of Power On
    for (size_t i = 0; i < mvHal3A.size(); i++){
    
       if (mvHal3A[i] != nullptr){
    
           mvHal3A[i]->notifyPowerOn();
        }
    }
}

这里继续跟踪mvHalSensor[i]->powerOn,会调用到HalSensor.cpp中,这里到了和Driver交互的部分:

  • 初始化SeninfDrv和SensorDrv;
  • setSensorMclk和setSensorMclkDrivingCurrent;
  • 最后通过mpSensorDrv->open;
//vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensor.cpp
MBOOL HalSensor:: powerOn(){
    
     
    mpSeninfDrv->init();
    mpSensorDrv->init();
    for (MUINT i = 0; i < uCountOfIndex; i++)
    {
    
        setSensorMclk(sensorIdx, 1)
        setSensorMclkDrivingCurrent(sensorIdx)
     
        // Open sensor, try to open 3 time
        for (int i =0; i < 3; i++) {
    
            if ((ret = mpSensorDrv->open(sensorIdx)) != SENSOR_NO_ERROR) {
    
                MY_LOGE("pSensorDrv->open fail, retry = %d ", i);
            }
        }
    }
}

接下来会调用到imgsensor_drv的open函数,到此featureControl调用到驱动的SENSOR_FEATURE_OPEN。

//vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp
MINT32
ImgSensorDrv::open(IMGSENSOR_SENSOR_IDX sensorIdx)
{
    
    MUINT32                           featureParaLen = sizeof(MUINT32);
    MUINT32                           featurePara;

    return featureControl(sensorIdx, SENSOR_FEATURE_OPEN, (MUINT8 *)&featurePara, &featureParaLen);
}

MINT32  ImgSensorDrv::featureControl(
    IMGSENSOR_SENSOR_IDX sensorIdx,
    ACDK_SENSOR_FEATURE_ENUM FeatureId,
    MUINT8 *pFeaturePara,
    MUINT32 *pFeatureParaLen
)
{
    

	ACDK_SENSOR_FEATURECONTROL_STRUCT featureCtrl;
	
    //结构ACDK_SENSOR_FEATURECONTROL_STRUCT和kernel中一致
    featureCtrl.InvokeCamera = sensorIdx;
    featureCtrl.FeatureId = FeatureId;//SENSOR_FEATURE_SET_DRIVER
    featureCtrl.pFeaturePara = pFeaturePara;
    featureCtrl.pFeatureParaLen = pFeatureParaLen;
    	
    if (ioctl(m_fdSensor, KDIMGSENSORIOC_X_FEATURECONCTROL , &featureCtrl) < 0) {
    
    	LOG_ERR("[featureControl] Err-ctrlCode (%s)", strerror(errno));
        return -errno;
    }
  	
    return SENSOR_NO_ERROR;
}

(3)Sensor Search流程

CameraService是在开机时启动的,启动后进行searchSensor的操作,会search系统有多少camera,开机时的search操作,只进行camera支持数量的遍历,以及sensor ID的读取操作。

HalSensorList:
vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.enumList.cpp
vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.cpp

SeninfDrv:
vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/mt6765/seninf_drv.cpp

SensorDrv:
vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp

在这里插入图片描述

//vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.cpp

MUINT
HalSensorList::
searchSensors()
{
    
    Mutex::Autolock _l(mEnumSensorMutex);

    MY_LOGD("searchSensors");
    return  enumerateSensor_Locked();
}

MUINT
HalSensorList::
queryNumberOfSensors() const
{
    
    Mutex::Autolock _l(mEnumSensorMutex);

    return  mEnumSensorList.size();
}

IMetadata const&
HalSensorList::
queryStaticInfo(MUINT const index) const
{
    
    EnumInfo const* pInfo = queryEnumInfoByIndex(index);
    MY_LOGF_IF(pInfo==NULL, "NULL EnumInfo for sensor %d", index);

    return  pInfo->mMetadata;
}

searchSensors()会调用enumerateSensor_Locked()。

//vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/HalSensorList.enumList.cpp

MUINT HalSensorList::enumerateSensor_Locked()
{
    
    SensorDrv *const pSensorDrv = SensorDrv::get();
    SeninfDrv *const pSeninfDrv = SeninfDrv::createInstance();
    //初始化seninf,配置ISP相关内容
    pSeninfDrv->init();
     
    //将所有的clk全部打开
    pSeninfDrv->setAllMclkOnOff(ISP_DRIVING_8MA, TRUE);
        
    pSensorDrv->init();
    for (MUINT i = IMGSENSOR_SENSOR_IDX_MIN_NUM; i <= max_index_of_camera; i++) {
    
        if((ret = pSensorDrv->searchSensor((IMGSENSOR_SENSOR_IDX)i)) == SENSOR_NO_ERROR){
    
            //query sensorinfo
           querySensorDrvInfo((IMGSENSOR_SENSOR_IDX)i);
           //fill in metadata
           buildSensorMetadata((IMGSENSOR_SENSOR_IDX)i);
           pSensorInfo = pSensorDrv->getSensorInfo((IMGSENSOR_SENSOR_IDX)i);
           addAndInitSensorEnumInfo_Locked(
                (IMGSENSOR_SENSOR_IDX)i,
                mapToSensorType(pSensorInfo->GetType()),
                pSensorInfo->getDrvMacroName());
        }
    }     
}

下面看下pSensorDrv->getSensorInfo的流程,这里有去获取sensorList的内容。

//vendor/mediatek/proprietary/hardware/mtkcam/drv/src/sensor/common/v1/imgsensor_drv.cpp
MINT32 ImgSensorDrv::searchSensor(IMGSENSOR_SENSOR_IDX sensorIdx)
{
    
    GetSensorInitFuncList(&pSensorInitFunc);
     
    featureControl(sensorIdx, SENSOR_FEATURE_SET_DRIVER, (MUINT8 *)&idx, &featureParaLen);
     
    NSFeature::SensorInfoBase* pSensorInfo = pSensorInitFunc[idx].pSensorInfo;
}

(A)GetSensorInitFuncList是获取到配置的sensorList的内容,此sensorList需要与kernel层配置的一致,不一致的话在打开camera时会出现异常。

//vendor/mediatek/proprietary/custom/mtxxxx/hal/imgsensor_src/sensorlist.cpp

MSDK_SENSOR_INIT_FUNCTION_STRUCT SensorList[] =
{
    
/*IMX*/
#if defined(IMX586_MIPI_RAW)
    RAW_INFO_M(IMX586_SENSOR_ID, DEFAULT_MODULE_INDEX, DEFAULT_MODULE_ID, SENSOR_DRVNAME_IMX586_MIPI_RAW, CAM_CALGetCalData),
#endif
#if defined(IMX519_MIPI_RAW)
    RAW_INFO_M(IMX519_SENSOR_ID, DEFAULT_MODULE_INDEX, DEFAULT_MODULE_ID, SENSOR_DRVNAME_IMX519_MIPI_RAW, CAM_CALGetCalData),
#endif
//...
};

UINT32 GetSensorInitFuncList(MSDK_SENSOR_INIT_FUNCTION_STRUCT **ppSensorList)
{
    
    if (NULL == ppSensorList) {
    
        ALOGE("ERROR: NULL pSensorList\n");
        return MHAL_UNKNOWN_ERROR;
    }
    *ppSensorList = &SensorList[0];
	return MHAL_NO_ERROR;
}

(B)featureControl的setDriver流程同上面的一致。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dongxianfei/article/details/121382327

智能推荐

基于单片机的加热炉炉温控制系统设计-程序员宅基地

文章浏览阅读3.5k次,点赞7次,收藏41次。但由于输出控制量只有两种状态,使被控参数在两个方向上变化的速率均为最大,因此容易引起反馈回路产生振荡,对自动控制加热炉炉温控制系统会产生十分不利的影响,甚至会因为输出开关的频繁动作而不能满足加热炉炉温控制系统对控制精度的要求。但随着计算机与超大规模集成电路的迅速发展,以现代控制理论和计算机为基础,采用数字控制、显示、A/D与D/A转换,配合执行器与控制阀构成的计算机控制加热炉炉温控制系统,在过程控制过程中得到越来越广泛的应用。由于炉温控制加热炉炉温控制系统的控制对象具有惯性大,连续性的特点。_基于单片机的加热炉炉温控制系统设计

Oracle-----约束简介&非空约束&唯一约束&主键约束-程序员宅基地

文章浏览阅读2.1k次,点赞2次,收藏4次。上一篇????:Oracle-----为表重命名&数据表删除&闪回技术&修改表结构文章目录1、约束简介2、非空约束(not null、nk)2.1 范例1:使用非空约束2.2 范例2:正确地增加语句2.3 范例3:错误地增加语句3、唯一约束(unique、uk)3.1 范例1:使用唯一约束3.2 范例2:正确地增加语句3.3 范例3:错误地增加语句3.4 范例4:查询user...

CamVid数据集(智能驾驶场景的语义分割)_camvid数据集11类别-程序员宅基地

文章浏览阅读3.3k次,点赞2次,收藏7次。前言CamVid 数据集是由剑桥大学公开发布的城市道路场景的数据集。CamVid全称:The Cambridge-driving Labeled Video Database,它是第一个具有目标类别语义标签的视频集合。数据集包 括 700 多张精准标注的图片用于强监督学习,可分为训练集、验证集、测试集。同时, 在 CamVid 数据集中通常使用 11 种常用的类别来进行分割精度的评估,分别为:道路 (Road)、交通标志(Symbol)、汽车(Car)、天空(Sky)、行人道(Sidewalk)、电_camvid数据集11类别

ESP32 LVGL8.1 实现太空人显示(29)_lv_img_declare-程序员宅基地

文章浏览阅读8.7k次,点赞11次,收藏90次。文章目录一、ESP32 LVGL工程配置1.1从库中下载LVGL代码1.2配置适合ESP32 液晶屏1.3编译下载测试二、GIF图片处理2.1下载gif图片2.2将gif图片按照帧率导出成图片2.lvgl animimg对象实现图片的播放1.3下载测试 注:本博客作为学习笔记,有错误的地方希望指正一、ESP32 LVGL工程配置首先要通过液晶屏显示太空人,我们这里主要有两种方式可以实现,第一种直接使用厂家只带的液晶屏幕驱动去实现图片的显示,另外使用其他的GUI提供的控件去实现,嵌入式常见的GUI挺多_lv_img_declare

最小权顶点覆盖问题-程序员宅基地

文章浏览阅读1.5w次,点赞7次,收藏30次。问题描述:给定一个赋权无向图G=(V,E),每个顶点v∈V都有一个权值w(v)。如果UV,且对任意(u,v)∈E有u∈U或v∈U,就称U为图G的一个顶点覆盖。G的最小权顶点覆盖是指G中所含顶点权之和最小的顶点覆盖。问题解决:用优先队列分支限界方法解最小权顶点覆盖,在算法的搜索的进程中保存当前已构造出的部分解空间树,在算法搜索达到叶节点时,其最优值对应的最优解同时保存下来。优先队列的优先_最小权顶点覆盖

matlab如何导入map,matlab添加M_map工具箱-程序员宅基地

文章浏览阅读517次。首先试了matlab自带的worldmap,感觉画出来的图形不尽如人意,比较杂乱。如下图。查阅了些资料,请教了Liangjing,一致推荐m_map。为了达到想要的效果,这次只要不再偷懒,下载M-Map工具箱(http://www.eos.ubc.ca/~rich/map.html)并进行安装。所幸过程比较顺利,现记录如下,回头把画出的效果图再添上。其他matlab的toolbox安装,也可参考进..._mmap工具包如何安装

随便推点

Boost中ASIO的一些用法-定时器_boost asio不编译可以用吗-程序员宅基地

文章浏览阅读2.1k次。一、介绍ASIO,基于操作系统的异步机制,可有效避免多线程编程的诸多副作用。目前主要关注于通信方面,使用大量的类封装了socket,提供更高层次的接口二、使用不需要编译,默认不支持SSL,要支持的话需要自己编译OpenSSL。三、用法Sample1、定时器#include #include #include using namespace bo_boost asio不编译可以用吗

c语言编程实现strlen,C语言::模拟实现strlen函数(示例代码)-程序员宅基地

文章浏览阅读750次。编写一个C语言程序模拟实现strlen函数.算法strlen函数功能是计算字符串中字符的个数.(除\0外)而字符串本身就是一个字符数组,只不过末尾以\0结束.因此,我们只需遍历除\0之外的所有字符即可.有三种方法可以解决这个问题.算法总结方法一:设置一个整型计数器,遍历字符串.方法二:通过不断函数自身的递归.方法三:与方法一类似,设置一个char*变量标记字符串尾部,通过指针相减得到字符长度.核心..._c语言实现strlen

P74-前端基础项目开发-首页main部分开发广告栏-项目完整代码_首页广告开发-程序员宅基地

文章浏览阅读904次。P74-前端基础项目开发-首页main部分开发广告栏-项目完整代码1.概述这篇文章是首页开发最后一个部分,也是这个项目的结束部分。通过这个项目练习让我们掌握了HTML+CSS的基础使用。2.广告栏2.1.广告栏需求样式2.2.创建广告栏内容在index.html文件中创建广告栏内容 <!-- 创建广告容器 --> <div class="ad w"> <ul class="shortcut"> <li> _首页广告开发

TS流结构图_现代电视技术中解析ts包头的工作流程图-程序员宅基地

文章浏览阅读2k次。该说真正了解TS,还是看了朋友推荐的《数字电视业务信息及其编码》一书之后,MPEG2 TS和数字电视是紧密不可分割的,值得总结一下其中的一些关系。ISO/IEC-13818-1:系统部分;ISO/IEC-13818-2:视频;ISO/IEC-13818-3:音频;ISO/IEC-13818-4:一致性测试;ISO/IEC-13818-5:软件部分;ISO/IEC-138_现代电视技术中解析ts包头的工作流程图

android 添加依赖出现Failed to resolve:"你添加的依赖名" 或者出现 debug@Compileclasspath问题_android failed to resolve: com.github.xiaohaibin:x-程序员宅基地

文章浏览阅读4.8w次,点赞11次,收藏16次。首先出现的问题是debug@Compileclasspath的问题,经过一波百度之后都说是AS build.gradle版本3.0以上的问题,但是经过一波修改之后并没有什么卵用,并没有解决这个问题,并且出现了新的问题,就是Failed to resolve:.......这个问题了,这面贴下终极解决方案,希望可以帮到你。问题截图:解决方案:在整个工程的build.gradle中添加以..._android failed to resolve: com.github.xiaohaibin:xbanner:1.8.9

php路由类默认模块,Laravel学习教程之路由模块-程序员宅基地

文章浏览阅读169次。前言本文主要给大家介绍的是关于Laravel路由模块的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。备注:本文是基于Laravel 5.4版本的路由模块代码进行分析书写;模块组成下图展示了路由模块中各个文件的关系,并进行简要说明;剖析服务提供者看Laravel模块,首先找ServiceProvider文件,这是模块与IOC容器交互的入口,从这个文件,可以看出该模块提供向..._symfony app('router')->getcurrentrequest()

推荐文章

热门文章

相关标签