1# Camera 2 3## Overview 4### Function 5 6The OpenHarmony camera driver model provides the camera hardware device interface (HDI) and the camera pipeline model to manage camera devices. 7The camera driver model is divided into three layers: 8 9+ HDI implementation layer: implements standard ohos (OpenHarmony operating system) APIs for cameras. 10+ Framework layer: interacts with the HDI implementation layer to set up data channels and operate camera devices. 11+ Device adaptation layer: supports different platforms by shielding the differences in underlying chips and operating systems. 12 13### Working Principles 14 15The camera module is used to initialize services and devices, set up data channels, and configure, create, deliver, and capture streams. The following figure shows the camera driver model. 16 17**Figure 1** HDF-based camera driver model 18 19![](figures/camera-driver-model-architecture.png) 20 211. When the system starts, the camera_host process is created. The process enumerates underlying devices, creates a **DeviceManager** instance (to manage the device tree), an object for each underlying device, and a **CameraHost** instance, and registers the **CameraHost** instance with the user-mode HDF (UHDF) service. Through the UHDF service, the camera service can obtain the underlying **CameraDeviceHost** services to operate the hardware devices. The **DeviceManager** instance can also be created by using the configuration table. 22 232. The Camera Service obtains the **CameraHost** instance through the CameraDeviceHost service. 24 25 The **CameraHost** instance can be used to obtain the underlying camera capabilities, turn on the flashlight, call **Open()** to start a camera and set up a connection with the camera, create a **DeviceManager** instance (to power on the hardware modules), and create a **CameraDevice** instance (to provide the device control interface for the upper layer). 26 27 When the **CameraDevice** instance is created, the PipelineCore modules will be instantiated. The StreamPipelineCore module creates pipelines, and the MetaQueueManager module reports metadata. 28 293. The Camera Service configures stream and creates a **Stream** class through the CameraDevice module. The StreamPipelineStrategy module creates the node connection mode of the corresponding stream by using the mode issued by the upper layer and querying the configuration table. The StreamPipelineBuilder module creates a node and returns the pipeline to the StreamPipelineDispatcher module through the connection. The StreamPipelineDispatcher module dispatches pipelines. 30 314. The Camera Service controls the stream operations through the **Stream** instance. 32 33 **AttachBufferQueue()** delivers the buffer queue requested from the display module to the bottom layer. The CameraDeviceDriverModel manages the buffer. After **Capture()** is called to deliver commands, the bottom layer transfers the buffer to the upper layer. The Image Signal Processor (ISP) node obtains a specified number of buffers from the buffer queue and delivers the buffers to the bottom-layer ISP hardware. After filling the buffers, the ISP hardware transfers the buffers to the CameraDeviceDriverModel. The CameraDeviceDriverModel fills the created pipeline with the received buffers by using a loop thread. Each node processes the pipeline data and transfers the data to the upper layer in a callback. At the same time, the buffers are freed to the buffer queue for reuse. 34 355. The Camera Service delivers the photographing command through **Capture()**. **ChangeToOfflineStream()** is used to query the position of the photographing buffer. If the ISP hardware has output an image and sent the image data to the IPP node, the common photographing stream can be converted into an offline stream. Otherwise, the close process is executed. **ChangeToOfflineStream()** passes **StreamInfo** to enable the offline stream to obtain the stream information of the common stream, determines the node connection mode of the offline stream based on the configuration table, and creates the node connection for the offline stream (if the node connection has been created, the node required by the non-offline stream will be closed by **CloseCamera**.) When the buffer is transferred from the pipeline to the upper layer, the pipeline resources are released. 36 376. The Camera Service sends the **CaptureSetting** parameter to the CameraDeviceDriverModel through **UpdateSettings()** of the **CameraDevice** instance. The CameraDeviceDriverModel forwards the parameter to each node through the StreamPipelineDispatcher module. The **CaptureSetting** parameter carried in **StartStreamingCapture()** and **Capture()** is forwarded to the node to which the stream belongs through the StreamPipelineDispatcher module. 38 397. The Camera Service uses **EnableResult()** and **DisableResult()** to control the reporting of underlying metadata. If the underlying metadata needs to be reported, the pipeline creates a buffer queue in the CameraDeviceDriverModel to collect and transfer metadata, queries the configuration table based on the StreamPipelineStrategy module, and creates and connects to the specified node through the StreamPipelineBuilder module. The MetaQueueManager module delivers the buffer to the bottom layer, and the bottom-layer node fills in data. The MetaQueueManager module then invokes the upper-layer callback to transfer the data to the upper layer. 40 418. The Camera Service calls **Close()** of the **CameraDevice** class, and the **CameraDevice** instance calls the corresponding DeviceManager module to power off each hardware. If an offline stream exists in the subpipeline of the IPP node, the offline stream must be reserved until the execution is complete. 42 439. To implement dynamic frame control, a CollectBuffer thread is started in the StreamOperator. The CollectBuffer thread obtains a buffer from the buffer queue of each stream. If the frame rate of a stream needs to be controlled (1/n of the sensor output frame rate), the CollectBuffer thread can control the buffer packaging of each frame as required, and determine whether to collect the buffer of the stream. For example, if the output frame rate of the sensor is 120 fps and the preview stream frame rate is 30 fps, the CollectBuffer thread collects the buffer of the preview stream every 4 fps. 44 45 46 47## Development Guidelines 48 49 50### When to Use 51 52The camera module encapsulates camera operations in camera preview, photographing, and video streams to implement camera hardware operations and improve development efficiency. 53 54### Available APIs 55 56The following table describes the C++ APIs generated from the Interface Definition Language (IDL) interface description. For details about the interface declaration, see the .idl file in **/drivers/interface/camera/v1_0/**. 57The parameters passed in the HDI cannot exceed the capability range obtained by **GetCameraAbility**. Even if the parameters beyond the capability range can be passed in APIs such as **UpdateSettings**, **CommitStreams**, and **Capture** with no error returned, unexpected behavior may be caused. 58- icamera_device.h 59 60 | API | Description | 61 | ---------------------------- | ------------------------------------------------------------ | 62 | int32_t GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj, sptr<IStreamOperator>& streamOperator) | Obtains the stream controller. | 63 | int32_t UpdateSettings(const std::vector<uint8_t>& settings) | Updates device control parameters. | 64 | int32_t SetResultMode(ResultCallbackMode mode) | Sets the result callback mode and function.| 65 | int32_t GetEnabledResults(std::vector<int32_t>& results) | Obtains the enabled ResultMeta. | 66 | int32_t EnableResult(const std::vector<int32_t>& results) | Enables specific ResultMeta. | 67 | int32_t DisableResult(const std::vector<int32_t>& results) | Disables specific ResultMeta. | 68 | int32_t Close() | Closes the camera device. | 69 70- icamera_device_callback.h 71 72 | API | Description | 73 | ------------------------------------------------------------ | ------------------------------------------------------------ | 74 | int32_t OnError(ErrorType type, int32_t errorCode) | Called when an error occurs on the camera device. The caller needs to implement this API. | 75 | int32_t OnResult(uint64_t timestamp, const std::vector<uint8_t>& result) | Called to report metadata related to the camera device. | 76 77 78- icamera_host.h 79 80 | API | Description | 81 | ------------------------------------------------------------ | ------------------------------------------------------------ | 82 | int32_t SetCallback(const sptr<ICameraHostCallback>& callbackObj) | Sets the **ICameraHostCallback** API. | 83 | int32_t GetCameraIds(std::vector<std::string>& cameraIds) | Obtains the IDs of available camera devices. | 84 | int32_t GetCameraAbility(const std::string& cameraId, std::vector<uint8_t>& cameraAbility) | Obtains the abilities of a camera device. | 85 | int32_t OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, sptr<ICameraDevice>& device) | Opens a camera. | 86 | int32_t SetFlashlight(const std::string& cameraId, bool isEnable) | Turns on or off the flash. | 87 88- icamera_host_callback.h 89 90 | API | Description | 91 | ------------------------------------------------------------ | ------------------------------------------------------------ | 92 | int32_t OnCameraStatus(const std::string& cameraId, CameraStatus status) | Called to report camera status changes. | 93 | int32_t OnFlashlightStatus(const std::string& cameraId, FlashlightStatus status) | Called to report the flash status changes. | 94 | int32_t OnCameraEvent(const std::string& cameraId, CameraEvent event) | Called to report a camera event. | 95 96- ioffline_stream_operator.h 97 98 | API | Description | 99 | ---- | ---- | 100 | int32_t CancelCapture(int32_t captureId) | Cancels a capture request. | 101 | int32_t ReleaseStreams(const std::vector<int32_t>& streamIds) | Releases streams. | 102 | int32_t Release() | Releases all offline streams. | 103 104- istream_operator.h 105 106 | API | Description | 107 | ------------------------------------------------------------ | ------------------------------------------------------------ | 108 | int32_t IsStreamsSupported(OperationMode mode,<br>const std::vector<uint8_t>& modeSetting,<br>const std::vector<StreamInfo>& infos,<br> StreamSupportType& type) | Checks whether a stream can be added. | 109 | int32_t CreateStreams(const std::vector<StreamInfo>& streamInfos) | Creates streams. | 110 | int32_t ReleaseStreams(const std::vector<int32_t>& streamIds) | Releases streams. | 111 | int32_t CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) | Configure streams. | 112 | int32_t GetStreamAttributes(std::vector<StreamAttribute>& attributes) | Obtain stream attributes. | 113 | int32_t AttachBufferQueue(int32_t streamId, const sptr<BufferProducerSequenceable>& bufferProducer) | Attaches a producer handle to a stream. | 114 | int32_t DetachBufferQueue(int32_t streamId) | Detaches a producer handle from a stream. | 115 | int32_t Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) | Captures images. | 116 | int32_t CancelCapture(int32_t captureId) | Cancels a capture. | 117 | int32_t ChangeToOfflineStream(const std::vector<int32_t>& streamIds,<br>const sptr<IStreamOperatorCallback>& callbackObj,<br>sptr<IOfflineStreamOperator>& offlineOperator) | Changes a stream into an offline stream. | 118 119- istream_operator_callback.h 120 121 | API | Description | 122 | ------------------------------------------------------------ | ----------------------------------------------- | 123 | int32_t OnCaptureStarted(int32_t captureId, const std::vector<int32_t>& streamIds) | Called when a capture starts. | 124 | int32_t OnCaptureEnded(int32_t captureId, const std::vector<CaptureEndedInfo>& infos) | Called when a capture ends. | 125 | int32_t OnCaptureError(int32_t captureId, const std::vector<CaptureErrorInfo>& infos) | Called when an error occurs during the capture. | 126 | int32_t OnFrameShutter(int32_t captureId, const std::vector<int32_t>& streamIds, uint64_t timestamp) | Called when a frame is captured. | 127 128### How to Develop 129The camera driver development procedure is as follows: 130 1311. Register a **CameraHost** instance. 132 133 Define the **HdfDriverEntry** structure to define the method for initializing **CameraHost**. For details about the code, see **drivers/peripheral/camera/interfaces/hdi_ipc/camera_host_driver.cpp**. 134 ```c++ 135 struct HdfDriverEntry g_cameraHostDriverEntry = { 136 .moduleVersion = 1, 137 .moduleName = "camera_service", 138 .Bind = HdfCameraHostDriverBind, 139 .Init = HdfCameraHostDriverInit, 140 .Release = HdfCameraHostDriverRelease, 141 }; 142 HDF_INIT(g_cameraHostDriverEntry); // Register the HdfDriverEntry structure with the HDF. 143 ``` 144 1452. Initialize the **CameraHost** service. 146 147 The **HdfCameraHostDriverBind()** method defined in the **HdfDriverEntry** structure registers **CameraServiceDispatch()** and **CameraHostStubInstance()**. **CameraServiceDispatch()** is used to remotely call the **CameraHost** methods, such as **OpenCamera()** and **SetFlashlight()**. **CameraHostStubInstance()** is called during the system startup to initialize the camera. 148 149 ```c++ 150 static int HdfCameraHostDriverBind(struct HdfDeviceObject *deviceObject) 151 { 152 HDF_LOGI("HdfCameraHostDriverBind enter"); 153 154 auto *hdfCameraHostHost = new (std::nothrow) HdfCameraHostHost; 155 if (hdfCameraHostHost == nullptr) { 156 HDF_LOGE("%{public}s: failed to create HdfCameraHostHost object", __func__); 157 return HDF_FAILURE; 158 } 159 160 hdfCameraHostHost->ioService.Dispatch = CameraHostDriverDispatch; // Provide a method to remotely call a CameraHost method. 161 hdfCameraHostHost->ioService.Open = NULL; 162 hdfCameraHostHost->ioService.Release = NULL; 163 164 auto serviceImpl = ICameraHost::Get(true); 165 if (serviceImpl == nullptr) { 166 HDF_LOGE("%{public}s: failed to get of implement service", __func__); 167 delete hdfCameraHostHost; 168 return HDF_FAILURE; 169 } 170 171 hdfCameraHostHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl, 172 ICameraHost::GetDescriptor()); // Initialize the camera. 173 if (hdfCameraHostHost->stub == nullptr) { 174 HDF_LOGE("%{public}s: failed to get stub object", __func__); 175 delete hdfCameraHostHost; 176 return HDF_FAILURE; 177 } 178 179 deviceObject->service = &hdfCameraHostHost->ioService; 180 return HDF_SUCCESS; 181 } 182 ``` 183 184 The following functions are the implementation of the methods of the **CameraHost**: 185 186 ```c++ 187 int32_t CameraHostStub::CameraHostServiceStubOnRemoteRequest(int cmdId, MessageParcel &data, 188 MessageParcel &reply, MessageOption &option) 189 { 190 switch(cmdId) { 191 case CMD_CAMERA_HOST_SET_CALLBACK: { 192 return CameraHostStubSetCallback(data, reply, option); 193 } 194 case CMD_CAMERA_HOST_GET_CAMERAID: { 195 return CameraHostStubGetCameraIds(data, reply, option); 196 } 197 case CMD_CAMERA_HOST_GET_CAMERA_ABILITY: { 198 return CameraHostStubGetCameraAbility(data, reply, option); 199 } 200 case CMD_CAMERA_HOST_OPEN_CAMERA: { 201 return CameraHostStubOpenCamera(data, reply, option); 202 } 203 case CMD_CAMERA_HOST_SET_FLASH_LIGHT: { 204 return CameraHostStubSetFlashlight(data, reply, option); 205 } 206 default: { 207 HDF_LOGE("%s: not support cmd %d", __func__, cmdId); 208 return HDF_ERR_INVALID_PARAM; 209 } 210 } 211 return HDF_SUCCESS; 212 } 213 ``` 214 215 **CameraHostStubInstance()** finally calls **CameraHostImpl::Init()** to obtain the physical camera and initialize the DeviceManager and PipelineCore modules. 216 2173. Obtain the **CameraHost** service. 218 219 Use **Get()** to obtain the **CameraHost** from the **CameraService**. The **Get()** method is as follows: 220 221 ```c++ 222 sptr<ICameraHost> ICameraHost::Get(const char *serviceName) 223 { 224 do { 225 using namespace OHOS::HDI::ServiceManager::V1_0; 226 auto servMgr = IServiceManager::Get(); 227 if (servMgr == nullptr) { 228 HDF_LOGE("%s: IServiceManager failed!", __func__); 229 break; 230 } 231 auto remote = servMgr->GetService(serviceName); // Obtain the CameraHost based on serviceName. 232 if (remote != nullptr) { 233 sptr<CameraHostProxy> hostSptr = iface_cast<CameraHostProxy>(remote); // Return the CameraHostProxy object that contains interfaces such as OpenCamera() to the caller. 234 return hostSptr; 235 } 236 HDF_LOGE("%s: GetService failed! serviceName = %s", __func__, serviceName); 237 } while(false); 238 HDF_LOGE("%s: get %s failed!", __func__, serviceName); 239 return nullptr; 240 } 241 ``` 242 2434. Open a camera device. 244 245 The **CameraHostProxy** class provides **SetCallback()**, **GetCameraIds()**, **GetCameraAbility()**, **OpenCamera()**, and **SetFlashlight()**. 246 247 Use **OpenCamera()** to call the remote **CameraHostStubOpenCamera()** through the **CMD_CAMERA_HOST_OPEN_CAMERA** to obtain an **ICameraDevice** object. 248 249 ```c++ 250 int32_t CameraHostProxy::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 251 sptr<ICameraDevice>& device) 252 { 253 MessageParcel cameraHostData; 254 MessageParcel cameraHostReply; 255 MessageOption cameraHostOption(MessageOption::TF_SYNC); 256 257 if (!cameraHostData.WriteInterfaceToken(ICameraHost::GetDescriptor())) { 258 HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__); 259 return HDF_ERR_INVALID_PARAM; 260 } 261 262 if (!cameraHostData.WriteCString(cameraId.c_str())) { 263 HDF_LOGE("%{public}s: write cameraId failed!", __func__); 264 return HDF_ERR_INVALID_PARAM; 265 } 266 267 if (!cameraHostData.WriteRemoteObject(OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(callbackObj, 268 ICameraDeviceCallback::GetDescriptor()))) { 269 HDF_LOGE("%{public}s: write callbackObj failed!", __func__); 270 return HDF_ERR_INVALID_PARAM; 271 } 272 273 int32_t cameraHostRet = Remote()->SendRequest(CMD_CAMERA_HOST_OPEN_CAMERA, cameraHostData, cameraHostReply, cameraHostOption); 274 if (cameraHostRet != HDF_SUCCESS) { 275 HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, cameraHostRet); 276 return cameraHostRet; 277 } 278 279 device = hdi_facecast<ICameraDevice>(cameraHostReply.ReadRemoteObject()); 280 281 return cameraHostRet; 282 } 283 ``` 284 285 **Remote()->SendRequest** calls **CameraHostServiceStubOnRemoteRequest()**, locates **CameraHostStubOpenCamera()** based on **cmdId**, and finally calls **CameraHostImpl::OpenCamera()** to obtain a **CameraDevice** and power on the camera hardware. 286 287 ```c++ 288 int32_t CameraHostImpl::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj, 289 sptr<ICameraDevice>& device) 290 { 291 CAMERA_LOGD("OpenCamera entry"); 292 DFX_LOCAL_HITRACE_BEGIN; 293 if (CameraIdInvalid(cameraId) != RC_OK || callbackObj == nullptr) { 294 CAMERA_LOGW("open camera id is empty or callback is null."); 295 return INVALID_ARGUMENT; 296 } 297 298 auto itr = cameraDeviceMap_.find(cameraId); 299 if (itr == cameraDeviceMap_.end()) { 300 CAMERA_LOGE("camera device not found."); 301 return INSUFFICIENT_RESOURCES; 302 } 303 CAMERA_LOGD("OpenCamera cameraId find success."); 304 305 std::shared_ptr<CameraDeviceImpl> cameraDevice = itr->second; 306 if (cameraDevice == nullptr) { 307 CAMERA_LOGE("camera device is null."); 308 return INSUFFICIENT_RESOURCES; 309 } 310 311 CamRetCode ret = cameraDevice->SetCallback(callbackObj); 312 CHECK_IF_NOT_EQUAL_RETURN_VALUE(ret, HDI::Camera::V1_0::NO_ERROR, ret); 313 314 CameraHostConfig *config = CameraHostConfig::GetInstance(); 315 CHECK_IF_PTR_NULL_RETURN_VALUE(config, INVALID_ARGUMENT); 316 317 std::vector<std::string> phyCameraIds; 318 RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds); 319 if (rc != RC_OK) { 320 CAMERA_LOGE("get physic cameraId failed."); 321 return DEVICE_ERROR; 322 } 323 if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) { // Power on the camera hardware. 324 CAMERA_LOGE("camera powerup failed."); 325 CameraPowerDown(phyCameraIds); 326 return DEVICE_ERROR; 327 } 328 329 auto sptrDevice = deviceBackup_.find(cameraId); 330 if (sptrDevice == deviceBackup_.end()) { 331 #ifdef CAMERA_BUILT_ON_OHOS_LITE 332 deviceBackup_[cameraId] = cameraDevice; 333 #else 334 deviceBackup_[cameraId] = cameraDevice.get(); 335 #endif 336 } 337 device = deviceBackup_[cameraId]; 338 cameraDevice->SetStatus(true); 339 CAMERA_LOGD("open camera success."); 340 DFX_LOCAL_HITRACE_END; 341 return HDI::Camera::V1_0::NO_ERROR; 342 } 343 ``` 344 3455. Obtain streams. 346 347 **CameraDeviceImpl** defines **GetStreamOperator()**, **UpdateSettings()**, **SetResultMode()**, and **GetEnabledResult()**. Use **GetStreamOperator()** to obtain steams. 348 349 ```c++ 350 int32_t CameraDeviceImpl::GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj, 351 sptr<IStreamOperator>& streamOperator) 352 { 353 HDI_DEVICE_PLACE_A_WATCHDOG; 354 DFX_LOCAL_HITRACE_BEGIN; 355 if (callbackObj == nullptr) { 356 CAMERA_LOGW("input callback is null."); 357 return INVALID_ARGUMENT; 358 } 359 360 spCameraDeciceCallback_ = callbackObj; 361 if (spStreamOperator_ == nullptr) { 362 #ifdef CAMERA_BUILT_ON_OHOS_LITE 363 // Create a spStreamOperator_ object and pass it to the caller for subsequent stream operations. 364 spStreamOperator_ = std::make_shared<StreamOperator>(spCameraDeciceCallback_, shared_from_this()); 365 #else 366 spStreamOperator_ = new(std::nothrow) StreamOperator(spCameraDeciceCallback_, shared_from_this()); 367 #endif 368 if (spStreamOperator_ == nullptr) { 369 CAMERA_LOGW("create stream operator failed."); 370 return DEVICE_ERROR; 371 } 372 spStreamOperator_->Init(); 373 ismOperator_ = spStreamOperator_; 374 } 375 streamOperator = ismOperator_; 376 #ifndef CAMERA_BUILT_ON_OHOS_LITE 377 CAMERA_LOGI("CameraDeviceImpl %{public}s: line: %{public}d", __FUNCTION__, __LINE__); 378 pipelineCore_->GetStreamPipelineCore()->SetCallback( 379 [this](const std::shared_ptr<CameraMetadata> &metadata) { 380 OnMetadataChanged(metadata); 381 }); 382 #endif 383 DFX_LOCAL_HITRACE_END; 384 return HDI::Camera::V1_0::NO_ERROR; 385 } 386 ``` 387 3886. Create streams. 389 390 Fill in the **StreamInfo** structure before creating streams by calling **CreateStreams()**. 391 392 ```c++ 393 using StreamInfo = struct _StreamInfo { 394 int streamId_; 395 int width_; // Stream width 396 int height_; // Stream height 397 int format_; // Stream format, for example, PIXEL_FMT_YCRCB_420_SP 398 int dataSpace_; 399 StreamIntent intent_; // StreamIntent, for example, PREVIEW 400 bool tunneledMode_; 401 ufferProducerSequenceable bufferQueue_; // Use streamCustomer->CreateProducer() to create a buffer queue for streams. 402 int minFrameDuration_; 403 EncodeType encodeType_; 404 }; 405 ``` 406 407 **CreateStreams()** is a method in the **StreamOperator** class (**StreamOperatorImpl** is the base class of **StreamOperator**). Use **CreateStreams()** to create a **StreamBase** object, which initializes operations such as **CreateBufferPool** through its **Init()** method. 408 409 ```c++ 410 int32_t StreamOperator::CreateStreams(const std::vector<StreamInfo>& streamInfos) 411 { 412 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 413 DFX_LOCAL_HITRACE_BEGIN; 414 for (const auto& it : streamInfos) { 415 CHECK_IF_NOT_EQUAL_RETURN_VALUE(CheckStreamInfo(it), true, INVALID_ARGUMENT); 416 CAMERA_LOGI("streamId:%{public}d and format:%{public}d and width:%{public}d and height:%{public}d", 417 it.streamId_, it.format_, it.width_, it.height_); 418 if (streamMap_.count(it.streamId_) > 0) { 419 CAMERA_LOGE("stream [id = %{public}d] has already been created.", it.streamId_); 420 return INVALID_ARGUMENT; 421 } 422 std::shared_ptr<IStream> stream = StreamFactory::Instance().CreateShared( // Create a stream instance. 423 IStream::g_availableStreamType[it.intent_], it.streamId_, it.intent_, pipelineCore_, messenger_); 424 if (stream == nullptr) { 425 CAMERA_LOGE("create stream [id = %{public}d] failed.", it.streamId_); 426 return INSUFFICIENT_RESOURCES; 427 } 428 StreamConfiguration scg; 429 StreamInfoToStreamConfiguration(scg, it); 430 RetCode rc = stream->ConfigStream(scg); 431 if (rc != RC_OK) { 432 CAMERA_LOGE("configure stream %{public}d failed", it.streamId_); 433 return INVALID_ARGUMENT; 434 } 435 if (!scg.tunnelMode && (it.bufferQueue_)->producer_ != nullptr) { 436 CAMERA_LOGE("stream [id:%{public}d] is not tunnel mode, can't bind a buffer producer", it.streamId_); 437 return INVALID_ARGUMENT; 438 } 439 if ((it.bufferQueue_)->producer_ != nullptr) { 440 auto tunnel = std::make_shared<StreamTunnel>(); 441 CHECK_IF_PTR_NULL_RETURN_VALUE(tunnel, INSUFFICIENT_RESOURCES); 442 rc = tunnel->AttachBufferQueue((it.bufferQueue_)->producer_); 443 CHECK_IF_NOT_EQUAL_RETURN_VALUE(rc, RC_OK, INVALID_ARGUMENT); 444 if (stream->AttachStreamTunnel(tunnel) != RC_OK) { 445 CAMERA_LOGE("attach buffer queue to stream [id = %{public}d] failed", it.streamId_); 446 return INVALID_ARGUMENT; 447 } 448 } 449 { 450 std::lock_guard<std::mutex> l(streamLock_); 451 streamMap_[stream->GetStreamId()] = stream; 452 } 453 CAMERA_LOGI("create stream success [id:%{public}d] [type:%{public}s]", stream->GetStreamId(), 454 IStream::g_availableStreamType[it.intent_].c_str()); 455 } 456 DFX_LOCAL_HITRACE_END; 457 return HDI::Camera::V1_0::NO_ERROR; 458 } 459 ``` 460 4617. Configure streams. 462 463 Use **CommitStreams()** to configure streams, including initializing and creating **PipelineCore**. **CommitStreams()** must be called after streams are created. 464 465 ```c++ 466 int32_t StreamOperator::CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) 467 { 468 CAMERA_LOGV("enter"); 469 CHECK_IF_PTR_NULL_RETURN_VALUE(streamPipeline_, DEVICE_ERROR); 470 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 471 if (modeSetting.empty()) { 472 CAMERA_LOGE("input vector is empty"); 473 return INVALID_ARGUMENT; 474 } 475 DFX_LOCAL_HITRACE_BEGIN; 476 477 std::vector<StreamConfiguration> configs = {}; 478 { 479 std::lock_guard<std::mutex> l(streamLock_); 480 std::transform(streamMap_.begin(), streamMap_.end(), std::back_inserter(configs), 481 [](auto &iter) { return iter.second->GetStreamAttribute(); }); 482 } 483 484 std::shared_ptr<CameraMetadata> setting; 485 MetadataUtils::ConvertVecToMetadata(modeSetting, setting); 486 DynamicStreamSwitchMode method = streamPipeline_->CheckStreamsSupported(mode, setting, configs); 487 if (method == DYNAMIC_STREAM_SWITCH_NOT_SUPPORT) { 488 return INVALID_ARGUMENT; 489 } 490 if (method == DYNAMIC_STREAM_SWITCH_NEED_INNER_RESTART) { 491 std::lock_guard<std::mutex> l(streamLock_); 492 for (auto it : streamMap_) { 493 it.second->StopStream(); 494 } 495 } 496 { 497 std::lock_guard<std::mutex> l(streamLock_); 498 for (auto it : streamMap_) { 499 if (it.second->CommitStream() != RC_OK) { 500 CAMERA_LOGE("commit stream [id = %{public}d] failed.", it.first); 501 return DEVICE_ERROR; 502 } 503 } 504 } 505 RetCode rc = streamPipeline_->PreConfig(setting); // Configure the device stream. 506 if (rc != RC_OK) { 507 CAMERA_LOGE("prepare mode settings failed"); 508 return DEVICE_ERROR; 509 } 510 rc = streamPipeline_->CreatePipeline(mode); // Create a pipeline. 511 if (rc != RC_OK) { 512 CAMERA_LOGE("create pipeline failed."); 513 return INVALID_ARGUMENT; 514 } 515 516 DFX_LOCAL_HITRACE_END; 517 return HDI::Camera::V1_0::NO_ERROR; 518 } 519 ``` 520 5218. Capture images. 522 523 Fill in the **CaptureInfo** structure before calling **Capture()**. 524 525 ```c++ 526 using CaptureInfo = struct _CaptureInfo { 527 int[] streamIds_; // IDs of the streams to capture. 528 unsigned char[] captureSetting_; // Use the camera ability obtained by GetCameraAbility() of CameraHost to fill in the settings. 529 bool enableShutterCallback_; 530 }; 531 ``` 532 533 Use the **Capture()** method in **StreamOperator** to capture data streams. 534 535 ```c++ 536 int32_t StreamOperator::Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) 537 { 538 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 539 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 540 DFX_LOCAL_HITRACE_BEGIN; 541 542 for (auto id : info.streamIds_) { 543 std::lock_guard<std::mutex> l(streamLock_); 544 auto it = streamMap_.find(id); 545 if (it == streamMap_.end()) { 546 return INVALID_ARGUMENT; 547 } 548 } 549 550 { 551 std::lock_guard<std::mutex> l(requestLock_); 552 auto itr = requestMap_.find(captureId); 553 if (itr != requestMap_.end()) { 554 return INVALID_ARGUMENT; 555 } 556 } 557 558 std::shared_ptr<CameraMetadata> captureSetting; 559 MetadataUtils::ConvertVecToMetadata(info.captureSetting_, captureSetting); 560 CaptureSetting setting = captureSetting; 561 auto request = 562 std::make_shared<CaptureRequest>(captureId, info.streamIds_.size(), setting, 563 info.enableShutterCallback_, isStreaming); 564 for (auto id : info.streamIds_) { 565 RetCode rc = streamMap_[id]->AddRequest(request); 566 if (rc != RC_OK) { 567 return DEVICE_ERROR; 568 } 569 } 570 571 { 572 std::lock_guard<std::mutex> l(requestLock_); 573 requestMap_[captureId] = request; 574 } 575 return HDI::Camera::V1_0::NO_ERROR; 576 } 577 ``` 578 5799. Cancel the capture and release the offline stream. 580 581 Use **CancelCapture()** in the **StreamOperatorImpl** class to cancel the stream capture based on **captureId**. 582 583 ```c++ 584 int32_t StreamOperator::CancelCapture(int32_t captureId) 585 { 586 CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT); 587 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 588 DFX_LOCAL_HITRACE_BEGIN; 589 590 std::lock_guard<std::mutex> l(requestLock_); 591 auto itr = requestMap_.find(captureId); // Search for the CameraCapture object in the Map based on the captureId. 592 if (itr == requestMap_.end()) { 593 CAMERA_LOGE("can't cancel capture [id = %{public}d], this capture doesn't exist", captureId); 594 return INVALID_ARGUMENT; 595 } 596 597 RetCode rc = itr->second->Cancel(); // Call Cancel() in CameraCapture to cancel the stream capture. 598 if (rc != RC_OK) { 599 return DEVICE_ERROR; 600 } 601 requestMap_.erase(itr); // Erase the CameraCapture object. 602 603 DFX_LOCAL_HITRACE_END; 604 return HDI::Camera::V1_0::NO_ERROR; 605 } 606 ``` 607 608 Use **ReleaseStreams()** in the **StreamOperatorImpl** class to release the streams created by using **CreateStream()** and **CommitStreams()** and destroy the pipeline. 609 610 ```c++ 611 int32_t StreamOperator::ReleaseStreams(const std::vector<int32_t>& streamIds) 612 { 613 PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_); 614 DFX_LOCAL_HITRACE_BEGIN; 615 for (auto id : streamIds) { 616 std::lock_guard<std::mutex> l(streamLock_); 617 auto it = streamMap_.find(id); 618 if (it == streamMap_.end()) { 619 continue; 620 } 621 if (it->second->IsRunning()) { 622 it->second->StopStream(); 623 } 624 it->second->DumpStatsInfo(); 625 streamMap_.erase(it); 626 } 627 628 for (auto id : streamIds) { 629 CHECK_IF_EQUAL_RETURN_VALUE(id < 0, true, INVALID_ARGUMENT); 630 } 631 632 DFX_LOCAL_HITRACE_END; 633 return HDI::Camera::V1_0::NO_ERROR; 634 } 635 ``` 636 63710. Close the camera device. 638 639 Use **Close()** in the **CameraDeviceImpl** class to close the camera device. The **PowerDown()** in **DeviceManager** is called to power off the device. 640 641### Example 642 643There is a [ohos_camera_demo](https://gitee.com/openharmony/drivers_peripheral/tree/OpenHarmony-3.2-Release/camera/hal/init) in the **/drivers/peripheral/camera/hal/init** directory. After the system is started, the executable file **ohos_camera_demo** is generated in the **/vendor/bin** directory. This demo implements basic camera capabilities such as preview and photographing. 644 645The following uses the demo to describe how to use the HDI to implement **PreviewOn()** and **CaptureON()**. 646 6471. Construct a **CameraDemo** object in the **main** function. This object contains methods for initializing the camera and starting, stopping, and releasing streams. The **mainDemo->InitSensors()** function is used to initialize the **CameraHost**, and the **mainDemo->InitCameraDevice()** function is used to initialize the **CameraDevice**. 648 649 ```c++ 650 int main(int argc, char** argv) 651 { 652 RetCode rc = RC_OK; 653 auto mainDemo = std::make_shared<CameraDemo>(); 654 rc = mainDemo->InitSensors(); // Initialize the CameraHost. 655 if (rc == RC_ERROR) { 656 CAMERA_LOGE("main test: mainDemo->InitSensors() error\n"); 657 return -1; 658 } 659 660 rc = mainDemo->InitCameraDevice(); // Initialize the CameraDevice. 661 if (rc == RC_ERROR) { 662 CAMERA_LOGE("main test: mainDemo->InitCameraDevice() error\n"); 663 return -1; 664 } 665 666 rc = PreviewOn(0, mainDemo); // Configure and enable streams. 667 if (rc != RC_OK) { 668 CAMERA_LOGE("main test: PreviewOn() error demo exit"); 669 return -1; 670 } 671 672 ManuList(mainDemo, argc, argv); // Print the menu to the console. 673 674 return RC_OK; 675 } 676 ``` 677 678 The function used to initialize the **CameraHost** is implemented as follows, where the HDI **ICameraHost::Get()** is called to obtain the **demoCameraHost** and set the callback: 679 680 ```c++ 681 RetCode OhosCameraDemo::InitSensors() 682 { 683 int rc = 0; 684 685 CAMERA_LOGD("demo test: InitSensors enter"); 686 687 if (demoCameraHost_ != nullptr) { 688 return RC_OK; 689 } 690 #ifdef CAMERA_BUILT_ON_OHOS_LITE 691 demoCameraHost_ = OHOS::Camera::CameraHost::CreateCameraHost(); 692 #else 693 constexpr const char *DEMO_SERVICE_NAME = "camera_service"; 694 demoCameraHost_ = ICameraHost::Get(DEMO_SERVICE_NAME, false); 695 #endif 696 if (demoCameraHost_ == nullptr) { 697 CAMERA_LOGE("demo test: ICameraHost::Get error"); 698 return RC_ERROR; 699 } 700 701 #ifdef CAMERA_BUILT_ON_OHOS_LITE 702 hostCallback_ = std::make_shared<DemoCameraHostCallback>(); 703 #else 704 hostCallback_ = new DemoCameraHostCallback(); 705 #endif 706 rc = demoCameraHost_->SetCallback(hostCallback_); 707 if (rc != HDI::Camera::V1_0::NO_ERROR) { 708 CAMERA_LOGE("demo test: demoCameraHost_->SetCallback(hostCallback_) error"); 709 return RC_ERROR; 710 } 711 712 CAMERA_LOGD("demo test: InitSensors exit"); 713 714 return RC_OK; 715 } 716 ``` 717 718 The function for initializing the **CameraDevice** is implemented as follows. The **GetCameraIds(cameraIds_)**, **GetCameraAbility(cameraId, ability_)**, and **OpenCamera(cameraIds\_.front(), callback, demoCameraDevice_)** methods are used to obtain the **demoCameraHost**. 719 720 ```c++ 721 RetCode OhosCameraDemo::InitCameraDevice() 722 { 723 int rc = 0; 724 725 CAMERA_LOGD("demo test: InitCameraDevice enter"); 726 727 if (demoCameraHost_ == nullptr) { 728 CAMERA_LOGE("demo test: InitCameraDevice demoCameraHost_ == nullptr"); 729 return RC_ERROR; 730 } 731 732 (void)demoCameraHost_->GetCameraIds(cameraIds_); 733 if (cameraIds_.empty()) { 734 return RC_ERROR; 735 } 736 const std::string cameraId = cameraIds_.front(); 737 demoCameraHost_->GetCameraAbility(cameraId, cameraAbility_); 738 739 MetadataUtils::ConvertVecToMetadata(cameraAbility_, ability_); 740 741 GetFaceDetectMode(ability_); 742 GetFocalLength(ability_); 743 GetAvailableFocusModes(ability_); 744 GetAvailableExposureModes(ability_); 745 GetExposureCompensationRange(ability_); 746 GetExposureCompensationSteps(ability_); 747 GetAvailableMeterModes(ability_); 748 GetAvailableFlashModes(ability_); 749 GetMirrorSupported(ability_); 750 GetStreamBasicConfigurations(ability_); 751 GetFpsRange(ability_); 752 GetCameraPosition(ability_); 753 GetCameraType(ability_); 754 GetCameraConnectionType(ability_); 755 GetFaceDetectMaxNum(ability_); 756 757 #ifdef CAMERA_BUILT_ON_OHOS_LITE 758 std::shared_ptr<CameraDeviceCallback> callback = std::make_shared<CameraDeviceCallback>(); 759 #else 760 sptr<DemoCameraDeviceCallback> callback = new DemoCameraDeviceCallback(); 761 #endif 762 rc = demoCameraHost_->OpenCamera(cameraIds_.front(), callback, demoCameraDevice_); 763 if (rc != HDI::Camera::V1_0::NO_ERROR || demoCameraDevice_ == nullptr) { 764 CAMERA_LOGE("demo test: InitCameraDevice OpenCamera failed"); 765 return RC_ERROR; 766 } 767 768 CAMERA_LOGD("demo test: InitCameraDevice exit"); 769 770 return RC_OK; 771 } 772 ``` 773 7742. Implement **PreviewOn()** to configure streams, enable preview streams, and start stream capture. 775 776 After **PreviewOn()** is called, the camera preview channel starts running. Two streams are enabled: preview stream and capture or video stream. Only the preview stream will be captured. 777 778 ```c++ 779 static RetCode PreviewOn(int mode, const std::shared_ptr<OhosCameraDemo>& mainDemo) 780 { 781 RetCode rc = RC_OK; 782 CAMERA_LOGD("main test: PreviewOn enter"); 783 784 rc = mainDemo->StartPreviewStream(); // Configure the preview stream. 785 if (rc != RC_OK) { 786 CAMERA_LOGE("main test: PreviewOn StartPreviewStream error"); 787 return RC_ERROR; 788 } 789 790 if (mode == 0) { 791 rc = mainDemo->StartCaptureStream(); // Configure the capture stream. 792 if (rc != RC_OK) { 793 CAMERA_LOGE("main test: PreviewOn StartCaptureStream error"); 794 return RC_ERROR; 795 } 796 } else { 797 rc = mainDemo->StartVideoStream(); // Configure the video stream. 798 if (rc != RC_OK) { 799 CAMERA_LOGE("main test: PreviewOn StartVideoStream error"); 800 return RC_ERROR; 801 } 802 } 803 804 rc = mainDemo->CaptureON(STREAM_ID_PREVIEW, CAPTURE_ID_PREVIEW, CAPTURE_PREVIEW); 805 if (rc != RC_OK) { 806 CAMERA_LOGE("main test: PreviewOn mainDemo->CaptureON() preview error"); 807 return RC_ERROR; 808 } 809 810 CAMERA_LOGD("main test: PreviewOn exit"); 811 return RC_OK; 812 } 813 ``` 814 815 The **StartCaptureStream()**, **StartVideoStream()**, and **StartPreviewStream()** methods call **CreateStream()** with different input parameters. 816 817 Use **CreateStream()** to call an HDI API to configure and create streams. Specifically, **CreateStream()** calls the HDI to obtain a **StreamOperation** object and then creates a **StreamInfo** object. Call **CreateStreams()** and **CommitStreams()** to create and configure streams. 818 819 ```c++ 820 RetCode OhosCameraDemo::CreateStream(const int streamId, std::shared_ptr<StreamCustomer> &streamCustomer, 821 StreamIntent intent) 822 { 823 int rc = 0; 824 CAMERA_LOGD("demo test: CreateStream enter"); 825 826 GetStreamOpt(); // Obtain a StreamOperator object. 827 if (streamOperator_ == nullptr) { 828 CAMERA_LOGE("demo test: CreateStream GetStreamOpt() is nullptr\n"); 829 return RC_ERROR; 830 } 831 832 StreamInfo streamInfo = {0}; 833 834 SetStreamInfo(streamInfo, streamCustomer, streamId, intent); // Fills in the StreamInfo stream. 835 if (streamInfo.bufferQueue_->producer_ == nullptr) { 836 CAMERA_LOGE("demo test: CreateStream CreateProducer(); is nullptr\n"); 837 return RC_ERROR; 838 } 839 840 std::vector<StreamInfo> streamInfos; 841 streamInfos.push_back(streamInfo); 842 843 rc = streamOperator_->CreateStreams(streamInfos); // Create a stream. 844 if (rc != HDI::Camera::V1_0::NO_ERROR) { 845 CAMERA_LOGE("demo test: CreateStream CreateStreams error\n"); 846 return RC_ERROR; 847 } 848 849 rc = streamOperator_->CommitStreams(NORMAL, cameraAbility_); 850 if (rc != HDI::Camera::V1_0::NO_ERROR) { 851 CAMERA_LOGE("demo test: CreateStream CommitStreams error\n"); 852 std::vector<int> streamIds; 853 streamIds.push_back(streamId); 854 streamOperator_->ReleaseStreams(streamIds); 855 return RC_ERROR; 856 } 857 858 CAMERA_LOGD("demo test: CreateStream exit"); 859 860 return RC_OK; 861 } 862 ``` 863 864 Use **CaptureON()** to call the **Capture()** method of **StreamOperator** to obtain camera data, flip the buffer, and start a thread to receive data of the corresponding type. 865 866 ```c++ 867 RetCode OhosCameraDemo::CaptureON(const int streamId, 868 const int captureId, CaptureMode mode) 869 { 870 CAMERA_LOGI("demo test: CaptureON enter streamId == %{public}d and captureId == %{public}d and mode == %{public}d", 871 streamId, captureId, mode); 872 std::lock_guard<std::mutex> l(metaDatalock_); 873 if (mode == CAPTURE_SNAPSHOT) { 874 constexpr double latitude = 27.987500; // dummy data: Qomolangma latitde 875 constexpr double longitude = 86.927500; // dummy data: Qomolangma longituude 876 constexpr double altitude = 8848.86; // dummy data: Qomolangma altitude 877 constexpr size_t entryCapacity = 100; 878 constexpr size_t dataCapacity = 2000; 879 captureSetting_ = std::make_shared<CameraSetting>(entryCapacity, dataCapacity); 880 captureQuality_ = OHOS_CAMERA_JPEG_LEVEL_HIGH; 881 captureOrientation_ = OHOS_CAMERA_JPEG_ROTATION_270; 882 mirrorSwitch_ = OHOS_CAMERA_MIRROR_ON; 883 gps_.push_back(latitude); 884 gps_.push_back(longitude); 885 gps_.push_back(altitude); 886 captureSetting_->addEntry(OHOS_JPEG_QUALITY, static_cast<void*>(&captureQuality_), 887 sizeof(captureQuality_)); 888 captureSetting_->addEntry(OHOS_JPEG_ORIENTATION, static_cast<void*>(&captureOrientation_), 889 sizeof(captureOrientation_)); 890 captureSetting_->addEntry(OHOS_CONTROL_CAPTURE_MIRROR, static_cast<void*>(&mirrorSwitch_), 891 sizeof(mirrorSwitch_)); 892 captureSetting_->addEntry(OHOS_JPEG_GPS_COORDINATES, gps_.data(), gps_.size()); 893 } 894 895 std::vector<uint8_t> setting; 896 MetadataUtils::ConvertMetadataToVec(captureSetting_, setting); 897 captureInfo_.streamIds_ = {streamId}; 898 if (mode == CAPTURE_SNAPSHOT) { 899 captureInfo_.captureSetting_ = setting; 900 } else { 901 captureInfo_.captureSetting_ = cameraAbility_; 902 } 903 captureInfo_.enableShutterCallback_ = false; 904 905 int rc = streamOperator_->Capture(captureId, captureInfo_, true); // The capture starts, and buffer starts to flip. 906 if (rc != HDI::Camera::V1_0::NO_ERROR) { 907 CAMERA_LOGE("demo test: CaptureStart Capture error\n"); 908 streamOperator_->ReleaseStreams(captureInfo_.streamIds_); 909 return RC_ERROR; 910 } 911 912 if (mode == CAPTURE_PREVIEW) { 913 streamCustomerPreview_->ReceiveFrameOn(nullptr); // Create a preview thread to receive the passed buffer. 914 } else if (mode == CAPTURE_SNAPSHOT) { 915 streamCustomerCapture_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // Create a capture thread to receive the passed buffer through the StoreImage callback. 916 StoreImage(addr, size); 917 }); 918 } else if (mode == CAPTURE_VIDEO) { 919 OpenVideoFile(); 920 921 streamCustomerVideo_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // Create a video thread to receive the passed buffer through the StoreImage callback. 922 StoreVideo(addr, size); 923 }); 924 } 925 CAMERA_LOGD("demo test: CaptureON exit"); 926 927 return RC_OK; 928 } 929 ``` 930 9313. Implement **ManuList()** to obtain characters from the console through **fgets()**. Different characters correspond to different capabilities provided by the demo, and the functionality menu is printed. 932 933 ```c++ 934 static void ManuList(const std::shared_ptr<OhosCameraDemo>& mainDemo, 935 const int argc, char** argv) 936 { 937 int idx, c; 938 bool isAwb = true; 939 const char *shortOptions = "h:cwvaeqof:"; 940 c = getopt_long(argc, argv, shortOptions, LONG_OPTIONS, &idx); 941 while (1) { 942 switch (c) { 943 case 'h': 944 c = PutMenuAndGetChr(); // Print the menu. 945 break; 946 case 'f': 947 FlashLightTest(mainDemo); // Verify the flashlight capability. 948 c = PutMenuAndGetChr(); 949 break; 950 case 'o': 951 OfflineTest(mainDemo); // Verify the offline capability. 952 c = PutMenuAndGetChr(); 953 break; 954 case 'c': 955 CaptureTest(mainDemo); // Verify the capture capability. 956 c = PutMenuAndGetChr(); 957 break; 958 case 'w': // Verify the AWB capability. 959 if (isAwb) { 960 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_INCANDESCENT); 961 } else { 962 mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_OFF); 963 } 964 isAwb = !isAwb; 965 c = PutMenuAndGetChr(); 966 break; 967 case 'a': // Verify the AE capability. 968 mainDemo->SetAeExpo(); 969 c = PutMenuAndGetChr(); 970 break; 971 case'e': // Verify the metadata operations. 972 mainDemo->SetMetadata(); 973 c = PutMenuAndGetChr(); 974 break; 975 case'v': // Verify the video function. 976 VideoTest(mainDemo); 977 c = PutMenuAndGetChr(); 978 break; 979 case 'q': // Exit the demo. 980 PreviewOff(mainDemo); 981 mainDemo->QuitDemo(); 982 return; 983 default: 984 CAMERA_LOGE("main test: command error please retry input command"); 985 c = PutMenuAndGetChr(); 986 break; 987 } 988 } 989 } 990 ``` 991 992 Use **PutMenuAndGetChr()** to print the menu of the demo and call **fgets()** to wait for commands from the console. 993 994 ```c++ 995 static int PutMenuAndGetChr(void) 996 { 997 constexpr uint32_t inputCount = 50; 998 int c = 0; 999 char strs[inputCount]; 1000 Usage(stdout); 1001 CAMERA_LOGD("pls input command(input -q exit this app)\n"); 1002 fgets(strs, inputCount, stdin); 1003 1004 for (int i = 0; i < inputCount; i++) { 1005 if (strs[i] != '-') { 1006 c = strs[i]; 1007 break; 1008 } 1009 } 1010 return c; 1011 } 1012 ``` 1013 1014 The console outputs the menu details as follows: 1015 1016 ```c++ 1017 "Options:\n" 1018 "-h | --help Print this message\n" 1019 "-o | --offline stream offline test\n" 1020 "-c | --capture capture one picture\n" 1021 "-w | --set WB Set white balance Cloudy\n" 1022 "-v | --video capture Video of 10s\n" 1023 "-a | --Set AE Set Auto exposure\n" 1024 "-e | --Set Metadeta Set Metadata\n" 1025 "-f | --Set Flashlight Set flashlight ON 5s OFF\n" 1026 "-q | --quit stop preview and quit this app\n"); 1027 ``` 1028 10294. Compile and build the **ohos_camera_demo**. 1030 1031 Add **init:ohos_camera_demo** to **deps** in the **drivers/peripheral/camera/hal/BUILD.gn** file. 1032 1033 The sample code is as follows: 1034 1035 ``` 1036 deps = [ 1037 "buffer_manager:camera_buffer_manager", 1038 "device_manager:camera_device_manager", 1039 "hdi_impl:camera_host_service_1.0", 1040 "pipeline_core:camera_pipeline_core", 1041 "utils:camera_utils", 1042 "init:ohos_camera_demo", 1043 ] 1044 ``` 1045 1046 The following uses RK3568 development board as an example. 1047 1. Run the **./build.sh --product-name rk3568 --ccache** command to generate the executable binary file **ohos_camera_demo** in **out/rk3568/packages/phone/vendor/bin/**. 1048 2. Import the executable file **ohos_camera_demo** to the development board, modify the permission, and run the file. 1049