OpenHarmony-v3.0-LTS Camera相机驱动框架(L2)解析1_初始化 原创 精华
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. 框架图
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 时序图
- CameraHostProxy 提供上层调用的代理接口。
- CameraHostStub 提供对应代理接口的HDI层的 ‘桩’。
- 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 时序图
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() 如何完成上电的功能?
将在下一章节进行解析
期待楼主后续解答
怎么把这个应用编译出来?