OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化 原创 精华

NL_AIDC_Ryanzx
发布于 2022-1-4 14:03
浏览
3收藏

OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化

说明

  • 解析源码基于 OpenHarmony-v3.0-LTS 版本,代码结构和部分源码与当前维护的主线分支有差别。
  • 解析示例代码 drivers\peripheral\camera\hal\init\demo_main.cpp

1. 简介

HarmonyOS 相机驱动框架模型对上实现相机HDI接口,对下实现相机Pipeline模型,管理相机各个硬件设备。
各层的基本概念如下:

  • HDI实现层,对上实现OHOS相机标准南向接口。
  • 框架层,对接HDI实现层的控制、流的转发,实现数据通路的搭建、管理相机各个硬件设备等功能。
  • 适配层,屏蔽底层芯片和OS差异,支持多平台适配。

2. 框架图

OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化-鸿蒙开发者社区

3. 代码结构

drivers\peripheral\camera
├── hal
│   ├── adapter                //芯片和平台适配层 
│   ├── buffer_manager         //buffer管理
│   ├── device_manager         //设备控制接口定义
│   ├── hdi_impl               //HDI Implementation实现
│   │   ├── include
│   │   ├── src
│   │   │   ├── camera_device              //Device
│   │   │   ├── camera_host                //Host
│   │   │   ├── offline_stream_operator    //OffineStreamOperator
│   │   │   └── stream_operator            //StreamOperator
│   │   └── test
│   ├── include
│   ├── init                                //HiSpark 3516 demo 代码
│   ├── pipeline_core                       
│   │   ├── host_stream
│   │   │   ├── include
│   │   │   └── src
│   │   ├── include
│   │   ├── ipp                            //ipp
│   │   │   ├── include
│   │   │   └── src
│   │   ├── nodes                          //基础通用node
│   │   │   ├── include
│   │   │   └── src
│   │   │       ├── dummy_node
│   │   │       ├── fork_node
│   │   │       ├── merge_node
│   │   │       ├── node_base
│   │   │       ├── sensor_node
│   │   │       ├── sink_node
│   │   │       ├── source_node
│   │   │       └── transform_node
│   │   ├── pipeline_impl                //pipeline构建实现
│   │   │   ├── include
│   │   │   └── src
│   │   │       ├── builder
│   │   │       ├── dispatcher
│   │   │       ├── parser
│   │   │       └── strategy
│   │   │           └── config
│   │   ├── src                          //PipelineCore
│   │   └── utils
├── hal_c                                //hal层 C实现接口
│   ├── hdi_cif
│   │   ├── include
│   │   └── src
│   └── include
└── interfaces                            //Camera Host框架HDI接口
    └── include                           
        ├── callback                      //框架涉及的所有callback接口
        │   ├── device
        │   ├── host
        │   └── operator
        ├── client
        └── server


4. 源码解析

上层demo代码相对简单,这里只贴出关键部分代码

int main(int argc, char** argv)
{
    RetCode rc = RC_OK;

    auto mainDemo = std::make_shared<Hos3516Demo>();
    rc = mainDemo->InitSensors();
    if (rc == RC_ERROR) {
        CAMERA_LOGE("main test: mainDemo->InitSensors() error\n");
        return -1;
    }
    rc = mainDemo->InitCameraDevice();
    if (rc == RC_ERROR) {
        CAMERA_LOGE("main test: mainDemo->InitCameraDevice() error\n");
        return -1;
    }

    ......

    return RC_OK;
}

4.1 Hos3516Demo::InitSensors()

4.1.1 上层代码

上层获取HDI层的ICameraHost:设备管理接口,并设置Host层的回调。

constexpr const char *DEMO_SERVICE_NAME = "camera_service";

