• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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