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 ![](figures/Camera模块驱动模型.png) 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_0/)。 51在HDI使用中下发的配置参数不能超出GetCameraAbility上报的能力范围。即使通过UpdateSettings、CommitStreams、Capture等接口可以下发超出该范围的配置参数,且接口调用不会返回失败,但设置后的行为是不确定的。 52- icamera_device.h 53 54 | 功能描述 | 接口名称 | 55 | ---------------------------- | ------------------------------------------------------------ | 56 | 获取流控制器 | int32_t GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj,<br>sptr<IStreamOperator>& streamOperator) | 57 | 更新设备控制参数 | int32_t UpdateSettings(const std::vector<uint8_t>& settings) | 58 | 设置Result回调模式和回调函数 | int32_t SetResultMode(ResultCallbackMode mode) | 59 | 获取使能的ResultMeta | int32_t GetEnabledResults(std::vector<int32_t>& results) | 60 | 使能具体的ResultMeta | int32_t EnableResult(const std::vector<int32_t>& results) | 61 | 禁止具体的ResultMeta | int32_t DisableResult(const std::vector<int32_t>& results) | 62 | 关闭Camera设备 | int32_t Close() | 63 64- icamera_device_callback.h 65 66 | 功能描述 | 接口名称 | 67 | ---------------------------------------------------------- | ------------------------------------------------------------ | 68 | 设备发生错误时调用,由调用者实现,用于返回错误信息给调用者 | int32_t OnError(ErrorType type, int32_t errorCode) | 69 | 上报camera设备相关的metadata的回调 | int32_t OnResult(uint64_t timestamp, const std::vector<uint8_t>& result) | 70 71 72- icamera_host.h 73 74 | 功能描述 | 接口名称 | 75 | ------------------------------ | ------------------------------------------------------------ | 76 | 设置ICameraHost回调接口 | int32_t SetCallback(const sptr<ICameraHostCallback>& callbackObj) | 77 | 获取当前可用的Camera设备ID列表 | int32_t GetCameraIds(std::vector<std::string>& cameraIds) | 78 | 获取Camera设备能力集合 | int32_t GetCameraAbility(const std::string& cameraId, std::vector<uint8_t>& cameraAbility) | 79 | 打开Camera设备 | int32_t OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj,<br>sptr<ICameraDevice>& device) | 80 | 打开或关闭闪光灯 | int32_t SetFlashlight(const std::string& cameraId, bool isEnable) | 81 82- icamera_host_callback.h 83 84 | 功能描述 | 接口名称 | 85 | ---------------------- | ------------------------------------------------------------ | 86 | Camera设备状态变化上报 | int32_t OnCameraStatus(const std::string& cameraId, CameraStatus status) | 87 | 闪光灯状态变化回调 | int32_t OnFlashlightStatus(const std::string& cameraId, FlashlightStatus status) | 88 | Camera事件回调 | int32_t OnCameraEvent(const std::string& cameraId, CameraEvent event) | 89 90- ioffline_stream_operator.h 91 92 | 功能描述 | 接口名称 | 93 | -------------- | ------------------------------------------------------------ | 94 | 取消捕获请求 | int32_t CancelCapture(int32_t captureId) | 95 | 释放流 | int32_t ReleaseStreams(const std::vector<int32_t>& streamIds) | 96 | 释放所有离线流 | int32_t Release() | 97 98- istream_operator.h 99 100 | 功能描述 | 接口名称 | 101 | -------------------------------- | ------------------------------------------------------------ | 102 | 查询是否支持添加参数对应的流 | int32_t IsStreamsSupported(<br>OperationMode mode,<br>const std::vector<uint8_t>& modeSetting,<br>const std::vector<StreamInfo>& infos,<br> StreamSupportType& type) | 103 | 创建流 | int32_t CreateStreams(const std::vector<StreamInfo>& streamInfos) | 104 | 释放流 | int32_t ReleaseStreams(const std::vector<int32_t>& streamIds) | 105 | 配置流 | int32_t CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) | 106 | 获取流的属性 | int32_t GetStreamAttributes(std::vector<StreamAttribute>& attributes) | 107 | 绑定生产者句柄和指定流 | int32_t AttachBufferQueue(int32_t streamId, const sptr<BufferProducerSequenceable>& bufferProducer) | 108 | 解除生产者句柄和指定流的绑定关系 | int32_t DetachBufferQueue(int32_t streamId) | 109 | 捕获图像 | int32_t Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) | 110 | 取消捕获 | int32_t CancelCapture(int32_t captureId) | 111 | 将指定流转换成离线流 | int32_t ChangeToOfflineStream(const std::vector<int32_t>& streamIds,<br>const sptr<IStreamOperatorCallback>& callbackObj,<br>sptr<IOfflineStreamOperator>& offlineOperator) | 112 113- istream_operator_callback.h 114 115 | 功能描述 | 接口名称 | 116 | ---------------------------------------- | ------------------------------------------------------------ | 117 | 捕获开始回调,在捕获开始时调用 | int32_t OnCaptureStarted(int32_t captureId, const std::vector<int32_t>& streamIds) | 118 | 捕获结束回调,在捕获结束时调用 | int32_t OnCaptureEnded(int32_t captureId, const std::vector<CaptureEndedInfo>& infos) | 119 | 捕获错误回调,在捕获过程中发生错误时调用 | int32_t OnCaptureError(int32_t captureId, const std::vector<CaptureErrorInfo>& infos) | 120 | 帧捕获回调 | int32_t OnFrameShutter(int32_t captureId, const std::vector<int32_t>& streamIds, uint64_t timestamp) | 121 122### 开发步骤<a name="7"></a> 123Camera驱动的开发过程主要包含以下步骤: 124 1251. 注册CameraHost 126 127 定义Camera的HdfDriverEntry结构体,该结构体中定义了CameraHost初始化的方法(代码目录drivers/peripheral/camera/interfaces/hdi_ipc/camera_host_driver.cpp)。 128 ```c++ 129 struct HdfDriverEntry g_cameraHostDriverEntry = { 130 .moduleVersion = 1, 131 .moduleName = "camera_service", 132 .Bind = HdfCameraHostDriverBind, 133 .Init = HdfCameraHostDriverInit, 134 .Release = HdfCameraHostDriverRelease, 135 }; 136 HDF_INIT(g_cameraHostDriverEntry); // 将Camera的HdfDriverEntry结构体注册到HDF上 137 ``` 138 1392. 初始化Host服务 140 141 步骤1中提到的HdfCameraHostDriverBind接口提供了CameraServiceDispatch和CameraHostStubInstance的注册。CameraServiceDispatch接口是远端调用CameraHost的方法,如OpenCamera(),SetFlashlight()等,CameraHostStubInstance接口是Camera设备的初始化,在开机时被调用。 142 143 ```c++ 144 static int HdfCameraHostDriverBind(struct HdfDeviceObject *deviceObject) 145 { 146 HDF_LOGI("HdfCameraHostDriverBind enter"); 147 148 auto *hdfCameraHostHost = new (std::nothrow) HdfCameraHostHost; 149 if (hdfCameraHostHost == nullptr) { 150 HDF_LOGE("%{public}s: failed to create HdfCameraHostHost object", __func__); 151 return HDF_FAILURE; 152 } 153 154 hdfCameraHostHost->ioService.Dispatch = CameraHostDriverDispatch; // 提供远端CameraHost调用方法 155 hdfCameraHostHost->ioService.Open = NULL; 156 hdfCameraHostHost->ioService.Release = NULL; 157 158 auto serviceImpl = ICameraHost::Get(true); 159 if (serviceImpl == nullptr) { 160 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 161 delete hdfCameraHostHost; 162 return HDF_FAILURE; 163 } 164 165 hdfCameraHostHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 166 ICameraHost::GetDescriptor()); // 初始化Camera设备 167 if (hdfCameraHostHost->stub == nullptr) { 168 HDF_LOGE("%{public}s: failed to get stub object", __func__); 169 delete hdfCameraHostHost; 170 return HDF_FAILURE; 171 } 172 173 deviceObject->service = &hdfCameraHostHost->ioService; 174 return HDF_SUCCESS; 175 } 176 ``` 177 178 下面的函数是远端CameraHost调用的方法: 179 180 ```c++ 181 int32_t CameraHostStub::CameraHostServiceStubOnRemoteRequest(int cmdId, MessageParcel &data, 182 MessageParcel &reply, MessageOption &option) 183 { 184 switch(cmdId) { 185 case CMD_CAMERA_HOST_SET_CALLBACK: { 186 return CameraHostStubSetCallback(data, reply, option); 187 } 188 case CMD_CAMERA_HOST_GET_CAMERAID: { 189 return CameraHostStubGetCameraIds(data, reply, option); 190 } 191 case CMD_CAMERA_HOST_GET_CAMERA_ABILITY: { 192 return CameraHostStubGetCameraAbility(data, reply, option); 193 } 194 case CMD_CAMERA_HOST_OPEN_CAMERA: { 195 return CameraHostStubOpenCamera(data, reply, option); 196 } 197 case CMD_CAMERA_HOST_SET_FLASH_LIGHT: { 198 return CameraHostStubSetFlashlight(data, reply, option); 199 } 200 default: { 201 HDF_LOGE("%s: not support cmd %d", __func__, cmdId); 202 return HDF_ERR_INVALID_PARAM; 203 } 204 } 205 return HDF_SUCCESS; 206 } 207 ``` 208 209 CameraHostStubInstance()接口最终调用CameraHostImpl::Init()方法,该方法会获取物理Camera,并对DeviceManager和PipelineCore进行初始化。 210 2113. 获取Host服务 212 213 调用Get()接口从远端CameraService中获取CameraHost对象。get()方法如下: 214 215 ```c++ 216 sptr<ICameraHost> ICameraHost::Get(const char *serviceName) 217 { 218 do { 219 using namespace OHOS::HDI::ServiceManager::V1_0; 220 auto servMgr = IServiceManager::Get(); 221 if (servMgr == nullptr) { 222 HDF_LOGE("%s: IServiceManager failed!", __func__); 223 break; 224 } 225 auto remote = servMgr->GetService(serviceName); // 根据serviceName名称获取CameraHost 226 if (remote != nullptr) { 227 sptr<CameraHostProxy> hostSptr = iface_cast<CameraHostProxy>(remote); // 将CameraHostProxy对象返回给调用者,该对象中包含OpenCamera()等方法。 228 return hostSptr; 229 } 230 HDF_LOGE("%s: GetService failed! serviceName = %s", __func__, serviceName); 231 } while(false); 232 HDF_LOGE("%s: get %s failed!", __func__, serviceName); 233 return nullptr; 234 } 235 ``` 236 2374. 打开设备 238 239 CameraHostProxy对象中有五个方法,分别是SetCallback、GetCameraIds、GetCameraAbility、OpenCamera和SetFlashlight。下面着重描述OpenCamera接口。 240 CameraHostProxy的OpenCamera()接口通过CMD_CAMERA_HOST_OPEN_CAMERA调用远端CameraHostStubOpenCamera()接口并获取ICameraDevice对象。 241 242 ```c++ 243 int32_t CameraHostProxy::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 244 sptr<ICameraDevice>& device) 245 { 246 MessageParcel cameraHostData; 247 MessageParcel cameraHostReply; 248 MessageOption cameraHostOption(MessageOption::TF_SYNC); 249 250 if (!cameraHostData.WriteInterfaceToken(ICameraHost::GetDescriptor())) { 251 HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__); 252 return HDF_ERR_INVALID_PARAM; 253 } 254 255 if (!cameraHostData.WriteCString(cameraId.c_str())) { 256 HDF_LOGE("%{public}s: write cameraId failed!", __func__); 257 return HDF_ERR_INVALID_PARAM; 258 } 259 260 if (!cameraHostData.WriteRemoteObject(OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(callbackObj, 261 ICameraDeviceCallback::GetDescriptor()))) { 262 HDF_LOGE("%{public}s: write callbackObj failed!", __func__); 263 return HDF_ERR_INVALID_PARAM; 264 } 265 266 int32_t cameraHostRet = Remote()->SendRequest(CMD_CAMERA_HOST_OPEN_CAMERA, cameraHostData, cameraHostReply, cameraHostOption); 267 if (cameraHostRet != HDF_SUCCESS) { 268 HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, cameraHostRet); 269 return cameraHostRet; 270 } 271 272 device = hdi_facecast<ICameraDevice>(cameraHostReply.ReadRemoteObject()); 273 274 return cameraHostRet; 275 } 276 ``` 277 278 Remote()->SendRequest调用上文提到的CameraHostServiceStubOnRemoteRequest(),根据cmdId进入CameraHostStubOpenCamera()接口,最终调用CameraHostImpl::OpenCamera(),该接口获取了CameraDevice并对硬件进行上电等操作。 279 280 ```c++ 281 int32_t CameraHostImpl::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 282 sptr<ICameraDevice>& device) 283 { 284 CAMERA_LOGD("OpenCamera entry"); 285 DFX_LOCAL_HITRACE_BEGIN; 286 if (CameraIdInvalid(cameraId) != RC_OK || callbackObj == nullptr) { 287 CAMERA_LOGW("open camera id is empty or callback is null."); 288 return INVALID_ARGUMENT; 289 } 290 291 auto itr = cameraDeviceMap_.find(cameraId); 292 if (itr == cameraDeviceMap_.end()) { 293 CAMERA_LOGE("camera device not found."); 294 return INSUFFICIENT_RESOURCES; 295 } 296 CAMERA_LOGD("OpenCamera cameraId find success."); 297 298 std::shared_ptr<CameraDeviceImpl> cameraDevice = itr->second; 299 if (cameraDevice == nullptr) { 300 CAMERA_LOGE("camera device is null."); 301 return INSUFFICIENT_RESOURCES; 302 } 303 304 CamRetCode ret = cameraDevice->SetCallback(callbackObj); 305 CHECK_IF_NOT_EQUAL_RETURN_VALUE(ret, HDI::Camera::V1_0::NO_ERROR, ret); 306 307 CameraHostConfig *config = CameraHostConfig::GetInstance(); 308 CHECK_IF_PTR_NULL_RETURN_VALUE(config, INVALID_ARGUMENT); 309 310 std::vector<std::string> phyCameraIds; 311 RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds); 312 if (rc != RC_OK) { 313 CAMERA_LOGE("get physic cameraId failed."); 314 return DEVICE_ERROR; 315 } 316 if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) { // 对Camera硬件上电 317 CAMERA_LOGE("camera powerup failed."); 318 CameraPowerDown(phyCameraIds); 319 return DEVICE_ERROR; 320 } 321 322 auto sptrDevice = deviceBackup_.find(cameraId); 323 if (sptrDevice == deviceBackup_.end()) { 324 #ifdef CAMERA_BUILT_ON_OHOS_LITE 325 deviceBackup_[cameraId] = cameraDevice; 326 #else 327 deviceBackup_[cameraId] = cameraDevice.get(); 328 #endif 329 } 330 device = deviceBackup_[cameraId]; 331 cameraDevice->SetStatus(true); 332 CAMERA_LOGD("open camera success."); 333 DFX_LOCAL_HITRACE_END; 334 return HDI::Camera::V1_0::NO_ERROR; 335 } 336 ``` 337 3385. 获取流 339 340 CameraDeviceImpl定义了GetStreamOperator、UpdateSettings、SetResultMode和GetEnabledResult等方法,获取流操作方法如下: 341 342 ```c++ 343 int32_t CameraDeviceImpl::GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj, 344 sptr<IStreamOperator>& streamOperator) 345 { 346 HDI_DEVICE_PLACE_A_WATCHDOG; 347 DFX_LOCAL_HITRACE_BEGIN; 348 if (callbackObj == nullptr) { 349 CAMERA_LOGW("input callback is null."); 350 return INVALID_ARGUMENT; 351 } 352 353 spCameraDeciceCallback_ = callbackObj; 354 if (spStreamOperator_ == nullptr) { 355 #ifdef CAMERA_BUILT_ON_OHOS_LITE 356 // 这里创建一个spStreamOperator_ 对象传递给调用者,以便对stream进行各种操作 357 spStreamOperator_ = std::make_shared<StreamOperator>(spCameraDeciceCallback_, shared_from_this()); 358 #else 359 spStreamOperator_ = new(std::nothrow) StreamOperator(spCameraDeciceCallback_, shared_from_this()); 360 #endif 361 if (spStreamOperator_ == nullptr) { 362 CAMERA_LOGW("create stream operator failed."); 363 return DEVICE_ERROR; 364 } 365 spStreamOperator_->Init(); 366 ismOperator_ = spStreamOperator_; 367 } 368 streamOperator = ismOperator_; 369 #ifndef CAMERA_BUILT_ON_OHOS_LITE 370 CAMERA_LOGI("CameraDeviceImpl %{public}s: line: %{public}d", __FUNCTION__, __LINE__); 371 pipelineCore_->GetStreamPipelineCore()->SetCallback( 372 [this](const std::shared_ptr<CameraMetadata> &metadata) { 373 OnMetadataChanged(metadata); 374 }); 375 #endif 376 DFX_LOCAL_HITRACE_END; 377 return HDI::Camera::V1_0::NO_ERROR; 378 } 379 ``` 380 3816. 创建流 382 383 调用CreateStreams创建流前需要填充StreamInfo结构体,具体内容如下: 384 385 ```c++ 386 using StreamInfo = struct _StreamInfo { 387 int streamId_; 388 int width_; // 数据流宽 389 int height_; // 数据流高 390 int format_; // 数据流格式,如PIXEL_FMT_YCRCB_420_SP 391 int dataSpace_; 392 StreamIntent intent_; // StreamIntent 如PREVIEW 393 bool tunneledMode_; 394 BufferProducerSequenceable bufferQueue_; // 数据流bufferQueue可用streamCustomer->CreateProducer()接口创建 395 int minFrameDuration_; 396 EncodeType encodeType_; 397 }; 398 ``` 399 400 CreateStreams()接口是StreamOperator(StreamOperatorImpl类是StreamOperator的基类)类中的方法,该接口的主要作用是创建一个StreamBase对象,通过StreamBase的Init方法初始化CreateBufferPool等操作。 401 402 ```c++ 403 int32_t StreamOperator::CreateStreams(const std::vector<StreamInfo>& streamInfos) 404 { 405 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 406 DFX_LOCAL_HITRACE_BEGIN; 407 for (const auto& it : streamInfos) { 408 CHECK_IF_NOT_EQUAL_RETURN_VALUE(CheckStreamInfo(it), true, INVALID_ARGUMENT); 409 CAMERA_LOGI("streamId:%{public}d and format:%{public}d and width:%{public}d and height:%{public}d", 410 it.streamId_, it.format_, it.width_, it.height_); 411 if (streamMap_.count(it.streamId_) > 0) { 412 CAMERA_LOGE("stream [id = %{public}d] has already been created.", it.streamId_); 413 return INVALID_ARGUMENT; 414 } 415 std::shared_ptr<IStream> stream = StreamFactory::Instance().CreateShared( // 创建Stream实例 416 IStream::g_availableStreamType[it.intent_], it.streamId_, it.intent_, pipelineCore_, messenger_); 417 if (stream == nullptr) { 418 CAMERA_LOGE("create stream [id = %{public}d] failed.", it.streamId_); 419 return INSUFFICIENT_RESOURCES; 420 } 421 StreamConfiguration scg; 422 StreamInfoToStreamConfiguration(scg, it); 423 RetCode rc = stream->ConfigStream(scg); 424 if (rc != RC_OK) { 425 CAMERA_LOGE("configure stream %{public}d failed", it.streamId_); 426 return INVALID_ARGUMENT; 427 } 428 if (!scg.tunnelMode && (it.bufferQueue_)->producer_ != nullptr) { 429 CAMERA_LOGE("stream [id:%{public}d] is not tunnel mode, can't bind a buffer producer", it.streamId_); 430 return INVALID_ARGUMENT; 431 } 432 if ((it.bufferQueue_)->producer_ != nullptr) { 433 auto tunnel = std::make_shared<StreamTunnel>(); 434 CHECK_IF_PTR_NULL_RETURN_VALUE(tunnel, INSUFFICIENT_RESOURCES); 435 rc = tunnel->AttachBufferQueue((it.bufferQueue_)->producer_); 436 CHECK_IF_NOT_EQUAL_RETURN_VALUE(rc, RC_OK, INVALID_ARGUMENT); 437 if (stream->AttachStreamTunnel(tunnel) != RC_OK) { 438 CAMERA_LOGE("attach buffer queue to stream [id = %{public}d] failed", it.streamId_); 439 return INVALID_ARGUMENT; 440 } 441 } 442 { 443 std::lock_guard<std::mutex> l(streamLock_); 444 streamMap_[stream->GetStreamId()] = stream; 445 } 446 CAMERA_LOGI("create stream success [id:%{public}d] [type:%{public}s]", stream->GetStreamId(), 447 IStream::g_availableStreamType[it.intent_].c_str()); 448 } 449 DFX_LOCAL_HITRACE_END; 450 return HDI::Camera::V1_0::NO_ERROR; 451 } 452 ``` 453 4547. 配置流 455 456 CommitStreams()是配置流的接口,必须在创建流之后调用,其主要作用是初始化Pipeline和创建Pipeline。 457 458 ```c++ 459 int32_t StreamOperator::CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) 460 { 461 CAMERA_LOGV("enter"); 462 CHECK_IF_PTR_NULL_RETURN_VALUE(streamPipeline_, DEVICE_ERROR); 463 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 464 if (modeSetting.empty()) { 465 CAMERA_LOGE("input vector is empty"); 466 return INVALID_ARGUMENT; 467 } 468 DFX_LOCAL_HITRACE_BEGIN; 469 470 std::vector<StreamConfiguration> configs = {}; 471 { 472 std::lock_guard<std::mutex> l(streamLock_); 473 std::transform(streamMap_.begin(), streamMap_.end(), std::back_inserter(configs), 474 [](auto &iter) { return iter.second->GetStreamAttribute(); }); 475 } 476 477 std::shared_ptr<CameraMetadata> setting; 478 MetadataUtils::ConvertVecToMetadata(modeSetting, setting); 479 DynamicStreamSwitchMode method = streamPipeline_->CheckStreamsSupported(mode, setting, configs); 480 if (method == DYNAMIC_STREAM_SWITCH_NOT_SUPPORT) { 481 return INVALID_ARGUMENT; 482 } 483 if (method == DYNAMIC_STREAM_SWITCH_NEED_INNER_RESTART) { 484 std::lock_guard<std::mutex> l(streamLock_); 485 for (auto it : streamMap_) { 486 it.second->StopStream(); 487 } 488 } 489 { 490 std::lock_guard<std::mutex> l(streamLock_); 491 for (auto it : streamMap_) { 492 if (it.second->CommitStream() != RC_OK) { 493 CAMERA_LOGE("commit stream [id = %{public}d] failed.", it.first); 494 return DEVICE_ERROR; 495 } 496 } 497 } 498 RetCode rc = streamPipeline_->PreConfig(setting); // 设备流配置 499 if (rc != RC_OK) { 500 CAMERA_LOGE("prepare mode settings failed"); 501 return DEVICE_ERROR; 502 } 503 rc = streamPipeline_->CreatePipeline(mode); // 创建一个pipeline 504 if (rc != RC_OK) { 505 CAMERA_LOGE("create pipeline failed."); 506 return INVALID_ARGUMENT; 507 } 508 509 DFX_LOCAL_HITRACE_END; 510 return HDI::Camera::V1_0::NO_ERROR; 511 } 512 ``` 513 5148. 捕获图像 515 516 在调用Capture()接口前需要先填充CaptureInfo结构体,具体内容如下: 517 518 ```c++ 519 using CaptureInfo = struct _CaptureInfo { 520 int[] streamIds_; // 需要Capture的streamIds 521 unsigned char[] captureSetting_; // 这里填充camera ability 可通过CameraHost 的GetCameraAbility()接口获取 522 bool enableShutterCallback_; 523 }; 524 ``` 525 526 StreamOperator中的Capture方法主要是捕获数据流: 527 528 ```c++ 529 int32_t StreamOperator::Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) 530 { 531 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 532 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 533 DFX_LOCAL_HITRACE_BEGIN; 534 535 for (auto id : info.streamIds_) { 536 std::lock_guard<std::mutex> l(streamLock_); 537 auto it = streamMap_.find(id); 538 if (it == streamMap_.end()) { 539 return INVALID_ARGUMENT; 540 } 541 } 542 543 { 544 std::lock_guard<std::mutex> l(requestLock_); 545 auto itr = requestMap_.find(captureId); 546 if (itr != requestMap_.end()) { 547 return INVALID_ARGUMENT; 548 } 549 } 550 551 std::shared_ptr<CameraMetadata> captureSetting; 552 MetadataUtils::ConvertVecToMetadata(info.captureSetting_, captureSetting); 553 CaptureSetting setting = captureSetting; 554 auto request = 555 std::make_shared<CaptureRequest>(captureId, info.streamIds_.size(), setting, 556 info.enableShutterCallback_, isStreaming); 557 for (auto id : info.streamIds_) { 558 RetCode rc = streamMap_[id]->AddRequest(request); 559 if (rc != RC_OK) { 560 return DEVICE_ERROR; 561 } 562 } 563 564 { 565 std::lock_guard<std::mutex> l(requestLock_); 566 requestMap_[captureId] = request; 567 } 568 return HDI::Camera::V1_0::NO_ERROR; 569 } 570 ``` 571 5729. 取消捕获和释放离线流 573 574 StreamOperator类中的CancelCapture()接口的主要作用是根据captureId取消数据流的捕获。 575 576 ```c++ 577 int32_t StreamOperator::CancelCapture(int32_t captureId) 578 { 579 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 580 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 581 DFX_LOCAL_HITRACE_BEGIN; 582 583 std::lock_guard<std::mutex> l(requestLock_); 584 auto itr = requestMap_.find(captureId); // 根据captureId 在Map中查找对应的CameraCapture对象 585 if (itr == requestMap_.end()) { 586 CAMERA_LOGE("can't cancel capture [id = %{public}d], this capture doesn't exist", captureId); 587 return INVALID_ARGUMENT; 588 } 589 590 RetCode rc = itr->second->Cancel(); // 调用CameraCapture中Cancel方法结束数据捕获 591 if (rc != RC_OK) { 592 return DEVICE_ERROR; 593 } 594 requestMap_.erase(itr); // 擦除该CameraCapture对象 595 596 DFX_LOCAL_HITRACE_END; 597 return HDI::Camera::V1_0::NO_ERROR; 598 } 599 ``` 600 601 StreamOperator类中的ReleaseStreams接口的主要作用是释放之前通过CreateStream()和CommitStreams()接口创建的流,并销毁Pipeline。 602 603 ```c++ 604 int32_t StreamOperator::ReleaseStreams(const std::vector<int32_t>& streamIds) 605 { 606 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 607 DFX_LOCAL_HITRACE_BEGIN; 608 for (auto id : streamIds) { 609 std::lock_guard<std::mutex> l(streamLock_); 610 auto it = streamMap_.find(id); 611 if (it == streamMap_.end()) { 612 continue; 613 } 614 if (it->second->IsRunning()) { 615 it->second->StopStream(); 616 } 617 it->second->DumpStatsInfo(); 618 streamMap_.erase(it); 619 } 620 621 for (auto id : streamIds) { 622 CHECK_IF_EQUAL_RETURN_VALUE(id < 0, true, INVALID_ARGUMENT); 623 } 624 625 DFX_LOCAL_HITRACE_END; 626 return HDI::Camera::V1_0::NO_ERROR; 627 } 628 ``` 629 63010. 关闭Camera设备 631 632 调用CameraDeviceImpl中的Close()来关闭CameraDevice,该接口调用deviceManager中的PowerDown()来给设备下电。 633 634### 开发实例<a name = "8"></a> 635 636在/drivers/peripheral/camera/hal/init目录下有一个关于Camera的demo,开机后会在/vendor/bin下生成可执行文件ohos_camera_demo,该demo可以完成Camera的预览,拍照等基础功能。下面我们就以此demo为例讲述怎样用HDI接口去编写预览PreviewOn()和拍照CaptureON()的用例,可参考[ohos_camera_demo](https://gitee.com/openharmony/drivers_peripheral/tree/OpenHarmony-3.2-Release/camera/hal/init)。 637 6381. 在main函数中构造一个CameraDemo 对象,该对象中有对Camera初始化、启停流、释放等控制的方法。下面mainDemo->InitSensors()函数为初始化CameraHost,mainDemo->InitCameraDevice()函数为初始化CameraDevice。 639 640 ```c++ 641 int main(int argc, char** argv) 642 { 643 RetCode rc = RC_OK; 644 auto mainDemo = std::make_shared<CameraDemo>(); 645 rc = mainDemo->InitSensors(); // 初始化CameraHost 646 if (rc == RC_ERROR) { 647 CAMERA_LOGE("main test: mainDemo->InitSensors() error\n"); 648 return -1; 649 } 650 651 rc = mainDemo->InitCameraDevice(); // 初始化CameraDevice 652 if (rc == RC_ERROR) { 653 CAMERA_LOGE("main test: mainDemo->InitCameraDevice() error\n"); 654 return -1; 655 } 656 657 rc = PreviewOn(0, mainDemo); // 配流和启流 658 if (rc != RC_OK) { 659 CAMERA_LOGE("main test: PreviewOn() error demo exit"); 660 return -1; 661 } 662 663 ManuList(mainDemo, argc, argv); // 打印菜单到控制台 664 665 return RC_OK; 666 } 667 ``` 668 669 初始化CameraHost函数实现如下,这里调用了HDI接口ICameraHost::Get()去获取demoCameraHost,并对其设置回调函数。 670 671 ```c++ 672 RetCode OhosCameraDemo::InitSensors() 673 { 674 int rc = 0; 675 676 CAMERA_LOGD("demo test: InitSensors enter"); 677 678 if (demoCameraHost_ != nullptr) { 679 return RC_OK; 680 } 681 #ifdef CAMERA_BUILT_ON_OHOS_LITE 682 demoCameraHost_ = OHOS::Camera::CameraHost::CreateCameraHost(); 683 #else 684 constexpr const char *DEMO_SERVICE_NAME = "camera_service"; 685 demoCameraHost_ = ICameraHost::Get(DEMO_SERVICE_NAME, false); 686 #endif 687 if (demoCameraHost_ == nullptr) { 688 CAMERA_LOGE("demo test: ICameraHost::Get error"); 689 return RC_ERROR; 690 } 691 692 #ifdef CAMERA_BUILT_ON_OHOS_LITE 693 hostCallback_ = std::make_shared<DemoCameraHostCallback>(); 694 #else 695 hostCallback_ = new DemoCameraHostCallback(); 696 #endif 697 rc = demoCameraHost_->SetCallback(hostCallback_); 698 if (rc != HDI::Camera::V1_0::NO_ERROR) { 699 CAMERA_LOGE("demo test: demoCameraHost_->SetCallback(hostCallback_) error"); 700 return RC_ERROR; 701 } 702 703 CAMERA_LOGD("demo test: InitSensors exit"); 704 705 return RC_OK; 706 } 707 ``` 708 709 初始化CameraDevice函数实现如下,这里调用了GetCameraIds(cameraIds_),GetCameraAbility(cameraId, ability_),OpenCamera(cameraIds_.front(), callback, demoCameraDevice_)等接口实现了demoCameraHost的获取。 710 711 ```c++ 712 RetCode OhosCameraDemo::InitCameraDevice() 713 { 714 int rc = 0; 715 716 CAMERA_LOGD("demo test: InitCameraDevice enter"); 717 718 if (demoCameraHost_ == nullptr) { 719 CAMERA_LOGE("demo test: InitCameraDevice demoCameraHost_ == nullptr"); 720 return RC_ERROR; 721 } 722 723 (void)demoCameraHost_->GetCameraIds(cameraIds_); 724 if (cameraIds_.empty()) { 725 return RC_ERROR; 726 } 727 const std::string cameraId = cameraIds_.front(); 728 demoCameraHost_->GetCameraAbility(cameraId, cameraAbility_); 729 730 MetadataUtils::ConvertVecToMetadata(cameraAbility_, ability_); 731 732 GetFaceDetectMode(ability_); 733 GetFocalLength(ability_); 734 GetAvailableFocusModes(ability_); 735 GetAvailableExposureModes(ability_); 736 GetExposureCompensationRange(ability_); 737 GetExposureCompensationSteps(ability_); 738 GetAvailableMeterModes(ability_); 739 GetAvailableFlashModes(ability_); 740 GetMirrorSupported(ability_); 741 GetStreamBasicConfigurations(ability_); 742 GetFpsRange(ability_); 743 GetCameraPosition(ability_); 744 GetCameraType(ability_); 745 GetCameraConnectionType(ability_); 746 GetFaceDetectMaxNum(ability_); 747 748 #ifdef CAMERA_BUILT_ON_OHOS_LITE 749 std::shared_ptr<CameraDeviceCallback> callback = std::make_shared<CameraDeviceCallback>(); 750 #else 751 sptr<DemoCameraDeviceCallback> callback = new DemoCameraDeviceCallback(); 752 #endif 753 rc = demoCameraHost_->OpenCamera(cameraIds_.front(), callback, demoCameraDevice_); 754 if (rc != HDI::Camera::V1_0::NO_ERROR || demoCameraDevice_ == nullptr) { 755 CAMERA_LOGE("demo test: InitCameraDevice OpenCamera failed"); 756 return RC_ERROR; 757 } 758 759 CAMERA_LOGD("demo test: InitCameraDevice exit"); 760 761 return RC_OK; 762 } 763 ``` 764 7652. PreviewOn()接口包含配置流、开启预览流和启动Capture动作。该接口执行完成后Camera预览通路已经开始运转并开启了两路流,一路流是preview,另外一路流是capture或者video,两路流中仅对preview流进行capture动作。 766 767 ```c++ 768 static RetCode PreviewOn(int mode, const std::shared_ptr<OhosCameraDemo>& mainDemo) 769 { 770 RetCode rc = RC_OK; 771 CAMERA_LOGD("main test: PreviewOn enter"); 772 773 rc = mainDemo->StartPreviewStream(); // 配置preview流 774 if (rc != RC_OK) { 775 CAMERA_LOGE("main test: PreviewOn StartPreviewStream error"); 776 return RC_ERROR; 777 } 778 779 if (mode == 0) { 780 rc = mainDemo->StartCaptureStream(); // 配置capture流 781 if (rc != RC_OK) { 782 CAMERA_LOGE("main test: PreviewOn StartCaptureStream error"); 783 return RC_ERROR; 784 } 785 } else { 786 rc = mainDemo->StartVideoStream(); // 配置video流 787 if (rc != RC_OK) { 788 CAMERA_LOGE("main test: PreviewOn StartVideoStream error"); 789 return RC_ERROR; 790 } 791 } 792 793 rc = mainDemo->CaptureON(STREAM_ID_PREVIEW, CAPTURE_ID_PREVIEW, CAPTURE_PREVIEW); 794 if (rc != RC_OK) { 795 CAMERA_LOGE("main test: PreviewOn mainDemo->CaptureON() preview error"); 796 return RC_ERROR; 797 } 798 799 CAMERA_LOGD("main test: PreviewOn exit"); 800 return RC_OK; 801 } 802 ``` 803 804 StartCaptureStream()、StartVideoStream()和StartPreviewStream()接口都会调用CreateStream()接口,只是传入的参数不同。 805 806 CreateStream()方法调用HDI接口去配置和创建流,首先调用HDI接口去获取StreamOperation对象,然后创建一个StreamInfo。调用CreateStreams()和CommitStreams()实际创建流并配置流。 807 808 ```c++ 809 RetCode OhosCameraDemo::CreateStream(const int streamId, std::shared_ptr<StreamCustomer> &streamCustomer, 810 StreamIntent intent) 811 { 812 int rc = 0; 813 CAMERA_LOGD("demo test: CreateStream enter"); 814 815 GetStreamOpt(); // 获取StreamOperator对象 816 if (streamOperator_ == nullptr) { 817 CAMERA_LOGE("demo test: CreateStream GetStreamOpt() is nullptr\n"); 818 return RC_ERROR; 819 } 820 821 StreamInfo streamInfo = {0}; 822 823 SetStreamInfo(streamInfo, streamCustomer, streamId, intent); // 填充StreamInfo流 824 if (streamInfo.bufferQueue_->producer_ == nullptr) { 825 CAMERA_LOGE("demo test: CreateStream CreateProducer(); is nullptr\n"); 826 return RC_ERROR; 827 } 828 829 std::vector<StreamInfo> streamInfos; 830 streamInfos.push_back(streamInfo); 831 832 rc = streamOperator_->CreateStreams(streamInfos); // 创建流 833 if (rc != HDI::Camera::V1_0::NO_ERROR) { 834 CAMERA_LOGE("demo test: CreateStream CreateStreams error\n"); 835 return RC_ERROR; 836 } 837 838 rc = streamOperator_->CommitStreams(NORMAL, cameraAbility_); 839 if (rc != HDI::Camera::V1_0::NO_ERROR) { 840 CAMERA_LOGE("demo test: CreateStream CommitStreams error\n"); 841 std::vector<int> streamIds; 842 streamIds.push_back(streamId); 843 streamOperator_->ReleaseStreams(streamIds); 844 return RC_ERROR; 845 } 846 847 CAMERA_LOGD("demo test: CreateStream exit"); 848 849 return RC_OK; 850 } 851 ``` 852 853 CaptureON()接口调用streamOperator的Capture()方法获取Camera数据并轮转buffer,拉起一个线程接收相应类型的数据。 854 855 ```c++ 856 RetCode OhosCameraDemo::CaptureON(const int streamId, 857 const int captureId, CaptureMode mode) 858 { 859 CAMERA_LOGI("demo test: CaptureON enter streamId == %{public}d and captureId == %{public}d and mode == %{public}d", 860 streamId, captureId, mode); 861 std::lock_guard<std::mutex> l(metaDatalock_); 862 if (mode == CAPTURE_SNAPSHOT) { 863 constexpr double latitude = 27.987500; // dummy data: Qomolangma latitde 864 constexpr double longitude = 86.927500; // dummy data: Qomolangma longituude 865 constexpr double altitude = 8848.86; // dummy data: Qomolangma altitude 866 constexpr size_t entryCapacity = 100; 867 constexpr size_t dataCapacity = 2000; 868 captureSetting_ = std::make_shared<CameraSetting>(entryCapacity, dataCapacity); 869 captureQuality_ = OHOS_CAMERA_JPEG_LEVEL_HIGH; 870 captureOrientation_ = OHOS_CAMERA_JPEG_ROTATION_270; 871 mirrorSwitch_ = OHOS_CAMERA_MIRROR_ON; 872 gps_.push_back(latitude); 873 gps_.push_back(longitude); 874 gps_.push_back(altitude); 875 captureSetting_->addEntry(OHOS_JPEG_QUALITY, static_cast<void*>(&captureQuality_), 876 sizeof(captureQuality_)); 877 captureSetting_->addEntry(OHOS_JPEG_ORIENTATION, static_cast<void*>(&captureOrientation_), 878 sizeof(captureOrientation_)); 879 captureSetting_->addEntry(OHOS_CONTROL_CAPTURE_MIRROR, static_cast<void*>(&mirrorSwitch_), 880 sizeof(mirrorSwitch_)); 881 captureSetting_->addEntry(OHOS_JPEG_GPS_COORDINATES, gps_.data(), gps_.size()); 882 } 883 884 std::vector<uint8_t> setting; 885 MetadataUtils::ConvertMetadataToVec(captureSetting_, setting); 886 captureInfo_.streamIds_ = {streamId}; 887 if (mode == CAPTURE_SNAPSHOT) { 888 captureInfo_.captureSetting_ = setting; 889 } else { 890 captureInfo_.captureSetting_ = cameraAbility_; 891 } 892 captureInfo_.enableShutterCallback_ = false; 893 894 int rc = streamOperator_->Capture(captureId, captureInfo_, true); // 实际capture开始,buffer轮转开始 895 if (rc != HDI::Camera::V1_0::NO_ERROR) { 896 CAMERA_LOGE("demo test: CaptureStart Capture error\n"); 897 streamOperator_->ReleaseStreams(captureInfo_.streamIds_); 898 return RC_ERROR; 899 } 900 901 if (mode == CAPTURE_PREVIEW) { 902 streamCustomerPreview_->ReceiveFrameOn(nullptr); // 创建预览线程接收传递上来的buffer 903 } else if (mode == CAPTURE_SNAPSHOT) { 904 streamCustomerCapture_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // 创建capture线程通过StoreImage回调接收传递上来的buffer 905 StoreImage(addr, size); 906 }); 907 } else if (mode == CAPTURE_VIDEO) { 908 OpenVideoFile(); 909 910 streamCustomerVideo_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // 创建video线程通过StoreImage回调接收传递上来的buffer 911 StoreVideo(addr, size); 912 }); 913 } 914 CAMERA_LOGD("demo test: CaptureON exit"); 915 916 return RC_OK; 917 } 918 ``` 919 9203. ManuList()函数从控制台通过fgets()接口获取字符,不同字符所对应demo支持的功能不同,并打印出该demo所支持功能的菜单。 921 922 ```c++ 923 static void ManuList(const std::shared_ptr<OhosCameraDemo>& mainDemo, 924 const int argc, char** argv) 925 { 926 int idx, c; 927 bool isAwb = true; 928 const char *shortOptions = "h:cwvaeqof:"; 929 c = getopt_long(argc, argv, shortOptions, LONG_OPTIONS, &idx); 930 while (1) { 931 switch (c) { 932 case 'h': 933 c = PutMenuAndGetChr(); // 打印菜单 934 break; 935 case 'f': 936 FlashLightTest(mainDemo); // 手电筒功能测试 937 c = PutMenuAndGetChr(); 938 break; 939 case 'o': 940 OfflineTest(mainDemo); // Offline功能测试 941 c = PutMenuAndGetChr(); 942 break; 943 case 'c': 944 CaptureTest(mainDemo); // Capture功能测试 945 c = PutMenuAndGetChr(); 946 break; 947 case 'w': // AWB功能测试 948 if (isAwb) { 949 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_INCANDESCENT); 950 } else { 951 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_OFF); 952 } 953 isAwb = !isAwb; 954 c = PutMenuAndGetChr(); 955 break; 956 case 'a': // AE功能测试 957 mainDemo->SetAeExpo(); 958 c = PutMenuAndGetChr(); 959 break; 960 case 'e': // Metadata测试 961 mainDemo->SetMetadata(); 962 c = PutMenuAndGetChr(); 963 break; 964 case 'v': // VIDEO功能测试 965 VideoTest(mainDemo); 966 c = PutMenuAndGetChr(); 967 break; 968 case 'q': // 退出demo 969 PreviewOff(mainDemo); 970 mainDemo->QuitDemo(); 971 return; 972 default: 973 CAMERA_LOGE("main test: command error please retry input command"); 974 c = PutMenuAndGetChr(); 975 break; 976 } 977 } 978 } 979 ``` 980 981 PutMenuAndGetChr()接口打印了demo程序的菜单,并调用fgets()等待从控制台输入命令,内容如下: 982 983 ```c++ 984 static int PutMenuAndGetChr(void) 985 { 986 constexpr uint32_t inputCount = 50; 987 int c = 0; 988 char strs[inputCount]; 989 Usage(stdout); 990 CAMERA_LOGD("pls input command(input -q exit this app)\n"); 991 fgets(strs, inputCount, stdin); 992 993 for (int i = 0; i < inputCount; i++) { 994 if (strs[i] != '-') { 995 c = strs[i]; 996 break; 997 } 998 } 999 return c; 1000 } 1001 ``` 1002 1003 控制台输出菜单详情如下: 1004 1005 ```c++ 1006 "Options:\n" 1007 "-h | --help Print this message\n" 1008 "-o | --offline stream offline test\n" 1009 "-c | --capture capture one picture\n" 1010 "-w | --set WB Set white balance Cloudy\n" 1011 "-v | --video capture Video of 10s\n" 1012 "-a | --Set AE Set Auto exposure\n" 1013 "-e | --Set Metadeta Set Metadata\n" 1014 "-f | --Set Flashlight Set flashlight ON 5s OFF\n" 1015 "-q | --quit stop preview and quit this app\n"); 1016 ``` 1017 10184. 编译用例 1019 在drivers/peripheral/camera/hal/BUILD.gn文件中的deps中添加“init:ohos_camera_demo”,示例代码如下: 1020 ``` 1021 deps = [ 1022 "buffer_manager:camera_buffer_manager", 1023 "device_manager:camera_device_manager", 1024 "hdi_impl:camera_host_service_1.0", 1025 "pipeline_core:camera_pipeline_core", 1026 "utils:camera_utils", 1027 "init:ohos_camera_demo", 1028 ] 1029 ``` 1030 1031 以RK3568为例: 1032 1. 执行全量编译命令./build.sh --product-name rk3568 --ccache,生成可执行二进制文件ohos_camera_demo,路径为:out/rk3568/packages/phone/vendor/bin/。 1033 2. 将可执行文件ohos_camera_demo导入开发板,修改权限直接运行即可。 1034