RetCode Hos3516Demo::InitSensors()
{
    int rc = 0;

    CAMERA_LOGD("demo test: InitSensors enter");

    if (demoCameraHost_ != nullptr) {
        return RC_OK;
    }

    demoCameraHost_ = ICameraHost::Get(DEMO_SERVICE_NAME);
    if (demoCameraHost_ == nullptr) {
        CAMERA_LOGE("demo test: ICameraHost::Get error");
        return RC_ERROR;
    }

    hostCallback_ = new CameraHostCallback();
    rc = demoCameraHost_->SetCallback(hostCallback_);
    if (rc != Camera::NO_ERROR) {
        CAMERA_LOGE("demo test: demoCameraHost_->SetCallback(hostCallback_) error");
        return RC_ERROR;
    }

    CAMERA_LOGD("demo test: InitSensors exit");

    return RC_OK;
}

4.1.2 时序图

OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化-鸿蒙开发者社区

  1. CameraHostProxy 提供上层调用的代理接口。
  2. CameraHostStub 提供对应代理接口的HDI层的 ‘桩’。
  3. CameraHostImpl 是接口层的具体实现。
    Proxy-Stub 负责上下接口参数的数据转换等工作。

4.1.3 ICameraHost::Get(const char *serviceName)

从ServiceManager中取出CameraHostProxy。并返回ICameraHost接口类指针

//drivers\peripheral\camera\interfaces\include\client\camera_host_proxy.cpp
sptr<ICameraHost> ICameraHost::Get(const char *serviceName)
{
    do {
        using namespace OHOS::HDI::ServiceManager::V1_0;
        auto servMgr = IServiceManager::Get();
        if (servMgr == nullptr) {
            HDF_LOGE("%s: IServiceManager failed!", __func__);
            break;
        }

        auto remote = servMgr->GetService(serviceName);
        if (remote != nullptr) {
            sptr<CameraHostProxy> hostSptr = iface_cast<CameraHostProxy>(remote);
            return hostSptr;
        }
        HDF_LOGE("%s: GetService failed! serviceName = %s", __func__, serviceName);
    } while(false);

    HDF_LOGE("%s: get %s failed!", __func__, serviceName);
    return nullptr;
}

4.1.4 CameraHostProxy::SetCallback(const OHOS::sptr<ICameraHostCallback> &callback)

ICameraHostCallback 回调接口类定义了下面两个回调接口,在CameraHostCallback类中具体实现并通过IPC通讯最终设置到CameraHostImpl

virtual void OnCameraStatus(const std::string &cameraId, CameraStatus status) = 0;
virtual void OnFlashlightStatus(const std::string &cameraId, FlashlightStatus status) = 0;

client::host_proxy发起IPC —> server::host_service_stub
注意 这里有个坑! 通常 SendRequest() 和 OnRemoteRequest() 是一对。sendRequest()在client::XXX_proxy调用,OnRemoteRequest() 在server::XXX_stub调用。但是CamereaHost 的OnRemoteRequest是由 HDF中的 HdfCameraService来接收 通过Dispatch接口再调用具体的CameraHostStub!!
这里的proxy和stub 的cmdID 宏定义名字不一样,不太利于代码阅读。

