【无标题】

前言

在openharmony系统中,camera-HDF有逻辑ID和物理ID的概念。

逻辑ID:对上报给框架层并最终报给应用层,UI能识别调用的逻辑设备ID。

最终cameraUI会以逻辑设备ID为操作粒度。

物理ID:对下与硬件打交道的ID。

每新增一个可用设备节点就会对应一个hardwareName。

1个物理ID有可能对应几个不同用途的硬件,目前只用到了sensor硬件。

因此常规情况下的映射关系:

设备节点(/dev/video) -> hardwareName-> 物理ID(CAMERA_FIRST) ->逻辑ID(lcam001)

比如板载设备就会提前映射这种关系。

左边那个是物理ID,右边是hardwareName,最终通过hardwareName找到设备节点 。

上章提到过有个HosV4L2Dev::deviceMatch表,就是负责检测并映射hardwareName和设备节点的。

那么物理ID和逻辑ID如何映射?在HCS文件(camera_host_config.hcs)中

        ability_01 :: ability {
            logicCameraId = "lcam001";
            physicsCameraIds = [
                "CAMERA_FIRST"
            ];

在camera-HDF初始化时,CameraHostImpl::Init会调用CameraHostConfig::GetInstance。

CameraHostConfig *CameraHostConfig::GetInstance()
{
    if (instance_ == nullptr) {
        instance_ = new (std::nothrow) CameraHostConfig();
        if (instance_ != nullptr) {
            instance_->ReadConfigFile();
        }

ReadConfigFile就会读取camera_host_config.hcb(由camera_host_config.hcs生成)。

最终存储在cameraIdMap_表中,这个表就是逻辑ID与物理ID映射表。

当框架层查询时会上报此表中的所有逻辑ID,最终上层能获取到的也是逻辑ID。后续UI界面就是对这些逻辑ID来进行操作,最终一步步的映射成设备节点的操作到内核驱动层。

上面是板载的预制场景,本章就是介绍USB设备插入后如何建立这些映射的。

UvcCallBack

上章提到,当从硬件中读取到需要的信息后,会通过回调函数传递到V4L2DeviceManager。

void V4L2DeviceManager::UvcCallBack(const std::string hardwareName, std::vector<DeviceControl>& deviceControl,
    std::vector<DeviceFormat>& deviceFormat, bool uvcState)
{
        //生成新的物理ID
        CameraId id = ReturnEnableCameraId("");
        //创建SENSOR的Controller
        RetCode rc = GetManager(DM_M_SENSOR)->CreateController(DM_C_SENSOR, hardwareName);

        //添加到物理ID-驱动name映射表
        HardwareConfiguration hardware;
        hardware.cameraId = id;
        hardware.managerId = DM_M_SENSOR;
        hardware.controllerId = DM_C_SENSOR;
        hardware.hardwareName = hardwareName;
        hardwareList_.push_back(hardware);

        //创建meta数据
        std::shared_ptr<CameraMetadata> meta = std::make_shared<CameraMetadata>(ITEM_CAPACITY_SIZE,
            DATA_CAPACITY_SIZE);
        meta->addEntry(OHOS_SENSOR_INFO_PHYSICAL_SIZE, physicalSize.data(), physicalSize.size());
        Convert(deviceControl, deviceFormat, meta);
        CHECK_IF_PTR_NULL_RETURN_VOID(uvcCb_);
        //回调
        uvcCb_(meta, uvcState, id);

生成物理ID

从CAMERA_FIRST开始往CAMERA_MAX找,如果在hardwareList_表中就表示被板载或者其他USB camera设备占了,最终找到一个没有被使用的物理ID。

hardwareList_表不仅存储了物理ID与hardwareName的映射关系,还有器件类型的ID。目前只使用了sensor,另外还有isp和flash。(当前业务没用到后面研究)

同时还根据驱动name创建了1个controller,后续对设备节点的操作都是通过这个controller来操作的。

加入hardwareList_

V4L2DeviceManager::Init初始化时会根据project_hardware.h文件生成一个表hardwareList_。之后根据这个表创建3个manager对象,用于管理3种器件。

RetCode V4L2DeviceManager::CreateManager()
{
    RetCode rc = RC_OK;
    std::shared_ptr<IManager> manager = nullptr;
    for (auto iter = hardwareList_.cbegin(); iter != hardwareList_.cend(); iter++) {
        if (CheckManagerList((*iter).managerId) == false) {
            switch ((*iter).managerId) {
                case DM_M_SENSOR:
                    manager = std::make_shared<SensorManager>(DM_M_SENSOR);
                    CHECK_IF_PTR_NULL_RETURN_VALUE(manager, RC_ERROR);
                    rc = CreateController((*iter).cameraId, manager, DM_M_SENSOR);
                    break;
                case DM_M_FLASH:
                    manager = std::make_shared<FlashManager>(DM_M_FLASH);
                    CHECK_IF_PTR_NULL_RETURN_VALUE(manager, RC_ERROR);
                    rc = CreateController((*iter).cameraId, manager, DM_M_FLASH);
                    break;
                case DM_M_ISP:
                    manager = std::make_shared<IspManager>(DM_M_ISP);
                    CHECK_IF_PTR_NULL_RETURN_VALUE(manager, RC_ERROR);
                    rc = CreateController((*iter).cameraId, manager, DM_M_ISP);
                    break;

·每个器件的manager创建后还会调用CreateController创建相应的控制器

RetCode V4L2DeviceManager::CreateController(CameraId cameraId, std::shared_ptr<IManager> manager, ManagerId managerId)
{
    RetCode rc = RC_OK;
    (void)cameraId;
    for (auto iter = hardwareList_.cbegin(); iter != hardwareList_.cend(); iter++) {
        if ((*iter).managerId == managerId) {
            switch (managerId) {
                case DM_M_SENSOR:
                    rc = manager->CreateController((*iter).controllerId, (*iter).hardwareName);
                    break;
                case DM_M_FLASH:
                    rc = manager->CreateController((*iter).controllerId, (*iter).hardwareName);
                    break;
                case DM_M_ISP:
                    rc = manager->CreateController((*iter).controllerId, (*iter).hardwareName);

初始化时创建的Controller其实是板载预置的,也就是之前介绍过的project_hardware.h文件。

而热插拔的USB设备节点也需要创建1个Controller,就是在生成物理ID后,通过传递过来的hardwareName创建的。

void V4L2DeviceManager::UvcCallBack(const std::string hardwareName, std::vector<DeviceControl>& deviceControl,
    std::vector<DeviceFormat>& deviceFormat, bool uvcState)
{
    if (uvcState) {
        CAMERA_LOGI("V4L2DeviceManager uvc plug in %{public}s begin", hardwareName.c_str());
        CameraId id = ReturnEnableCameraId("");
        CHECK_IF_EQUAL_RETURN_VOID(id, CAMERA_MAX);

        RetCode rc = GetManager(DM_M_SENSOR)->CreateController(DM_C_SENSOR, hardwareName);

最终将相关信息加入hardwareList_表。

        hardware.cameraId = id;
        hardware.managerId = DM_M_SENSOR;
        hardware.controllerId = DM_C_SENSOR;
        hardware.hardwareName = hardwareName;
        hardwareList_.push_back(hardware);

CameraMetadata

每个camera设备会设置一些属性,比如设备连接类型(是板载还是USB的)、分辨率、帧率等等。板载设备是通过HDF层的设备树预置的,也是之前介绍过的camera_host_config.hcs。

USB设备没有预置的,因此需要自动生成一个。

std::shared_ptr<CameraMetadata> meta = std::make_shared<CameraMetadata>(ITEM_CAPACITY_SIZE,
            DATA_CAPACITY_SIZE);

至于数据如何填充,目前我的方案就是在HCS文件中建立一个USB模板,每次新增设备就拷贝一个用于当前设备的实例,然后将从设备种查询并传递过来的控制信息、视频格式写入到metadata实例。

通过硬件设备填充数据就不说了,通过模板数据填充其他域就往上到了hostService模块了。

HostService模块

hdi_impl:camera_host_service_1.0这个模块就是cameraHDF对上提供服务的模块。

hdf_config\uhdf\device_info.hcs
        hdi_server :: host {
            hostName = "camera_host";
            priority = 50;
            gid = ["camera_host", "uhdf_driver", "vendor_mpp_driver"];
            camera_device :: device {
                 device0 :: deviceNode {
                     policy = 2;
                     priority = 100;
                     moduleName = "libcamera_host_service_1.0.z.so";
                     serviceName = "camera_service";

框架层获取camera_service时,获取到的就是CameraHostImpl的远程调用。

上面提过CameraHostImpl初始化时会调用CameraHostConfig::GetInstance从HCS文件中加载板载camera的信息(逻辑物理ID映射关系和metadata)。除此之外还会注册一个热插拔回调

    deviceManager->SetHotplugDevCallBack([this](const std::shared_ptr<CameraAbility> &meta,
        const bool &status, const CameraId &cameraId) {
            CameraStatus cameraStatus = status ? AVAILABLE : UN_AVAILABLE;
            OnCameraStatus(cameraId, cameraStatus, meta);

这里的deviceManager就是V4L2DeviceManager。V4L2DeviceManager在UvcCallBack中最后的

回调uvcCb_就到了CameraHostImpl的OnCameraStatus。

        std::string logicalCameraId = config->ReturnEnableLogicalCameraId();
        config->AddUsbCameraId(logicalCameraId);
        RetCode rc = config->AddCameraId(logicalCameraId, physicalCameraIds, ability);
        if (rc == RC_OK && logicalCameraId.size() > 0) {
            CAMERA_LOGI("add physicalCameraIds %{public}d logicalCameraId %{public}s",
                static_cast<int>(cameraId), logicalCameraId.c_str());
            if (cameraHostCallback_ != nullptr) {
                cameraHostCallback_->OnCameraStatus(logicalCameraId, status);
            }
        }
        std::shared_ptr<CameraDeviceImpl> cameraDevice =
            CameraDeviceImpl::CreateCameraDevice(logicalCameraId);
        if (cameraDevice != nullptr) {
            cameraDeviceMap_[logicalCameraId] = cameraDevice;
        }

第一步就是生成最新的逻辑ID,可以看到都是以lcam00开头的

std::string CameraHostConfig::ReturnEnableLogicalCameraId()
{
    for (int32_t id = 1; id < CAMERA_MAX+1; id++) {
        logicalCameraId = "lcam00";
        logicalCameraId = logicalCameraId + std::to_string(id);
}

所以板载预置也都用lcam00x的逻辑ID,保持队列,分析问题也方便。

第二步就是将逻辑ID加入USB表中,因为后续创建流时板载走的节点和usb的不同需要区分出来。

void CameraHostConfig::AddUsbCameraId(std::string cameraId)
{
     usbCameraIdVector_.push_back(cameraId);
}

然后将逻辑ID和物理ID映射加入cameraIdMap_表。

RetCode CameraHostConfig::AddCameraId(const std::string &logicalCameraId,
    const std::vector<std::string> &physicalCameraIds, const std::shared_ptr<CameraAbility> ability)
{
    ...
        if(GetCameraAbility("lcamusb", abilitytemplate) == RC_OK){
            abilityNew = std::make_shared<CameraMetadata>(ITEM_CAPACITY_SIZE, DATA_CAPACITY_SIZE);
            CopyCameraMetadataItems(abilityNew->get(), abilitytemplate->get());
            mergMeta(abilityNew->get(), ability->get());
            }
        cameraIdMap_.insert(std::make_pair(logicalCameraId, physicalCameraIds));
        cameraAbilityMap_.insert(std::make_pair(logicalCameraId, abilityNew!=NULL?abilityNew:ability));
    ...
}

这里注意了,我之前提过的metadata数据逻辑在这。

先把HCS中预置的usb模板metadata数据拷贝一份,然后将我们之前从硬件获取的meta数据合并过去,这样就形成了一份此硬件对应的metadata数据并加入cameraAbilityMap_表。

最后针对这个逻辑ID创建一个CameraDeviceImpl实例放入cameraDeviceMap_表中。

总结

上述流程主要是生成了一个物理ID和逻辑ID并把对应关系加入表中方便后续查询。

在devicemanager层创建了一个sensorcontroller(对于hardwarename)便于后续操作设备文件。

在hostservice层创建了一个CameraDeviceImpl(对应逻辑ID)给上层设备调用提供实例。

最后还自动为此设备填充了metadata数据作为参数以便后续使用。

至此在HDF-camera中USB设备插入初始化流程结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值