OpenHarmony-v3.0-LTS Camera相機驅(qū)動框架(L2)解析1_初始化
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
說明
- 解析源碼基于 OpenHarmony-v3.0-LTS 版本,代碼結(jié)構(gòu)和部分源碼與當(dāng)前維護的主線分支有差別。
- 解析示例代碼 drivers\peripheral\camera\hal\init\demo_main.cpp
1. 簡介
HarmonyOS 相機驅(qū)動框架模型對上實現(xiàn)相機HDI接口,對下實現(xiàn)相機Pipeline模型,管理相機各個硬件設(shè)備。
各層的基本概念如下:
HDI實現(xiàn)層,對上實現(xiàn)OHOS相機標(biāo)準(zhǔn)南向接口。
框架層,對接HDI實現(xiàn)層的控制、流的轉(zhuǎn)發(fā),實現(xiàn)數(shù)據(jù)通路的搭建、管理相機各個硬件設(shè)備等功能。
適配層,屏蔽底層芯片和OS差異,支持多平臺適配。
2. 框架圖

3. 代碼結(jié)構(gòu)
- drivers\peripheral\camera
- ├── hal
- │ ├── adapter //芯片和平臺適配層
- │ ├── buffer_manager //buffer管理
- │ ├── device_manager //設(shè)備控制接口定義
- │ ├── hdi_impl //HDI Implementation實現(xiàn)
- │ │ ├── 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 //基礎(chǔ)通用node
- │ │ │ ├── include
- │ │ │ └── src
- │ │ │ ├── dummy_node
- │ │ │ ├── fork_node
- │ │ │ ├── merge_node
- │ │ │ ├── node_base
- │ │ │ ├── sensor_node
- │ │ │ ├── sink_node
- │ │ │ ├── source_node
- │ │ │ └── transform_node
- │ │ ├── pipeline_impl //pipeline構(gòu)建實現(xiàn)
- │ │ │ ├── include
- │ │ │ └── src
- │ │ │ ├── builder
- │ │ │ ├── dispatcher
- │ │ │ ├── parser
- │ │ │ └── strategy
- │ │ │ └── config
- │ │ ├── src //PipelineCore
- │ │ └── utils
- ├── hal_c //hal層 C實現(xiàn)接口
- │ ├── hdi_cif
- │ │ ├── include
- │ │ └── src
- │ └── include
- └── interfaces //Camera Host框架HDI接口
- └── include
- ├── callback //框架涉及的所有callback接口
- │ ├── device
- │ ├── host
- │ └── operator
- ├── client
- └── server
4. 源碼解析
上層demo代碼相對簡單,這里只貼出關(guān)鍵部分代碼
- 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:設(shè)備管理接口,并設(shè)置Host層的回調(diào)。
- 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 時序圖

CameraHostProxy 提供上層調(diào)用的代理接口。
CameraHostStub 提供對應(yīng)代理接口的HDI層的 ‘樁’。
CameraHostImpl 是接口層的具體實現(xiàn)。
Proxy-Stub 負責(zé)上下接口參數(shù)的數(shù)據(jù)轉(zhuǎn)換等工作。
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 回調(diào)接口類定義了下面兩個回調(diào)接口,在CameraHostCallback類中具體實現(xiàn)并通過IPC通訊最終設(shè)置到CameraHostImpl
- virtual void OnCameraStatus(const std::string &cameraId, CameraStatus status) = 0;
- virtual void OnFlashlightStatus(const std::string &cameraId, FlashlightStatus status) = 0;
client::host_proxy發(fā)起IPC —> server::host_service_stub
注意 這里有個坑! 通常 SendRequest() 和 OnRemoteRequest() 是一對。sendRequest()在client::XXX_proxy調(diào)用,OnRemoteRequest() 在server::XXX_stub調(diào)用。但是CamereaHost 的OnRemoteRequest是由 HDF中的 HdfCameraService來接收 通過Dispatch接口再調(diào)用具體的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;
- }
最終調(diào)用到HDI 接口層的camera_host 完成callback的設(shè)置。
- //drivers\peripheral\camera\hal\hdi_impl\src\camera_host\camera_host_impl.cpp
- /**
- * @brief 設(shè)置Host回調(diào)函數(shù)
- *
- * @param callback Host回調(diào)函數(shù)
- * @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 、獲取默認前置的攝像頭設(shè)備的ability、創(chuàng)建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 時序圖

4.2.3 GetCameraIds()和GetCameraAblilty()
先來看下兩個簡單的設(shè)備信息獲取接口。
獲取系統(tǒng)配置中的cameraIds和CameraAbility
IPC 的過程和setcallback一樣 此處 略去 IPC相關(guān)代碼和時序圖
直接看實現(xiàn)CameraHostImpl::GetCameraIds() 和 CameraHostImpl::GetCameraAbility(),調(diào)用了CameraHostConfig::GetCameraIds()和CameraHostConfig::GetCameraAbility()
- 、、drivers\peripheral\camera\hal\hdi_impl\src\camera_host\camera_host_impl.cpp
- /**
- * @brief 獲取當(dāng)前可用的Camera設(shè)備列表
- *
- * @param ids 返回的當(dāng)前可用的設(shè)備列表
- */
- 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設(shè)備id
- * @param ability Camera設(shè)備的能力集
- * @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負責(zé)從camera_host_config.hcb文件讀出設(shè)備驅(qū)動信息。
- //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工具生成的具體生成的相關(guān)代碼在驅(qū)動芯片適配的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。
這里會先創(chuàng)建一個CameraDeviceCallback設(shè)備回調(diào) 作為Camera設(shè)備的回調(diào)接口。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對應(yīng)的CameraDeviceImpl,然后通過CameraDeviceImpl設(shè)置device的callback.
再通過cameraId從CameraHostConfig查出對應(yīng)的phyCameraIds,在調(diào)用CameraPowerUp接口完成上電.
最后把CameraDevice的status set true.
至此上層的相機初始化就完成了。
- /**
- * @brief 打開Camera設(shè)備
- *
- * @param cameraId 要打開的Camera設(shè)備id
- * @param callback Camera設(shè)備的回調(diào)函數(shù)
- * @param camera 返回的Camera設(shè)備接口
- * @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;
- //這里說明參數(shù)callback必須設(shè)置?。。?nbsp;
- 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_中的值什么時候設(shè)置的?
CameraPowerUp() 如何完成上電的功能?
將在下一章節(jié)進行解析
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)