//drivers\peripheral\camera\interfaces\include\client\camera_host_proxy.cpp
CamRetCode CameraHostProxy::SetCallback(const OHOS::sptr<ICameraHostCallback> &callback)
{
    ......

    int32_t ret = Remote()->SendRequest(CMD_CAMERA_HOST_REMOTE_SET_CALLBACK, data, reply, option);

    ......

    return static_cast<CamRetCode>(reply.ReadInt32());
}
//drivers\peripheral\camera\interfaces\include\server\camera_host_service_stub.cpp
int32_t CameraHostStub::CameraHostStubSetCallback(
    MessageParcel &data, MessageParcel &reply, MessageOption &option)
{
    bool flag = data.ReadBool();
    sptr<ICameraHostCallback> hostCallback = nullptr;
    if (flag) {
        sptr<IRemoteObject> remoteObj = data.ReadRemoteObject();
        hostCallback = OHOS::iface_cast<ICameraHostCallback>(remoteObj);
    }
    CamRetCode ret = cameraHost_->SetCallback(hostCallback);
    if (!reply.WriteInt32(static_cast<int32_t>(ret))) {
        HDF_LOGE("%s: write retcode failed", __func__);
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

最终调用到HDI 接口层的camera_host 完成callback的设置。

//drivers\peripheral\camera\hal\hdi_impl\src\camera_host\camera_host_impl.cpp
/**
 * @brief 设置Host回调函数
 *
 * @param callback Host回调函数
 * @return CamRetCode
 */
CamRetCode CameraHostImpl::SetCallback(const OHOS::sptr<ICameraHostCallback> &callback)
{
    DFX_LOCAL_HITRACE_BEGIN;

    if (callback == nullptr) {
        CAMERA_LOGW("host callback is null.");
        return INVALID_ARGUMENT;
    }

    cameraHostCallback_ = callback;

    DFX_LOCAL_HITRACE_END;
    return NO_ERROR;
}

4.2 Hos3516Demo::InitCameraDevice()

4.2.1 上层代码

获取CameraIds 、获取默认前置的摄像头设备的ability、创建CameraDeviceCallbak 并OpenCamera

RetCode Hos3516Demo::InitCameraDevice()
{
    int rc = 0;

    CAMERA_LOGD("demo test: InitCameraDevice enter");

    if (demoCameraHost_ == nullptr) {
        CAMERA_LOGE("demo test: InitCameraDevice demoCameraHost_ == nullptr");
        return RC_ERROR;
    }

    (void)demoCameraHost_->GetCameraIds(cameraIds_);
    if (cameraIds_.empty()) {
        return RC_ERROR;
    }
    const std::string cameraId = cameraIds_.front();
    demoCameraHost_->GetCameraAbility(cameraId, ability_);

    sptr<CameraDeviceCallback> callback = new CameraDeviceCallback();
    rc = demoCameraHost_->OpenCamera(cameraIds_.front(), callback, demoCameraDevice_);
    if (rc != Camera::NO_ERROR || demoCameraDevice_ == nullptr) {
        CAMERA_LOGE("demo test: InitCameraDevice OpenCamera failed");
        return RC_ERROR;
    }

    CAMERA_LOGD("demo test: InitCameraDevice exit");

    return RC_OK;
}

4.2.2 时序图

OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化-鸿蒙开发者社区

4.2.3 GetCameraIds()和GetCameraAblilty()

先来看下两个简单的设备信息获取接口。

获取系统配置中的cameraIds和CameraAbility
IPC 的过程和setcallback一样 此处 略去 IPC相关代码和时序图
直接看实现CameraHostImpl::GetCameraIds() 和 CameraHostImpl::GetCameraAbility(),调用了CameraHostConfig::GetCameraIds()和CameraHostConfig::GetCameraAbility()

、、drivers\peripheral\camera\hal\hdi_impl\src\camera_host\camera_host_impl.cpp
/**
 * @brief 获取当前可用的Camera设备列表
 *
 * @param ids 返回的当前可用的设备列表
 */
CamRetCode CameraHostImpl::GetCameraIds(std::vector<std::string> &cameraIds)
{
    DFX_LOCAL_HITRACE_BEGIN;

    CameraHostConfig *config = CameraHostConfig::GetInstance();
    if (config == nullptr) {
        return INVALID_ARGUMENT;
    }
    RetCode rc = config->GetCameraIds(cameraIds);
    if (rc != RC_OK) {
        return INVALID_ARGUMENT;
    }

    DFX_LOCAL_HITRACE_END;
    return NO_ERROR;
}
/**
 * @brief 获取Camera的能力集
 *
 * @param cameraId 要获取的Camera设备id
 * @param ability Camera设备的能力集
 * @return CamRetCode
 * @see CameraAbility
 */
CamRetCode CameraHostImpl::GetCameraAbility(const std::string &cameraId,
    std::shared_ptr<CameraAbility> &ability)
{
    DFX_LOCAL_HITRACE_BEGIN;
    CameraHostConfig *config = CameraHostConfig::GetInstance();
    if (config == nullptr) {
        return INVALID_ARGUMENT;
    }
    RetCode rc = config->GetCameraAbility(cameraId, ability);
    if (rc != RC_OK) {
        return INVALID_ARGUMENT;
    }
    DFX_LOCAL_HITRACE_END;
    return NO_ERROR;
}

CameraHostConfig负责从camera_host_config.hcb文件读出设备驱动信息。

//drivers\peripheral\camera\hal\hdi_impl\src\camera_host\camera_host_config.cpp
RetCode CameraHostConfig::ReadConfigFile()
{
    std::unique_ptr<HcsDeal> hcsDeal = std::make_unique<HcsDeal>(CONFIG_PATH_NAME);
    if (hcsDeal == nullptr) {
        CAMERA_LOGE("make HcsDeal failed. [pathname = %{public}s]", CONFIG_PATH_NAME.c_str());
        return RC_ERROR;
    }

    RetCode rc = hcsDeal->Init();
    if (rc != RC_OK) {
        CAMERA_LOGE("hcs deal init failed. [pathname = %{public}s]", CONFIG_PATH_NAME.c_str());
        return rc;
    }

    rc = hcsDeal->GetCameraId(cameraIdMap_);
    if (rc != RC_OK || cameraIdMap_.empty()) {
        CAMERA_LOGE("config camera id not found. [pathname = %{public}s]", CONFIG_PATH_NAME.c_str());
        return rc;
    }

    rc = hcsDeal->GetMetadata(cameraAbilityMap_);
    if (rc != RC_OK || cameraAbilityMap_.empty()) {
        CAMERA_LOGE("config camera ability not found. [pathname = %{public}s]", CONFIG_PATH_NAME.c_str());
        return rc;
    }

    return RC_OK;
}
RetCode CameraHostConfig::GetCameraIds(std::vector<std::string> &cameraIds)
{
    auto itr = cameraAbilityMap_.begin();
    for (; itr != cameraAbilityMap_.end(); itr++) {
        cameraIds.push_back(itr->first);
    }

    return RC_OK;
}
RetCode CameraHostConfig::GetCameraAbility(
    const std::string &cameraId, std::shared_ptr<CameraAbility> &ability)
{
    auto itr = cameraAbilityMap_.find(cameraId);
    if (itr != cameraAbilityMap_.end()) {
        ability = itr->second;
        return RC_OK;
    }

    return RC_ERROR;
}

hcb文件是由hcs文件通过build_hcs.py工具生成的具体生成的相关代码在驱动芯片适配的BUILD.gn中

//drivers/peripheral/camera/hal/adapter/chipset/hispark_taurus/BUILD.gn
action("build_camera_host_config") {
  script = "$hdf_framework_path/tools/hc-gen/build_hcs.py"
  sources = [ rebase_path(
          "//vendor/hisilicon/Hi3516DV300/hdf_config/uhdf/camera/hal/mpp/hispark_taurus/hdi_impl/camera_host_config.hcs") ]
  outputs = [ "$target_gen_dir/hdi_impl/camera_host_config.hcb" ]
  args = [
    "-o",
    rebase_path(outputs[0]),
    sources[0],
  ]
}

ohos_prebuilt_etc("camera_host_config.hcb") {
  deps = [ ":build_camera_host_config" ]
  hcs_outputs = get_target_outputs(":build_camera_host_config")
  source = hcs_outputs[0]
  relative_install_dir = "hdfconfig"
  subsystem_name = "hdf"
  part_name = "hdf"
}
//vendor/hisilicon/Hi3516DV300/hdf_config/uhdf/camera/hal/mpp/hispark_taurus/hdi_impl/camera_host_config.hcs
root {
    module="sample";
    camera_host_config {
        match_attr = "camera_host_interface";
        ....
        ability_01 :: ability {
            logicCameraId = "lcam001";
            physicsCameraIds = [
                "CAMERA_FIRST",
                "CAMERA_SECOND"
            ];
            metadata {
                aeAvailableAntiBandingModes = [
                    "OHOS_CAMERA_AE_ANTIBANDING_MODE_OFF"
                ];
            ......

4.2.4 OpenCamera()

先简单说下callback。
这里会先创建一个CameraDeviceCallback设备回调 作为Camera设备的回调接口。CameraDeviceCallback的接口类定义在

//drivers\peripheral\camera\interfaces\include\icamera_device_callback.h
virtual void OnError(ErrorType type, int32_t errorCode) = 0;
virtual void OnResult(uint64_t timestamp, const std::shared_ptr<CameraStandard::CameraMetadata> &result) = 0;

开始OpenCamera()。还是通过一次ipc 最后到HDI的camera_host
CameraHostImpl::OpenCamera 先从cameraDeviceMap_中查找cameraId对应的CameraDeviceImpl,然后通过CameraDeviceImpl设置device的callback.
再通过cameraId从CameraHostConfig查出对应的phyCameraIds,在调用CameraPowerUp接口完成上电.
最后把CameraDevice的status set true.

至此上层的相机初始化就完成了。

/**
 * @brief 打开Camera设备
 *
 * @param cameraId 要打开的Camera设备id
 * @param callback Camera设备的回调函数
 * @param camera 返回的Camera设备接口
 * @return CamRetCode
 * @see ICameraDeviceCallback
 * @see ICameraDevice
 */
CamRetCode CameraHostImpl::OpenCamera(const std::string &cameraId,
    const OHOS::sptr<ICameraDeviceCallback> &callback,
    OHOS::sptr<ICameraDevice> &device)
{
    CAMERA_LOGD("OpenCamera entry");
    DFX_LOCAL_HITRACE_BEGIN;
    
    //这里说明参数callback必须设置!!!
    if (CameraIdInvalid(cameraId) != RC_OK || callback == nullptr) {
        CAMERA_LOGW("open camera id is empty or callback is null.");
        return INVALID_ARGUMENT;
    }

    auto itr = cameraDeviceMap_.find(cameraId);
    if (itr == cameraDeviceMap_.end()) {
        CAMERA_LOGE("camera device not found.");
        return INSUFFICIENT_RESOURCES;
    }
    CAMERA_LOGD("OpenCamera cameraId find success.");

    std::shared_ptr<CameraDeviceImpl> cameraDevice =
        std::static_pointer_cast<CameraDeviceImpl>(itr->second);
    if (cameraDevice == nullptr) {
        CAMERA_LOGE("camera device is null.");
        return INSUFFICIENT_RESOURCES;
    }

    CamRetCode ret = cameraDevice->SetCallback(callback);
    if (ret != NO_ERROR) {
        CAMERA_LOGW("set camera device callback faild.");
        return ret;
    }

    CameraHostConfig *config = CameraHostConfig::GetInstance();
    if (config == nullptr) {
        return INVALID_ARGUMENT;
    }
    std::vector<std::string> phyCameraIds;
    RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds);
    if (rc != RC_OK) {
        CAMERA_LOGE("get physic cameraId failed.");
        return DEVICE_ERROR;
    }

    if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) {
        CAMERA_LOGE("camera powerup failed.");
        CameraPowerDown(phyCameraIds);
        return DEVICE_ERROR;
    }

    auto sptrDevice = deviceBackup_.find(cameraId);
    if (sptrDevice == deviceBackup_.end()) {
        deviceBackup_[cameraId] = cameraDevice.get();
    }
    device = deviceBackup_[cameraId];

    cameraDevice->SetStatus(true);
    CAMERA_LOGD("open camera success.");
    DFX_LOCAL_HITRACE_END;
    return NO_ERROR;
}

5 这里留下了两个问题

  • cameraDeviceMap_中的值什么时候设置的?
  • CameraPowerUp() 如何完成上电的功能?
    将在下一章节进行解析

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-1-6 14:03:53修改
5
收藏 3
回复
举报
2条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

期待楼主后续解答

回复
2022-1-5 11:15:19
LoinDIci
LoinDIci

怎么把这个应用编译出来?

回复
2022-8-19 14:13:03
回复
    相关推荐