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