1# Camera 2 3## 概述<a name="1"></a> 4### 功能简介<a name="2"></a> 5 6OpenHarmony相机驱动框架模型对上实现相机HDI(Hardware Device Interface)接口,对下实现相机Pipeline模型,管理相机各个硬件设备。 7该驱动框架模型内部分为三层,依次为HDI实现层、框架层和设备适配层。各层基本概念如下: 8 9+ HDI实现层:实现OHOS(OpenHarmony Operation System)相机标准南向接口。 10+ 框架层:对接HDI实现层的控制、流的转发,实现数据通路的搭建,管理相机各个硬件设备等功能。 11+ 设备适配层:屏蔽底层芯片和OS(Operation System)差异,支持多平台适配。 12 13### 运作机制<a name="3"></a> 14 15Camera模块主要包含服务、设备的初始化,数据通路的搭建,流的配置、创建、下发、捕获等,具体运作机制参考以下图文解析: 16 17**图 1** 基于HDF驱动框架的Camera驱动模型 18 19  20 211. 系统启动时创建camera_host进程。进程创建后,首先枚举底层设备,创建(也可以通过配置表创建)管理设备树的DeviceManager类及其内部各个底层设备的对象,创建对应的CameraHost类实例并且将其注册到UHDF(用户态HDF驱动框架)服务中,方便相机服务层通过UHDF服务获取底层CameraDeviceHost的服务,从而操作硬件设备。 22 232. Service通过CameraDeviceHost服务获取CameraHost实例,CameraHost可以获取底层的Camera能力,开启闪光灯、调用Open接口打开Camera创建连接、创建DeviceManager(负责底层硬件模块上电)、创建CameraDevice(向上提供设备控制接口)。创建CameraDevice时会实例化PipelineCore的各个子模块,其中StreamPipelineCore负责创建Pipeline,MetaQueueManager负责上报metaData。 24 253. Service通过CameraDevice模块配置流、创建Stream类。StreamPipelineStrategy模块通过上层下发的模式和查询配置表创建对应流的Node连接方式,StreamPipelineBuilder模块创建Node实例并且连接返回该Pipeline给StreamPipelineDispatcher。StreamPipelineDispatcher提供统一的Pipeline调用管理。 26 274. Service通过Stream控制整个流的操作,AttachBufferQueue接口将从显示模块申请的BufferQueue下发到底层,由CameraDeviceDriverModel自行管理buffer,当Capture接口下发命令后,底层开始向上传递buffer。Pipeline的IspNode依次从BufferQueue获取指定数量buffer,然后下发到底层ISP(Image Signal Processor,图像信号处理器)硬件,ISP填充完之后将buffer传递给CameraDeviceDriverModel,CameraDeviceDriverModel通过循环线程将buffer填充到已经创建好的Pipeline中,各个Node处理后通过回调传递给上层,同时buffer返回BufferQueue等待下一次下发。 28 295. Service通过Capture接口下发拍照命令。ChangeToOfflineStream接口查询拍照buffer位置,如果ISP已经出图,并且图像数据已经送到IPP node,可以将普通拍照流转换为离线流,否则直接走关闭流程。ChangeToOfflineStream接口通过传递StreamInfo使离线流获取到普通流的流信息,并且通过配置表确认离线流的具体Node连接方式,创建离线流的Node连接(如果已创建则通过CloseCamera释放非离线流所需的Node),等待buffer从底层Pipeline回传到上层再释放持有的Pipeline相关资源。 30 316. Service通过CameraDevice的UpdateSettings接口向下发送CaptureSetting参数,CameraDeviceDriverModel通过StreamPipelineDispatcher模块向各个Node转发,StartStreamingCapture和Capture接口携带的CaptureSetting通过StreamPipelineDispatcher模块向该流所属的Node转发。 32 337. Service通过EnableResult和DisableResult接口控制底层metaData的上报。如果需要底层metaData上报,pipeline会创建CameraDeviceDriverModel内部的一个Bufferqueue用来收集和传递metaData,根据StreamPipelineStrategy模块查询配置表并通过StreamPipelineBuilder创建和连接Node,MetaQueueManager下发buffer至底层,底层相关Node填充数据,MetaQueueManager模块再调用上层回调传递给上层。 34 358. Service调用CameraDevice的Close接口,CameraDevice调用对应的DeviceManager模块对各个硬件下电;如果此时在Ipp的SubPipeline中存在OfflineStream,则需要保留OfflineStream,直到执行完毕。 36 379. 动态帧率控制。在StreamOperator中起一个CollectBuffer线程,CollectBuffer线程从每一路stream的BufferQueue中获取buffer,如果某一路流的帧率需要控制(为sensor出帧帧率的1/n),可以根据需求控制每一帧的buffer打包,并决定是否collect此路流的buffer(比如sensor出帧帧率为120fps,预览流的帧率为30fps,CollectBuffer线程collect预览流的buffer时,每隔4fps collect一次)。 38 39 40 41## 开发指导<a name="4"></a> 42 43 44### 场景介绍<a name="5"></a> 45 46Camera模块主要针对相机预览、拍照、视频流等场景,对这些场景下的相机操作进行封装,使开发者更易操作相机硬件,提高开发效率。 47 48### 接口说明<a name="6"></a> 49 50注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件`/drivers/interface/camera/v1_1/`,获取路径为:[https://gitee.com/openharmony/drivers_interface/tree/master/camera](https://gitee.com/openharmony/drivers_interface/tree/master/camera)。 51在HDI使用中下发的配置参数不能超出GetCameraAbility上报的能力范围。即使通过UpdateSettings、CommitStreams、Capture等接口可以下发超出该范围的配置参数,且接口调用不会返回失败,但设置后的行为是不确定的。 52- icamera_device.h 53 54 | 功能描述 | 接口名称 | 55 | ---------------------------- | ------------------------------------------------------------ | 56 | 获取流控制器 | int32_t GetStreamOperator_V1_1(<br>const sptr\<OHOS::HDI::Camera::V1_0::IStreamOperatorCallback\>& callbackObj,<br>sptr\<OHOS::HDI::Camera::V1_1::IStreamOperator\>& streamOperator<br>) | 57 58- icamera_host.h 59 60 | 功能描述 | 接口名称 | 61 | ------------------------------ | ------------------------------------------------------------ | 62 | 打开Camera设备 | int32_t OpenCamera_V1_1(<br>const std::string& cameraId, <br>const sptr\<OHOS::HDI::Camera::V1_0::ICameraDeviceCallback\>& callbackObj, <br>sptr\<OHOS::HDI::Camera::V1_1::ICameraDevice\>& device<br>) | 63 | 预启动摄像头设备 | int32_t PreLaunch(const PrelaunchConfig& config) | 64 65- istream_operator.h 66 67 | 功能描述 | 接口名称 | 68 | -------------------------------- | ------------------------------------------------------------ | 69 | 查询是否支持添加参数对应的流 | int32_t IsStreamsSupported_V1_1(<br>OperationMode mode,<br>const std::vector<uint8_t>& modeSetting,<br>const std::vector<StreamInfo_V1_1>& infos,<br>StreamSupportType& type<br>) | 70 | 创建流 | int32_t CreateStreams_V1_1(const std::vector<StreamInfo_V1_1>& streamInfos) | 71 72 73### 开发步骤<a name="7"></a> 74Camera驱动的开发过程主要包含以下步骤: 75 761. 注册CameraHost 77 78 定义Camera的HdfDriverEntry结构体,该结构体中定义了CameraHost初始化的方法(代码目录drivers/peripheral/camera/interfaces/hdi_ipc/camera_host_driver.cpp)。 79 ```c++ 80 struct HdfDriverEntry g_cameraHostDriverEntry = { 81 .moduleVersion = 1, 82 .moduleName = "camera_service", 83 .Bind = HdfCameraHostDriverBind, 84 .Init = HdfCameraHostDriverInit, 85 .Release = HdfCameraHostDriverRelease, 86 }; 87 HDF_INIT(g_cameraHostDriverEntry); // 将Camera的HdfDriverEntry结构体注册到HDF上 88 ``` 89 902. 初始化Host服务 91 92 步骤1中提到的HdfCameraHostDriverBind接口提供了CameraServiceDispatch和CameraHostStubInstance的注册。CameraServiceDispatch接口是远端调用CameraHost的方法,如OpenCamera(),SetFlashlight()等,CameraHostStubInstance接口是Camera设备的初始化,在开机时被调用。 93 94 ```c++ 95 static int HdfCameraHostDriverBind(struct HdfDeviceObject *deviceObject) 96 { 97 HDF_LOGI("HdfCameraHostDriverBind enter"); 98 99 auto *hdfCameraHostHost = new (std::nothrow) HdfCameraHostHost; 100 if (hdfCameraHostHost == nullptr) { 101 HDF_LOGE("%{public}s: failed to create HdfCameraHostHost object", __func__); 102 return HDF_FAILURE; 103 } 104 105 hdfCameraHostHost->ioService.Dispatch = CameraHostDriverDispatch; // 提供远端CameraHost调用方法 106 hdfCameraHostHost->ioService.Open = NULL; 107 hdfCameraHostHost->ioService.Release = NULL; 108 109 auto serviceImpl = ICameraHost::Get(true); 110 if (serviceImpl == nullptr) { 111 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 112 delete hdfCameraHostHost; 113 return HDF_FAILURE; 114 } 115 116 hdfCameraHostHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 117 ICameraHost::GetDescriptor()); // 初始化Camera设备 118 if (hdfCameraHostHost->stub == nullptr) { 119 HDF_LOGE("%{public}s: failed to get stub object", __func__); 120 delete hdfCameraHostHost; 121 return HDF_FAILURE; 122 } 123 124 deviceObject->service = &hdfCameraHostHost->ioService; 125 return HDF_SUCCESS; 126 } 127 ``` 128 129 下面的函数是远端CameraHost调用的方法: 130 131 ```c++ 132 int32_t CameraHostStub::CameraHostServiceStubOnRemoteRequest(int cmdId, MessageParcel &data, 133 MessageParcel &reply, MessageOption &option) 134 { 135 switch(cmdId) { 136 case CMD_CAMERA_HOST_SET_CALLBACK: { 137 return CameraHostStubSetCallback(data, reply, option); 138 } 139 case CMD_CAMERA_HOST_GET_CAMERAID: { 140 return CameraHostStubGetCameraIds(data, reply, option); 141 } 142 case CMD_CAMERA_HOST_GET_CAMERA_ABILITY: { 143 return CameraHostStubGetCameraAbility(data, reply, option); 144 } 145 case CMD_CAMERA_HOST_OPEN_CAMERA: { 146 return CameraHostStubOpenCamera(data, reply, option); 147 } 148 case CMD_CAMERA_HOST_SET_FLASH_LIGHT: { 149 return CameraHostStubSetFlashlight(data, reply, option); 150 } 151 default: { 152 HDF_LOGE("%s: not support cmd %d", __func__, cmdId); 153 return HDF_ERR_INVALID_PARAM; 154 } 155 } 156 return HDF_SUCCESS; 157 } 158 ``` 159 160 CameraHostStubInstance()接口最终调用CameraHostImpl::Init()方法,该方法会获取物理Camera,并对DeviceManager和PipelineCore进行初始化。 161 1623. 获取Host服务 163 164 调用Get()接口从远端CameraService中获取CameraHost对象。get()方法如下: 165 166 ```c++ 167 sptr<ICameraHost> ICameraHost::Get(const char *serviceName) 168 { 169 do { 170 using namespace OHOS::HDI::ServiceManager::V1_0; 171 auto servMgr = IServiceManager::Get(); 172 if (servMgr == nullptr) { 173 HDF_LOGE("%s: IServiceManager failed!", __func__); 174 break; 175 } 176 auto remote = servMgr->GetService(serviceName); // 根据serviceName名称获取CameraHost 177 if (remote != nullptr) { 178 sptr<CameraHostProxy> hostSptr = iface_cast<CameraHostProxy>(remote); // 将CameraHostProxy对象返回给调用者,该对象中包含OpenCamera()等方法。 179 return hostSptr; 180 } 181 HDF_LOGE("%s: GetService failed! serviceName = %s", __func__, serviceName); 182 } while(false); 183 HDF_LOGE("%s: get %s failed!", __func__, serviceName); 184 return nullptr; 185 } 186 ``` 187 1884. 打开设备 189 190 CameraHostProxy对象中有五个方法,分别是SetCallback、GetCameraIds、GetCameraAbility、OpenCamera和SetFlashlight。下面着重描述OpenCamera接口。 191 CameraHostProxy的OpenCamera()接口通过CMD_CAMERA_HOST_OPEN_CAMERA调用远端CameraHostStubOpenCamera()接口并获取ICameraDevice对象。 192 193 ```c++ 194 int32_t CameraHostProxy::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 195 sptr<ICameraDevice>& device) 196 { 197 MessageParcel cameraHostData; 198 MessageParcel cameraHostReply; 199 MessageOption cameraHostOption(MessageOption::TF_SYNC); 200 201 if (!cameraHostData.WriteInterfaceToken(ICameraHost::GetDescriptor())) { 202 HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__); 203 return HDF_ERR_INVALID_PARAM; 204 } 205 206 if (!cameraHostData.WriteCString(cameraId.c_str())) { 207 HDF_LOGE("%{public}s: write cameraId failed!", __func__); 208 return HDF_ERR_INVALID_PARAM; 209 } 210 211 if (!cameraHostData.WriteRemoteObject(OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(callbackObj, 212 ICameraDeviceCallback::GetDescriptor()))) { 213 HDF_LOGE("%{public}s: write callbackObj failed!", __func__); 214 return HDF_ERR_INVALID_PARAM; 215 } 216 217 int32_t cameraHostRet = Remote()->SendRequest(CMD_CAMERA_HOST_OPEN_CAMERA, cameraHostData, cameraHostReply, cameraHostOption); 218 if (cameraHostRet != HDF_SUCCESS) { 219 HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, cameraHostRet); 220 return cameraHostRet; 221 } 222 223 device = hdi_facecast<ICameraDevice>(cameraHostReply.ReadRemoteObject()); 224 225 return cameraHostRet; 226 } 227 ``` 228 229 Remote()->SendRequest调用上文提到的CameraHostServiceStubOnRemoteRequest(),根据cmdId进入CameraHostStubOpenCamera()接口,最终调用CameraHostImpl::OpenCamera(),该接口获取了CameraDevice并对硬件进行上电等操作。 230 231 ```c++ 232 int32_t CameraHostImpl::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 233 sptr<ICameraDevice>& device) 234 { 235 CAMERA_LOGD("OpenCamera entry"); 236 DFX_LOCAL_HITRACE_BEGIN; 237 if (CameraIdInvalid(cameraId) != RC_OK || callbackObj == nullptr) { 238 CAMERA_LOGW("open camera id is empty or callback is null."); 239 return INVALID_ARGUMENT; 240 } 241 242 auto itr = cameraDeviceMap_.find(cameraId); 243 if (itr == cameraDeviceMap_.end()) { 244 CAMERA_LOGE("camera device not found."); 245 return INSUFFICIENT_RESOURCES; 246 } 247 CAMERA_LOGD("OpenCamera cameraId find success."); 248 249 std::shared_ptr<CameraDeviceImpl> cameraDevice = itr->second; 250 if (cameraDevice == nullptr) { 251 CAMERA_LOGE("camera device is null."); 252 return INSUFFICIENT_RESOURCES; 253 } 254 255 CamRetCode ret = cameraDevice->SetCallback(callbackObj); 256 CHECK_IF_NOT_EQUAL_RETURN_VALUE(ret, HDI::Camera::V1_0::NO_ERROR, ret); 257 258 CameraHostConfig *config = CameraHostConfig::GetInstance(); 259 CHECK_IF_PTR_NULL_RETURN_VALUE(config, INVALID_ARGUMENT); 260 261 std::vector<std::string> phyCameraIds; 262 RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds); 263 if (rc != RC_OK) { 264 CAMERA_LOGE("get physic cameraId failed."); 265 return DEVICE_ERROR; 266 } 267 if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) { // 对Camera硬件上电 268 CAMERA_LOGE("camera powerup failed."); 269 CameraPowerDown(phyCameraIds); 270 return DEVICE_ERROR; 271 } 272 273 auto sptrDevice = deviceBackup_.find(cameraId); 274 if (sptrDevice == deviceBackup_.end()) { 275 #ifdef CAMERA_BUILT_ON_OHOS_LITE 276 deviceBackup_[cameraId] = cameraDevice; 277 #else 278 deviceBackup_[cameraId] = cameraDevice.get(); 279 #endif 280 } 281 device = deviceBackup_[cameraId]; 282 cameraDevice->SetStatus(true); 283 CAMERA_LOGD("open camera success."); 284 DFX_LOCAL_HITRACE_END; 285 return HDI::Camera::V1_0::NO_ERROR; 286 } 287 ``` 288 2895. 获取流 290 291 CameraDeviceImpl定义了GetStreamOperator、UpdateSettings、SetResultMode和GetEnabledResult等方法,获取流操作方法如下: 292 293 ```c++ 294 int32_t CameraDeviceImpl::GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj, 295 sptr<IStreamOperator>& streamOperator) 296 { 297 HDI_DEVICE_PLACE_A_WATCHDOG; 298 DFX_LOCAL_HITRACE_BEGIN; 299 if (callbackObj == nullptr) { 300 CAMERA_LOGW("input callback is null."); 301 return INVALID_ARGUMENT; 302 } 303 304 spCameraDeciceCallback_ = callbackObj; 305 if (spStreamOperator_ == nullptr) { 306 #ifdef CAMERA_BUILT_ON_OHOS_LITE 307 // 这里创建一个spStreamOperator_ 对象传递给调用者,以便对stream进行各种操作 308 spStreamOperator_ = std::make_shared<StreamOperator>(spCameraDeciceCallback_, shared_from_this()); 309 #else 310 spStreamOperator_ = new(std::nothrow) StreamOperator(spCameraDeciceCallback_, shared_from_this()); 311 #endif 312 if (spStreamOperator_ == nullptr) { 313 CAMERA_LOGW("create stream operator failed."); 314 return DEVICE_ERROR; 315 } 316 spStreamOperator_->Init(); 317 ismOperator_ = spStreamOperator_; 318 } 319 streamOperator = ismOperator_; 320 #ifndef CAMERA_BUILT_ON_OHOS_LITE 321 CAMERA_LOGI("CameraDeviceImpl %{public}s: line: %{public}d", __FUNCTION__, __LINE__); 322 pipelineCore_->GetStreamPipelineCore()->SetCallback( 323 [this](const std::shared_ptr<CameraMetadata> &metadata) { 324 OnMetadataChanged(metadata); 325 }); 326 #endif 327 DFX_LOCAL_HITRACE_END; 328 return HDI::Camera::V1_0::NO_ERROR; 329 } 330 ``` 331 3326. 创建流 333 334 调用CreateStreams创建流前需要填充StreamInfo结构体,具体内容如下: 335 336 ```c++ 337 using StreamInfo = struct _StreamInfo { 338 int streamId_; 339 int width_; // 数据流宽 340 int height_; // 数据流高 341 int format_; // 数据流格式,如PIXEL_FMT_YCRCB_420_SP 342 int dataSpace_; 343 StreamIntent intent_; // StreamIntent 如PREVIEW 344 bool tunneledMode_; 345 BufferProducerSequenceable bufferQueue_; // 数据流bufferQueue可用streamCustomer->CreateProducer()接口创建 346 int minFrameDuration_; 347 EncodeType encodeType_; 348 }; 349 ``` 350 351 CreateStreams()接口是StreamOperator(StreamOperatorImpl类是StreamOperator的基类)类中的方法,该接口的主要作用是创建一个StreamBase对象,通过StreamBase的Init方法初始化CreateBufferPool等操作。 352 353 ```c++ 354 int32_t StreamOperator::CreateStreams(const std::vector<StreamInfo>& streamInfos) 355 { 356 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 357 DFX_LOCAL_HITRACE_BEGIN; 358 for (const auto& it : streamInfos) { 359 CHECK_IF_NOT_EQUAL_RETURN_VALUE(CheckStreamInfo(it), true, INVALID_ARGUMENT); 360 CAMERA_LOGI("streamId:%{public}d and format:%{public}d and width:%{public}d and height:%{public}d", 361 it.streamId_, it.format_, it.width_, it.height_); 362 if (streamMap_.count(it.streamId_) > 0) { 363 CAMERA_LOGE("stream [id = %{public}d] has already been created.", it.streamId_); 364 return INVALID_ARGUMENT; 365 } 366 std::shared_ptr<IStream> stream = StreamFactory::Instance().CreateShared( // 创建Stream实例 367 IStream::g_availableStreamType[it.intent_], it.streamId_, it.intent_, pipelineCore_, messenger_); 368 if (stream == nullptr) { 369 CAMERA_LOGE("create stream [id = %{public}d] failed.", it.streamId_); 370 return INSUFFICIENT_RESOURCES; 371 } 372 StreamConfiguration scg; 373 StreamInfoToStreamConfiguration(scg, it); 374 RetCode rc = stream->ConfigStream(scg); 375 if (rc != RC_OK) { 376 CAMERA_LOGE("configure stream %{public}d failed", it.streamId_); 377 return INVALID_ARGUMENT; 378 } 379 if (!scg.tunnelMode && (it.bufferQueue_)->producer_ != nullptr) { 380 CAMERA_LOGE("stream [id:%{public}d] is not tunnel mode, can't bind a buffer producer", it.streamId_); 381 return INVALID_ARGUMENT; 382 } 383 if ((it.bufferQueue_)->producer_ != nullptr) { 384 auto tunnel = std::make_shared<StreamTunnel>(); 385 CHECK_IF_PTR_NULL_RETURN_VALUE(tunnel, INSUFFICIENT_RESOURCES); 386 rc = tunnel->AttachBufferQueue((it.bufferQueue_)->producer_); 387 CHECK_IF_NOT_EQUAL_RETURN_VALUE(rc, RC_OK, INVALID_ARGUMENT); 388 if (stream->AttachStreamTunnel(tunnel) != RC_OK) { 389 CAMERA_LOGE("attach buffer queue to stream [id = %{public}d] failed", it.streamId_); 390 return INVALID_ARGUMENT; 391 } 392 } 393 { 394 std::lock_guard<std::mutex> l(streamLock_); 395 streamMap_[stream->GetStreamId()] = stream; 396 } 397 CAMERA_LOGI("create stream success [id:%{public}d] [type:%{public}s]", stream->GetStreamId(), 398 IStream::g_availableStreamType[it.intent_].c_str()); 399 } 400 DFX_LOCAL_HITRACE_END; 401 return HDI::Camera::V1_0::NO_ERROR; 402 } 403 ``` 404 4057. 配置流 406 407 CommitStreams()是配置流的接口,必须在创建流之后调用,其主要作用是初始化Pipeline和创建Pipeline。 408 409 ```c++ 410 int32_t StreamOperator::CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) 411 { 412 CAMERA_LOGV("enter"); 413 CHECK_IF_PTR_NULL_RETURN_VALUE(streamPipeline_, DEVICE_ERROR); 414 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 415 if (modeSetting.empty()) { 416 CAMERA_LOGE("input vector is empty"); 417 return INVALID_ARGUMENT; 418 } 419 DFX_LOCAL_HITRACE_BEGIN; 420 421 std::vector<StreamConfiguration> configs = {}; 422 { 423 std::lock_guard<std::mutex> l(streamLock_); 424 std::transform(streamMap_.begin(), streamMap_.end(), std::back_inserter(configs), 425 [](auto &iter) { return iter.second->GetStreamAttribute(); }); 426 } 427 428 std::shared_ptr<CameraMetadata> setting; 429 MetadataUtils::ConvertVecToMetadata(modeSetting, setting); 430 DynamicStreamSwitchMode method = streamPipeline_->CheckStreamsSupported(mode, setting, configs); 431 if (method == DYNAMIC_STREAM_SWITCH_NOT_SUPPORT) { 432 return INVALID_ARGUMENT; 433 } 434 if (method == DYNAMIC_STREAM_SWITCH_NEED_INNER_RESTART) { 435 std::lock_guard<std::mutex> l(streamLock_); 436 for (auto it : streamMap_) { 437 it.second->StopStream(); 438 } 439 } 440 { 441 std::lock_guard<std::mutex> l(streamLock_); 442 for (auto it : streamMap_) { 443 if (it.second->CommitStream() != RC_OK) { 444 CAMERA_LOGE("commit stream [id = %{public}d] failed.", it.first); 445 return DEVICE_ERROR; 446 } 447 } 448 } 449 RetCode rc = streamPipeline_->PreConfig(setting); // 设备流配置 450 if (rc != RC_OK) { 451 CAMERA_LOGE("prepare mode settings failed"); 452 return DEVICE_ERROR; 453 } 454 rc = streamPipeline_->CreatePipeline(mode); // 创建一个pipeline 455 if (rc != RC_OK) { 456 CAMERA_LOGE("create pipeline failed."); 457 return INVALID_ARGUMENT; 458 } 459 460 DFX_LOCAL_HITRACE_END; 461 return HDI::Camera::V1_0::NO_ERROR; 462 } 463 ``` 464 4658. 捕获图像 466 467 在调用Capture()接口前需要先填充CaptureInfo结构体,具体内容如下: 468 469 ```c++ 470 using CaptureInfo = struct _CaptureInfo { 471 int[] streamIds_; // 需要Capture的streamIds 472 unsigned char[] captureSetting_; // 这里填充camera ability 可通过CameraHost 的GetCameraAbility()接口获取 473 bool enableShutterCallback_; 474 }; 475 ``` 476 477 StreamOperator中的Capture方法主要是捕获数据流: 478 479 ```c++ 480 int32_t StreamOperator::Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) 481 { 482 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 483 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 484 DFX_LOCAL_HITRACE_BEGIN; 485 486 for (auto id : info.streamIds_) { 487 std::lock_guard<std::mutex> l(streamLock_); 488 auto it = streamMap_.find(id); 489 if (it == streamMap_.end()) { 490 return INVALID_ARGUMENT; 491 } 492 } 493 494 { 495 std::lock_guard<std::mutex> l(requestLock_); 496 auto itr = requestMap_.find(captureId); 497 if (itr != requestMap_.end()) { 498 return INVALID_ARGUMENT; 499 } 500 } 501 502 std::shared_ptr<CameraMetadata> captureSetting; 503 MetadataUtils::ConvertVecToMetadata(info.captureSetting_, captureSetting); 504 CaptureSetting setting = captureSetting; 505 auto request = 506 std::make_shared<CaptureRequest>(captureId, info.streamIds_.size(), setting, 507 info.enableShutterCallback_, isStreaming); 508 for (auto id : info.streamIds_) { 509 RetCode rc = streamMap_[id]->AddRequest(request); 510 if (rc != RC_OK) { 511 return DEVICE_ERROR; 512 } 513 } 514 515 { 516 std::lock_guard<std::mutex> l(requestLock_); 517 requestMap_[captureId] = request; 518 } 519 return HDI::Camera::V1_0::NO_ERROR; 520 } 521 ``` 522 5239. 取消捕获和释放离线流 524 525 StreamOperator类中的CancelCapture()接口的主要作用是根据captureId取消数据流的捕获。 526 527 ```c++ 528 int32_t StreamOperator::CancelCapture(int32_t captureId) 529 { 530 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 531 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 532 DFX_LOCAL_HITRACE_BEGIN; 533 534 std::lock_guard<std::mutex> l(requestLock_); 535 auto itr = requestMap_.find(captureId); // 根据captureId 在Map中查找对应的CameraCapture对象 536 if (itr == requestMap_.end()) { 537 CAMERA_LOGE("can't cancel capture [id = %{public}d], this capture doesn't exist", captureId); 538 return INVALID_ARGUMENT; 539 } 540 541 RetCode rc = itr->second->Cancel(); // 调用CameraCapture中Cancel方法结束数据捕获 542 if (rc != RC_OK) { 543 return DEVICE_ERROR; 544 } 545 requestMap_.erase(itr); // 擦除该CameraCapture对象 546 547 DFX_LOCAL_HITRACE_END; 548 return HDI::Camera::V1_0::NO_ERROR; 549 } 550 ``` 551 552 StreamOperator类中的ReleaseStreams接口的主要作用是释放之前通过CreateStream()和CommitStreams()接口创建的流,并销毁Pipeline。 553 554 ```c++ 555 int32_t StreamOperator::ReleaseStreams(const std::vector<int32_t>& streamIds) 556 { 557 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 558 DFX_LOCAL_HITRACE_BEGIN; 559 for (auto id : streamIds) { 560 std::lock_guard<std::mutex> l(streamLock_); 561 auto it = streamMap_.find(id); 562 if (it == streamMap_.end()) { 563 continue; 564 } 565 if (it->second->IsRunning()) { 566 it->second->StopStream(); 567 } 568 it->second->DumpStatsInfo(); 569 streamMap_.erase(it); 570 } 571 572 for (auto id : streamIds) { 573 CHECK_IF_EQUAL_RETURN_VALUE(id < 0, true, INVALID_ARGUMENT); 574 } 575 576 DFX_LOCAL_HITRACE_END; 577 return HDI::Camera::V1_0::NO_ERROR; 578 } 579 ``` 580 58110. 关闭Camera设备 582 583 调用CameraDeviceImpl中的Close()来关闭CameraDevice,该接口调用deviceManager中的PowerDown()来给设备下电。 584 585### 开发实例<a name = "8"></a> 586 587在/drivers/peripheral/camera/test/demo目录下有一个关于Camera的demo,开机后会在/vendor/bin下生成可执行文件ohos_camera_demo,该demo可以完成Camera的预览,拍照等基础功能。下面我们就以此demo为例讲述怎样用HDI接口去编写预览PreviewOn()和拍照CaptureON()的用例,可参考[ohos_camera_demo](https://gitee.com/openharmony/drivers_peripheral/tree/master/camera/test/demo)。 588 5891. 在main函数中构造一个CameraDemo 对象,该对象中有对Camera初始化、启停流、释放等控制的方法。下面mainDemo->InitSensors()函数为初始化CameraHost,mainDemo->InitCameraDevice()函数为初始化CameraDevice。 590 591 ```c++ 592 int main(int argc, char** argv) 593 { 594 RetCode rc = RC_OK; 595 auto mainDemo = std::make_shared<CameraDemo>(); 596 rc = mainDemo->InitSensors(); // 初始化CameraHost 597 if (rc == RC_ERROR) { 598 CAMERA_LOGE("main test: mainDemo->InitSensors() error\n"); 599 return -1; 600 } 601 602 rc = mainDemo->InitCameraDevice(); // 初始化CameraDevice 603 if (rc == RC_ERROR) { 604 CAMERA_LOGE("main test: mainDemo->InitCameraDevice() error\n"); 605 return -1; 606 } 607 608 rc = PreviewOn(0, mainDemo); // 配流和启流 609 if (rc != RC_OK) { 610 CAMERA_LOGE("main test: PreviewOn() error demo exit"); 611 return -1; 612 } 613 614 ManuList(mainDemo, argc, argv); // 打印菜单到控制台 615 616 return RC_OK; 617 } 618 ``` 619 620 初始化CameraHost函数实现如下,这里调用了HDI接口ICameraHost::Get()去获取demoCameraHost,并对其设置回调函数。 621 622 ```c++ 623 RetCode OhosCameraDemo::InitSensors() 624 { 625 int rc = 0; 626 627 CAMERA_LOGD("demo test: InitSensors enter"); 628 629 if (demoCameraHost_ != nullptr) { 630 return RC_OK; 631 } 632 #ifdef CAMERA_BUILT_ON_OHOS_LITE 633 demoCameraHost_ = OHOS::Camera::CameraHost::CreateCameraHost(); 634 #else 635 constexpr const char *DEMO_SERVICE_NAME = "camera_service"; 636 demoCameraHost_ = ICameraHost::Get(DEMO_SERVICE_NAME, false); 637 #endif 638 if (demoCameraHost_ == nullptr) { 639 CAMERA_LOGE("demo test: ICameraHost::Get error"); 640 return RC_ERROR; 641 } 642 643 #ifdef CAMERA_BUILT_ON_OHOS_LITE 644 hostCallback_ = std::make_shared<DemoCameraHostCallback>(); 645 #else 646 hostCallback_ = new DemoCameraHostCallback(); 647 #endif 648 rc = demoCameraHost_->SetCallback(hostCallback_); 649 if (rc != HDI::Camera::V1_0::NO_ERROR) { 650 CAMERA_LOGE("demo test: demoCameraHost_->SetCallback(hostCallback_) error"); 651 return RC_ERROR; 652 } 653 654 CAMERA_LOGD("demo test: InitSensors exit"); 655 656 return RC_OK; 657 } 658 ``` 659 660 初始化CameraDevice函数实现如下,这里调用了GetCameraIds(cameraIds_),GetCameraAbility(cameraId, ability_),OpenCamera(cameraIds_.front(), callback, demoCameraDevice_)等接口实现了demoCameraHost的获取。 661 662 ```c++ 663 RetCode OhosCameraDemo::InitCameraDevice() 664 { 665 int rc = 0; 666 667 CAMERA_LOGD("demo test: InitCameraDevice enter"); 668 669 if (demoCameraHost_ == nullptr) { 670 CAMERA_LOGE("demo test: InitCameraDevice demoCameraHost_ == nullptr"); 671 return RC_ERROR; 672 } 673 674 (void)demoCameraHost_->GetCameraIds(cameraIds_); 675 if (cameraIds_.empty()) { 676 return RC_ERROR; 677 } 678 const std::string cameraId = cameraIds_.front(); 679 demoCameraHost_->GetCameraAbility(cameraId, cameraAbility_); 680 681 MetadataUtils::ConvertVecToMetadata(cameraAbility_, ability_); 682 683 GetFaceDetectMode(ability_); 684 GetFocalLength(ability_); 685 GetAvailableFocusModes(ability_); 686 GetAvailableExposureModes(ability_); 687 GetExposureCompensationRange(ability_); 688 GetExposureCompensationSteps(ability_); 689 GetAvailableMeterModes(ability_); 690 GetAvailableFlashModes(ability_); 691 GetMirrorSupported(ability_); 692 GetStreamBasicConfigurations(ability_); 693 GetFpsRange(ability_); 694 GetCameraPosition(ability_); 695 GetCameraType(ability_); 696 GetCameraConnectionType(ability_); 697 GetFaceDetectMaxNum(ability_); 698 699 #ifdef CAMERA_BUILT_ON_OHOS_LITE 700 std::shared_ptr<CameraDeviceCallback> callback = std::make_shared<CameraDeviceCallback>(); 701 #else 702 sptr<DemoCameraDeviceCallback> callback = new DemoCameraDeviceCallback(); 703 #endif 704 rc = demoCameraHost_->OpenCamera(cameraIds_.front(), callback, demoCameraDevice_); 705 if (rc != HDI::Camera::V1_0::NO_ERROR || demoCameraDevice_ == nullptr) { 706 CAMERA_LOGE("demo test: InitCameraDevice OpenCamera failed"); 707 return RC_ERROR; 708 } 709 710 CAMERA_LOGD("demo test: InitCameraDevice exit"); 711 712 return RC_OK; 713 } 714 ``` 715 7162. PreviewOn()接口包含配置流、开启预览流和启动Capture动作。该接口执行完成后Camera预览通路已经开始运转并开启了两路流,一路流是preview,另外一路流是capture或者video,两路流中仅对preview流进行capture动作。 717 718 ```c++ 719 static RetCode PreviewOn(int mode, const std::shared_ptr<OhosCameraDemo>& mainDemo) 720 { 721 RetCode rc = RC_OK; 722 CAMERA_LOGD("main test: PreviewOn enter"); 723 724 rc = mainDemo->StartPreviewStream(); // 配置preview流 725 if (rc != RC_OK) { 726 CAMERA_LOGE("main test: PreviewOn StartPreviewStream error"); 727 return RC_ERROR; 728 } 729 730 if (mode == 0) { 731 rc = mainDemo->StartCaptureStream(); // 配置capture流 732 if (rc != RC_OK) { 733 CAMERA_LOGE("main test: PreviewOn StartCaptureStream error"); 734 return RC_ERROR; 735 } 736 } else { 737 rc = mainDemo->StartVideoStream(); // 配置video流 738 if (rc != RC_OK) { 739 CAMERA_LOGE("main test: PreviewOn StartVideoStream error"); 740 return RC_ERROR; 741 } 742 } 743 744 rc = mainDemo->CaptureON(STREAM_ID_PREVIEW, CAPTURE_ID_PREVIEW, CAPTURE_PREVIEW); 745 if (rc != RC_OK) { 746 CAMERA_LOGE("main test: PreviewOn mainDemo->CaptureON() preview error"); 747 return RC_ERROR; 748 } 749 750 CAMERA_LOGD("main test: PreviewOn exit"); 751 return RC_OK; 752 } 753 ``` 754 755 StartCaptureStream()、StartVideoStream()和StartPreviewStream()接口都会调用CreateStream()接口,只是传入的参数不同。 756 757 CreateStream()方法调用HDI接口去配置和创建流,首先调用HDI接口去获取StreamOperation对象,然后创建一个StreamInfo。调用CreateStreams()和CommitStreams()实际创建流并配置流。 758 759 ```c++ 760 RetCode OhosCameraDemo::CreateStream(const int streamId, std::shared_ptr<StreamCustomer> &streamCustomer, 761 StreamIntent intent) 762 { 763 int rc = 0; 764 CAMERA_LOGD("demo test: CreateStream enter"); 765 766 GetStreamOpt(); // 获取StreamOperator对象 767 if (streamOperator_ == nullptr) { 768 CAMERA_LOGE("demo test: CreateStream GetStreamOpt() is nullptr\n"); 769 return RC_ERROR; 770 } 771 772 StreamInfo streamInfo = {0}; 773 774 SetStreamInfo(streamInfo, streamCustomer, streamId, intent); // 填充StreamInfo流 775 if (streamInfo.bufferQueue_->producer_ == nullptr) { 776 CAMERA_LOGE("demo test: CreateStream CreateProducer(); is nullptr\n"); 777 return RC_ERROR; 778 } 779 780 std::vector<StreamInfo> streamInfos; 781 streamInfos.push_back(streamInfo); 782 783 rc = streamOperator_->CreateStreams(streamInfos); // 创建流 784 if (rc != HDI::Camera::V1_0::NO_ERROR) { 785 CAMERA_LOGE("demo test: CreateStream CreateStreams error\n"); 786 return RC_ERROR; 787 } 788 789 rc = streamOperator_->CommitStreams(NORMAL, cameraAbility_); 790 if (rc != HDI::Camera::V1_0::NO_ERROR) { 791 CAMERA_LOGE("demo test: CreateStream CommitStreams error\n"); 792 std::vector<int> streamIds; 793 streamIds.push_back(streamId); 794 streamOperator_->ReleaseStreams(streamIds); 795 return RC_ERROR; 796 } 797 798 CAMERA_LOGD("demo test: CreateStream exit"); 799 800 return RC_OK; 801 } 802 ``` 803 804 CaptureON()接口调用streamOperator的Capture()方法获取Camera数据并轮转buffer,拉起一个线程接收相应类型的数据。 805 806 ```c++ 807 RetCode OhosCameraDemo::CaptureON(const int streamId, 808 const int captureId, CaptureMode mode) 809 { 810 CAMERA_LOGI("demo test: CaptureON enter streamId == %{public}d and captureId == %{public}d and mode == %{public}d", 811 streamId, captureId, mode); 812 std::lock_guard<std::mutex> l(metaDatalock_); 813 if (mode == CAPTURE_SNAPSHOT) { 814 constexpr double latitude = 27.987500; // dummy data: Qomolangma latitde 815 constexpr double longitude = 86.927500; // dummy data: Qomolangma longituude 816 constexpr double altitude = 8848.86; // dummy data: Qomolangma altitude 817 constexpr size_t entryCapacity = 100; 818 constexpr size_t dataCapacity = 2000; 819 captureSetting_ = std::make_shared<CameraSetting>(entryCapacity, dataCapacity); 820 captureQuality_ = OHOS_CAMERA_JPEG_LEVEL_HIGH; 821 captureOrientation_ = OHOS_CAMERA_JPEG_ROTATION_270; 822 mirrorSwitch_ = OHOS_CAMERA_MIRROR_ON; 823 gps_.push_back(latitude); 824 gps_.push_back(longitude); 825 gps_.push_back(altitude); 826 captureSetting_->addEntry(OHOS_JPEG_QUALITY, static_cast<void*>(&captureQuality_), 827 sizeof(captureQuality_)); 828 captureSetting_->addEntry(OHOS_JPEG_ORIENTATION, static_cast<void*>(&captureOrientation_), 829 sizeof(captureOrientation_)); 830 captureSetting_->addEntry(OHOS_CONTROL_CAPTURE_MIRROR, static_cast<void*>(&mirrorSwitch_), 831 sizeof(mirrorSwitch_)); 832 captureSetting_->addEntry(OHOS_JPEG_GPS_COORDINATES, gps_.data(), gps_.size()); 833 } 834 835 std::vector<uint8_t> setting; 836 MetadataUtils::ConvertMetadataToVec(captureSetting_, setting); 837 captureInfo_.streamIds_ = {streamId}; 838 if (mode == CAPTURE_SNAPSHOT) { 839 captureInfo_.captureSetting_ = setting; 840 } else { 841 captureInfo_.captureSetting_ = cameraAbility_; 842 } 843 captureInfo_.enableShutterCallback_ = false; 844 845 int rc = streamOperator_->Capture(captureId, captureInfo_, true); // 实际capture开始,buffer轮转开始 846 if (rc != HDI::Camera::V1_0::NO_ERROR) { 847 CAMERA_LOGE("demo test: CaptureStart Capture error\n"); 848 streamOperator_->ReleaseStreams(captureInfo_.streamIds_); 849 return RC_ERROR; 850 } 851 852 if (mode == CAPTURE_PREVIEW) { 853 streamCustomerPreview_->ReceiveFrameOn(nullptr); // 创建预览线程接收传递上来的buffer 854 } else if (mode == CAPTURE_SNAPSHOT) { 855 streamCustomerCapture_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // 创建capture线程通过StoreImage回调接收传递上来的buffer 856 StoreImage(addr, size); 857 }); 858 } else if (mode == CAPTURE_VIDEO) { 859 OpenVideoFile(); 860 861 streamCustomerVideo_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // 创建video线程通过StoreImage回调接收传递上来的buffer 862 StoreVideo(addr, size); 863 }); 864 } 865 CAMERA_LOGD("demo test: CaptureON exit"); 866 867 return RC_OK; 868 } 869 ``` 870 8713. ManuList()函数从控制台通过fgets()接口获取字符,不同字符所对应demo支持的功能不同,并打印出该demo所支持功能的菜单。 872 873 ```c++ 874 static void ManuList(const std::shared_ptr<OhosCameraDemo>& mainDemo, 875 const int argc, char** argv) 876 { 877 int idx, c; 878 bool isAwb = true; 879 const char *shortOptions = "h:cwvaeqof:"; 880 c = getopt_long(argc, argv, shortOptions, LONG_OPTIONS, &idx); 881 while (1) { 882 switch (c) { 883 case 'h': 884 c = PutMenuAndGetChr(); // 打印菜单 885 break; 886 case 'f': 887 FlashLightTest(mainDemo); // 手电筒功能测试 888 c = PutMenuAndGetChr(); 889 break; 890 case 'o': 891 OfflineTest(mainDemo); // Offline功能测试 892 c = PutMenuAndGetChr(); 893 break; 894 case 'c': 895 CaptureTest(mainDemo); // Capture功能测试 896 c = PutMenuAndGetChr(); 897 break; 898 case 'w': // AWB功能测试 899 if (isAwb) { 900 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_INCANDESCENT); 901 } else { 902 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_OFF); 903 } 904 isAwb = !isAwb; 905 c = PutMenuAndGetChr(); 906 break; 907 case 'a': // AE功能测试 908 mainDemo->SetAeExpo(); 909 c = PutMenuAndGetChr(); 910 break; 911 case 'e': // Metadata测试 912 mainDemo->SetMetadata(); 913 c = PutMenuAndGetChr(); 914 break; 915 case 'v': // VIDEO功能测试 916 VideoTest(mainDemo); 917 c = PutMenuAndGetChr(); 918 break; 919 case 'q': // 退出demo 920 PreviewOff(mainDemo); 921 mainDemo->QuitDemo(); 922 return; 923 default: 924 CAMERA_LOGE("main test: command error please retry input command"); 925 c = PutMenuAndGetChr(); 926 break; 927 } 928 } 929 } 930 ``` 931 932 PutMenuAndGetChr()接口打印了demo程序的菜单,并调用fgets()等待从控制台输入命令,内容如下: 933 934 ```c++ 935 static int PutMenuAndGetChr(void) 936 { 937 constexpr uint32_t inputCount = 50; 938 int c = 0; 939 char strs[inputCount]; 940 Usage(stdout); 941 CAMERA_LOGD("pls input command(input -q exit this app)\n"); 942 fgets(strs, inputCount, stdin); 943 944 for (int i = 0; i < inputCount; i++) { 945 if (strs[i] != '-') { 946 c = strs[i]; 947 break; 948 } 949 } 950 return c; 951 } 952 ``` 953 954 控制台输出菜单详情如下: 955 956 ```c++ 957 "Options:\n" 958 "-h | --help Print this message\n" 959 "-o | --offline stream offline test\n" 960 "-c | --capture capture one picture\n" 961 "-w | --set WB Set white balance Cloudy\n" 962 "-v | --video capture Video of 10s\n" 963 "-a | --Set AE Set Auto exposure\n" 964 "-e | --Set Metadeta Set Metadata\n" 965 "-f | --Set Flashlight Set flashlight ON 5s OFF\n" 966 "-q | --quit stop preview and quit this app\n"); 967 ``` 968 9694. 编译用例 970 在drivers/peripheral/camera/BUILD.gn文件中的deps中添加“init:ohos_camera_demo”,示例代码如下: 971 ``` 972 deps = [ 973 "vdi_base/common/buffer_manager:camera_buffer_manager", 974 "vdi_base/common/device_manager:camera_device_manager", 975 "vdi_base/common/hdi_impl:camera_host_service_1.0", 976 "vdi_base/common/pipeline_core:camera_pipeline_core", 977 "vdi_base/common/utils:camera_utils", 978 "test/common:ohos_camera_demo", 979 ] 980 ``` 981 982 以RK3568为例: 983 1. 执行全量编译命令./build.sh --product-name rk3568 --ccache,生成可执行二进制文件ohos_camera_demo,路径为:out/rk3568/packages/phone/vendor/bin/。 984 2. 将可执行文件ohos_camera_demo导入开发板,修改权限直接运行即可。 985 986## 参考<a name="4"></a> 987 988### HCS配置文件说明 989 990针对Camera模块0penHarmony提供了默认的HCS配置。开发者若有特殊需求可自行修改相关的HCS配置文件。Camera模块HCS配置文件路径:`/vendor/hihope/rk3568/hdf_config/uhdf/camera`,其中: 991 992- `./hdi_impl/camera_host_config.hcs` 相机静态能力:包括镜头位置、镜头类型、连接类型、支持的曝光模式等,需要根据产品的具体规格来配置 993- `./pipeline_core/config.hcs` 主要是pipeline的连接方式,pipeline配置中包含支持的pipeline类型,每一种pipeline中包含的节点以及节点之间的连接关系 994 995 编译后在`/drivers/periphera/camra/vdi_base/common/pipeline_core/pipeline_impl/src/strategy/config`目录下生产`congfig.c`和`congfig.h`文件 996- `./pipeline_core/ipp_algo_config.hcs` 算法配置文件 997- `./pipeline_core/params.hcs` 场景、流类型名及其id定义,pipeline内部是以流id区分流类型的,所以此处需要添加定义 998 999 编译后在`/drivers/periphera/camra/vdi_base/common/pipeline_core/pipeline_impl/src/strategy/config`目录下生产`params.c`和`params.h`文件 1000 1001### Camera Dump使用指导 1002 1003#### 功能简介 1004Camera Dump功能为Camera相关功能的开发提供测试保障,根据需要配置开关文件即可开启此功能。 1005* 在流程的不同阶段提供buffer Dump功能,可帮助开发者快速定位图像问题点和数据,清晰直观地判断图像数据在哪个处理节点中出现问题。 1006* 对metadata的Dump可以判断metadata参数设置是否正确,还能确定不同参数对图像画质的影响。 1007 1008#### 源码目录说明 1009 1010 1011``` 1012/drivers/peripheral/camera/vdi_base/common/dump 1013├── include 1014│ └── camera_dump.h #Dump头文件 1015└── src 1016 └── camera_dump.cpp #Dump核心源码 1017``` 1018 1019 1020#### Dump配置文件说明 1021 1022Dump配置文件为dump.config,存放在开发设备 /data/local/tmp 目录中。 1023 1024 **表1** Dump开关说明 1025 1026| 开关 | **取值** | **描述** | **适用场景** | **输出数据格式**| 1027| -------- | -------- | -------- | -------- | -------- | 1028| enableDQBufDump | true/false | 开启开关,可以Dump v4l2_buffer.cpp文件中DequeueBuffer函数中的数据 | 预览、拍照、录像 | 板载相机:YUV420<br>USB相机:YUV422 | 1029| enableUVCNodeBufferDump | true/false | 开启开关,可以Dump uvc_node.cpp文件中YUV422To420函数转换前的数据 | 预览、拍照、录像 | USB相机:YUV422 | 1030| enableUVCNodeConvertedBufferDump | true/false | 开启开关,可以Dump uvc_node.cpp文件中YUV422To420函数转换后的数据 | 预览、拍照、录像 | USB相机:YUV420 | 1031| enableExifNodeConvertedBufferDump | true/false | 开启开关,可以Dump exif_node.cpp文件中DeliverBuffer函数中的数据 | 拍照 | JPEG | 1032| enableFaceNodeConvertedBufferDump | true/false | 开启开关,可以Dump face_node.cpp文件中DeliverBuffer函数中的数据 | 无(预留给后期使用) | 无 | 1033| enableForkNodeConvertedBufferDump | true/false | 开启开关,可以Dump fork_node.cpp文件中DeliverBuffer函数中的数据 | 预览、拍照、录像 | YUV422 | 1034| enableRKFaceNodeConvertedBufferDump | true/false | 开启开关,可以Dump rk_face_node.cpp文件中DeliverBuffer函数中的数据 | 无(预留给后期使用) | 无 | 1035| enableRKExifNodeConvertedBufferDump | true/false | 开启开关,可以Dump rk_exif_node.cpp文件中DeliverBuffer函数中的数据 | 拍照 | JPEG | 1036| enableCodecNodeConvertedBufferDump | true/false | 开启开关,可以Dump codec_node.cpp文件中DeliverBuffer函数中的数据 | 预览、拍照、录像 | JPEG、YUV420、RGBA8888 | 1037| enableRKCodecNodeConvertedBufferDump | true/false | 开启开关,可以Dump rk_codec_node.cpp文件中DeliverBuffer函数中的数据 | 预览、拍照、录像 | JPEG、H264、RGBA8888 | 1038| enableSreamTunnelBufferDump | true/false | 开启开关,可以Dump stream_tunnel.cpp文件中PutBuffer函数中的数据 | 预览、拍照、录像 | JPEG、H264、YUV420、RGBA8888 | 1039| enableMetadataDump | true/false | 开启Dump metadata 数据开关 | 预览、拍照、录像 | .meta | 1040 1041 1042除了上述开关,还可以配置Dump的采样间隔,如表2所示。 1043 1044 **表2** Dump采样间隔 1045 1046| Dump采样间隔 | **取值** | **描述** | 1047| -------- | -------- | -------- | 1048| previewInterval | int(大于等于1) | Dump预览间隔,默认1,每帧都Dump | 1049| videoInterval | int(大于等于1) | Dump录像间隔,默认1,每帧都Dump | 1050 1051#### 配置示例 1052 1053在本地计算机任意位置新建一个文件,命名为dump.config,根据以上开关,将要Dump的位置对应的开关写入文件中,值指定为true。 1054 1055完整配置: 1056 1057>__enableDQBufDump=true__<br/> 1058>enableUVCNodeBufferDump=false<br/> 1059>enableUVCNodeConvertedBufferDump=false<br/> 1060>enableExifNodeConvertedBufferDump=false<br/> 1061>enableFaceNodeConvertedBufferDump=false<br/> 1062>enableForkNodeConvertedBufferDump=false<br/> 1063>enableRKFaceNodeConvertedBufferDump=false<br/> 1064>enableRKExifNodeConvertedBufferDump=false<br/> 1065>enableCodecNodeConvertedBufferDump=false<br/> 1066>enableRKCodecNodeConvertedBufferDump=false<br/> 1067>enableSreamTunnelBufferDump=false<br/> 1068>**enableMetadataDump=true**<br/> 1069>**previewInterval=3**<br/> 1070>videoInterval=1<br/> 1071 1072 1073配置示例: 1074 1075例如,要Dump DequeueBuffer和metadata的数据,并且将Dump采样间隔设置为3,可以按上面加粗的配置修改。 1076 1077#### 开启Dump功能 10781. 将配置文件发送到开发设备的目录 /data/local/tmp 中。 1079 1080 ``` 1081 hdc file send dump.config /data/local/tmp 1082 ``` 1083 10842. 修改Dump目录权限。 1085 1086 ``` 1087 hdc shell mount -o rw,remount /data 1088 hdc shell chmod 777 /data/ -R 1089 ``` 1090 10913. 打开Dump。 1092 1093 ``` 1094 hdc shell "hidumper -s 5100 -a '-host camera_host -o'" 1095 ``` 1096 1097 * -s 5100 获取id为5100的元能力的全部信息,这里指Camera。 1098 * -a '-host camera_host -o'" 导出指定的系统元能力信息。 1099 * 详细的hidumper说明,请参考[HiDumper使用指导](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-dfx-hidumper.md)。 1100 1101 11024. 打开相机,进行预览、拍照和录像等操作。 1103 1104#### Dump结果 1105打开Dump后,会在设备的 /data/local/tmp 目录中生成Dump调测数据文件,将数据文件发送到本地电脑中后即可查看。 1106``` 1107hdc file recv /data/local/tmp/xxxx.yuv ~/ 1108``` 1109 1110 1111 1112