driver-peripherals-camera-des.md 46.5 KB
Newer Older
1
# Camera
2

3 4
## 概述<a name="1"></a>
### 功能简介<a name="2"></a>
5

6
OpenHarmony相机驱动框架模型对上实现相机HDI(Hardware Device Interface)接口,对下实现相机Pipeline模型,管理相机各个硬件设备。
7
该驱动框架模型内部分为三层,依次为HDI实现层、框架层和设备适配层。各层基本概念如下:
8

9
+ HDI实现层:实现OHOS(OpenHarmony Operation System)相机标准南向接口。
10
+ 框架层:对接HDI实现层的控制、流的转发,实现数据通路的搭建,管理相机各个硬件设备等功能。
11
+ 设备适配层:屏蔽底层芯片和OS(Operation System)差异,支持多平台适配。
12

13 14 15
### 运作机制<a name="3"></a>

Camera模块主要包含服务、设备的初始化,数据通路的搭建,流的配置、创建、下发、捕获等,具体运作机制参考以下图文解析:
16

17
**图 1**  基于HDF驱动框架的Camera驱动模型 
18

19
        ![](figures/Camera模块驱动模型.png)
20

21
1. 系统启动时创建camera_host进程。进程创建后,首先枚举底层设备,创建(也可以通过配置表创建)管理设备树的DeviceManager类及其内部各个底层设备的对象,创建对应的CameraHost类实例并且将其注册到UHDF(用户态HDF驱动框架)服务中,方便相机服务层通过UHDF服务获取底层CameraDeviceHost的服务,从而操作硬件设备。
22

23
2. Service通过CameraDeviceHost服务获取CameraHost实例,CameraHost可以获取底层的Camera能力,开启闪光灯、调用Open接口打开Camera创建连接、创建DeviceManager(负责底层硬件模块上电)、创建CameraDevice(向上提供设备控制接口)。创建CameraDevice时会实例化PipelineCore的各个子模块,其中StreamPipelineCore负责创建Pipeline,MetaQueueManager负责上报metaData。
24

25
3. Service通过CameraDevice模块配置流、创建Stream类。StreamPipelineStrategy模块通过上层下发的模式和查询配置表创建对应流的Node连接方式,StreamPipelineBuilder模块创建Node实例并且连接返回该Pipeline给StreamPipelineDispatcher。StreamPipelineDispatcher提供统一的Pipeline调用管理。
26

W
wu 已提交
27
4. 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

W
wu 已提交
29
5. Service通过Capture接口下发拍照命令。ChangeToOfflineStream接口查询拍照buffer位置,如果ISP已经出图,并且图像数据已经送到IPP node,可以将普通拍照流转换为离线流,否则直接走关闭流程。ChangeToOfflineStream接口通过传递StreamInfo使离线流获取到普通流的流信息,并且通过配置表确认离线流的具体Node连接方式,创建离线流的Node连接(如果已创建则通过CloseCamera释放非离线流所需的Node),等待buffer从底层Pipeline回传到上层再释放持有的Pipeline相关资源。
30 31 32

6. Service通过CameraDevice的UpdateSettings接口向下发送CaptureSetting参数,CameraDeviceDriverModel通过StreamPipelineDispatcher模块向各个Node转发,StartStreamingCapture和Capture接口携带的CaptureSetting通过StreamPipelineDispatcher模块向该流所属的Node转发。

33
7. Service通过EnableResult和DisableResult接口控制底层metaData的上报。如果需要底层metaData上报,pipeline会创建CameraDeviceDriverModel内部的一个Bufferqueue用来收集和传递metaData,根据StreamPipelineStrategy模块查询配置表并通过StreamPipelineBuilder创建和连接Node,MetaQueueManager下发buffer至底层,底层相关Node填充数据,MetaQueueManager模块再调用上层回调传递给上层。
34 35 36

8. Service调用CameraDevice的Close接口,CameraDevice调用对应的DeviceManager模块对各个硬件下电;如果此时在Ipp的SubPipeline中存在OfflineStream,则需要保留OfflineStream,直到执行完毕。

37
9. 动态帧率控制。在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

46
Camera模块主要针对相机预览、拍照、视频流等场景,对这些场景下的相机操作进行封装,使开发者更易操作相机硬件,提高开发效率。
47

48 49
### 接口说明<a name="6"></a>

50 51
注:以下接口列举的为IDL接口描述生成的对应C++语言函数接口,接口声明见idl文件(/drivers/interface/camera/v1_0/)。         
在HDI使用中下发的配置参数不能超出GetCameraAbility上报的能力范围。即使通过UpdateSettings、CommitStreams、Capture等接口可以下发超出该范围的配置参数,且接口调用不会返回失败,但设置后的行为是不确定的。
52
- icamera_device.h
53

54 55
  | 功能描述                     | 接口名称                                                     |
  | ---------------------------- | ------------------------------------------------------------ |
56 57 58 59 60 61 62
  | 获取流控制器                 | int32_t GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj,<br>sptr<IStreamOperator>& streamOperator) |
  | 更新设备控制参数             | int32_t UpdateSettings(const std::vector<uint8_t>& settings) |
  | 设置Result回调模式和回调函数 | int32_t SetResultMode(ResultCallbackMode mode) |
  | 获取使能的ResultMeta         | int32_t GetEnabledResults(std::vector<int32_t>& results) |
  | 使能具体的ResultMeta         | int32_t EnableResult(const std::vector<int32_t>& results) |
  | 禁止具体的ResultMeta         | int32_t DisableResult(const std::vector<int32_t>& results) |    
  | 关闭Camera设备               | int32_t Close()                                                 |
63

64
- icamera_device_callback.h
65

66 67
  | 功能描述                                                   | 接口名称                                                     |
  | ---------------------------------------------------------- | ------------------------------------------------------------ |
68 69
  | 设备发生错误时调用,由调用者实现,用于返回错误信息给调用者 | int32_t OnError(ErrorType type, int32_t errorCode)              |
  | 上报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 78 79 80
  | 获取当前可用的Camera设备ID列表 | int32_t GetCameraIds(std::vector<std::string>& cameraIds) |
  | 获取Camera设备能力集合         | int32_t GetCameraAbility(const std::string& cameraId, std::vector<uint8_t>& cameraAbility) |
  | 打开Camera设备                 | int32_t OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj,<br>sptr<ICameraDevice>& device) |
  | 打开或关闭闪光灯               | int32_t SetFlashlight(const std::string& cameraId, bool isEnable) |
81

82
- icamera_host_callback.h
83

84 85
  | 功能描述               | 接口名称                                                     |
  | ---------------------- | ------------------------------------------------------------ |
86 87 88
  | Camera设备状态变化上报 | int32_t OnCameraStatus(const std::string& cameraId, CameraStatus status) |
  | 闪光灯状态变化回调     | int32_t OnFlashlightStatus(const std::string& cameraId, FlashlightStatus status) |
  | Camera事件回调     | int32_t OnCameraEvent(const std::string& cameraId, CameraEvent event) |
89

90
- ioffline_stream_operator.h
91

92 93
  | 功能描述       | 接口名称                                                     |
  | -------------- | ------------------------------------------------------------ |
94 95
  | 取消捕获请求   | int32_t CancelCapture(int32_t captureId)                      |
  | 释放流         | 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 104
  | 创建流                           | int32_t CreateStreams(const std::vector<StreamInfo>& streamInfos) |
  | 释放流                           | int32_t ReleaseStreams(const std::vector<int32_t>& streamIds) |
105
  | 配置流                           | int32_t CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting) |
106 107 108 109 110 111
  | 获取流的属性                     | int32_t GetStreamAttributes(std::vector<StreamAttribute>& attributes) |
  | 绑定生产者句柄和指定流           | int32_t AttachBufferQueue(int32_t streamId, const sptr<BufferProducerSequenceable>& bufferProducer) |
  | 解除生产者句柄和指定流的绑定关系 | int32_t DetachBufferQueue(int32_t streamId)                   |
  | 捕获图像                         | int32_t Capture(int32_t captureId, const CaptureInfo& info, bool isStreaming) |
  | 取消捕获                         | int32_t CancelCapture(int32_t captureId)                      |
  | 将指定流转换成离线流             | 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 118 119 120
  | 捕获开始回调,在捕获开始时调用           | int32_t OnCaptureStarted(int32_t captureId, const std::vector<int32_t>& streamIds) |
  | 捕获结束回调,在捕获结束时调用           | int32_t OnCaptureEnded(int32_t captureId, const std::vector<CaptureEndedInfo>& infos) |
  | 捕获错误回调,在捕获过程中发生错误时调用 | int32_t OnCaptureError(int32_t captureId, const std::vector<CaptureErrorInfo>& infos) |
  | 帧捕获回调                               | int32_t OnFrameShutter(int32_t captureId, const std::vector<int32_t>& streamIds, uint64_t timestamp) |
121

122 123
### 开发步骤<a name="7"></a>
Camera驱动的开发过程主要包含以下步骤:
124

125
1. 注册CameraHost
126

127
    定义Camera的HdfDriverEntry结构体,该结构体中定义了CameraHost初始化的方法(代码目录drivers/peripheral/camera/interfaces/hdi_ipc/camera_host_driver.cpp)。
128
    ```c++
129 130 131 132 133 134 135 136 137 138
   struct HdfDriverEntry g_cameraHostDriverEntry = {
       .moduleVersion = 1,
       .moduleName = "camera_service",
       .Bind = HdfCameraHostDriverBind,
       .Init = HdfCameraHostDriverInit,
       .Release = HdfCameraHostDriverRelease,
   };
   HDF_INIT(g_cameraHostDriverEntry); // 将Camera的HdfDriverEntry结构体注册到HDF上
   ```

139
2. 初始化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 147 148 149
       HDF_LOGI("HdfCameraHostDriverBind enter");
    
       auto *hdfCameraHostHost = new (std::nothrow) HdfCameraHostHost;
       if (hdfCameraHostHost == nullptr) {
150
           HDF_LOGE("%{public}s: failed to create HdfCameraHostHost object", __func__);
151 152 153
           return HDF_FAILURE;
       }
    
154
       hdfCameraHostHost->ioService.Dispatch = CameraHostDriverDispatch; // 提供远端CameraHost调用方法
155 156 157 158 159 160 161
       hdfCameraHostHost->ioService.Open = NULL;
       hdfCameraHostHost->ioService.Release = NULL;
    
       auto serviceImpl = ICameraHost::Get(true);
       if (serviceImpl == nullptr) {
           HDF_LOGE("%{public}s: failed to get of implement service", __func__);
           delete hdfCameraHostHost;
162 163
           return HDF_FAILURE;
       }
164 165
    
       hdfCameraHostHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
166
           ICameraHost::GetDescriptor()); // 初始化Camera设备
167 168 169
       if (hdfCameraHostHost->stub == nullptr) {
           HDF_LOGE("%{public}s: failed to get stub object", __func__);
           delete hdfCameraHostHost;
170 171
           return HDF_FAILURE;
       }
172 173
    
       deviceObject->service = &hdfCameraHostHost->ioService;
174 175 176 177 178 179
       return HDF_SUCCESS;
   }
   ```

   下面的函数是远端CameraHost调用的方法:

180
   ```c++
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
   int32_t CameraHostStub::CameraHostServiceStubOnRemoteRequest(int cmdId, MessageParcel &data,
       MessageParcel &reply, MessageOption &option)
   {
       switch(cmdId) {
           case CMD_CAMERA_HOST_SET_CALLBACK: {
               return CameraHostStubSetCallback(data, reply, option);
           }
           case CMD_CAMERA_HOST_GET_CAMERAID: {
               return CameraHostStubGetCameraIds(data, reply, option);
           }
           case CMD_CAMERA_HOST_GET_CAMERA_ABILITY: {
               return CameraHostStubGetCameraAbility(data, reply, option);
           }
           case CMD_CAMERA_HOST_OPEN_CAMERA: {
               return CameraHostStubOpenCamera(data, reply, option);
           }
           case CMD_CAMERA_HOST_SET_FLASH_LIGHT: {
               return CameraHostStubSetFlashlight(data, reply, option);
           }
           default: {
               HDF_LOGE("%s: not support cmd %d", __func__, cmdId);
               return HDF_ERR_INVALID_PARAM;
           }
       }
       return HDF_SUCCESS;
   }
   ```

   CameraHostStubInstance()接口最终调用CameraHostImpl::Init()方法,该方法会获取物理Camera,并对DeviceManager和PipelineCore进行初始化。

211
3. 获取Host服务
212 213 214

   调用Get()接口从远端CameraService中获取CameraHost对象。get()方法如下:

215
   ```c++
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
   sptr<ICameraHost> ICameraHost::Get(const char *serviceName)
   {
       do {
           using namespace OHOS::HDI::ServiceManager::V1_0;
           auto servMgr = IServiceManager::Get();
           if (servMgr == nullptr) {
               HDF_LOGE("%s: IServiceManager failed!", __func__);
               break;
           }
           auto remote = servMgr->GetService(serviceName);  // 根据serviceName名称获取CameraHost
           if (remote != nullptr) {
               sptr<CameraHostProxy> hostSptr = iface_cast<CameraHostProxy>(remote); // 将CameraHostProxy对象返回给调用者,该对象中包含OpenCamera()等方法。
               return hostSptr;
           }
           HDF_LOGE("%s: GetService failed! serviceName = %s", __func__, serviceName);
       } while(false);
       HDF_LOGE("%s: get %s failed!", __func__, serviceName);
       return nullptr;
   }
   ```

237
4. 打开设备
238 239 240 241

   CameraHostProxy对象中有五个方法,分别是SetCallback、GetCameraIds、GetCameraAbility、OpenCamera和SetFlashlight。下面着重描述OpenCamera接口。
   CameraHostProxy的OpenCamera()接口通过CMD_CAMERA_HOST_OPEN_CAMERA调用远端CameraHostStubOpenCamera()接口并获取ICameraDevice对象。

242
   ```c++
243 244
   int32_t CameraHostProxy::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj,
       sptr<ICameraDevice>& device)
245
   {
246 247 248 249 250 251 252
       MessageParcel cameraHostData;
       MessageParcel cameraHostReply;
       MessageOption cameraHostOption(MessageOption::TF_SYNC);
    
       if (!cameraHostData.WriteInterfaceToken(ICameraHost::GetDescriptor())) {
           HDF_LOGE("%{public}s: failed to write interface descriptor!", __func__);
           return HDF_ERR_INVALID_PARAM;
253
       }
254 255 256 257
    
       if (!cameraHostData.WriteCString(cameraId.c_str())) {
           HDF_LOGE("%{public}s: write cameraId failed!", __func__);
           return HDF_ERR_INVALID_PARAM;
258
       }
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
    
       if (!cameraHostData.WriteRemoteObject(OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(callbackObj, 
           ICameraDeviceCallback::GetDescriptor()))) {
           HDF_LOGE("%{public}s: write callbackObj failed!", __func__);
           return HDF_ERR_INVALID_PARAM;
       }
    
       int32_t cameraHostRet = Remote()->SendRequest(CMD_CAMERA_HOST_OPEN_CAMERA, cameraHostData, cameraHostReply, cameraHostOption);
       if (cameraHostRet != HDF_SUCCESS) {
           HDF_LOGE("%{public}s failed, error code is %{public}d", __func__, cameraHostRet);
           return cameraHostRet;
       }
    
       device = hdi_facecast<ICameraDevice>(cameraHostReply.ReadRemoteObject());
    
       return cameraHostRet;
275 276 277 278 279
   }
   ```

   Remote()->SendRequest调用上文提到的CameraHostServiceStubOnRemoteRequest(),根据cmdId进入CameraHostStubOpenCamera()接口,最终调用CameraHostImpl::OpenCamera(),该接口获取了CameraDevice并对硬件进行上电等操作。

280
   ```c++
281 282
   int32_t CameraHostImpl::OpenCamera(const std::string& cameraId, const sptr<ICameraDeviceCallback>& callbackObj,
       sptr<ICameraDevice>& device)
283
   {
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
       CAMERA_LOGD("OpenCamera entry");
       DFX_LOCAL_HITRACE_BEGIN;
       if (CameraIdInvalid(cameraId) != RC_OK || callbackObj == nullptr) {
           CAMERA_LOGW("open camera id is empty or callback is null.");
           return INVALID_ARGUMENT;
       }
    
       auto itr = cameraDeviceMap_.find(cameraId);
       if (itr == cameraDeviceMap_.end()) {
           CAMERA_LOGE("camera device not found.");
           return INSUFFICIENT_RESOURCES;
       }
       CAMERA_LOGD("OpenCamera cameraId find success.");
    
       std::shared_ptr<CameraDeviceImpl> cameraDevice = itr->second;
299 300 301 302
       if (cameraDevice == nullptr) {
           CAMERA_LOGE("camera device is null.");
           return INSUFFICIENT_RESOURCES;
       }
303 304 305 306
    
       CamRetCode ret = cameraDevice->SetCallback(callbackObj);
       CHECK_IF_NOT_EQUAL_RETURN_VALUE(ret, HDI::Camera::V1_0::NO_ERROR, ret);
    
307
       CameraHostConfig *config = CameraHostConfig::GetInstance();
308 309
       CHECK_IF_PTR_NULL_RETURN_VALUE(config, INVALID_ARGUMENT);
    
310 311 312 313 314 315
       std::vector<std::string> phyCameraIds;
       RetCode rc = config->GetPhysicCameraIds(cameraId, phyCameraIds);
       if (rc != RC_OK) {
           CAMERA_LOGE("get physic cameraId failed.");
           return DEVICE_ERROR;
       }
316
       if (CameraPowerUp(cameraId, phyCameraIds) != RC_OK) { // 对Camera硬件上电
317 318 319 320
           CAMERA_LOGE("camera powerup failed.");
           CameraPowerDown(phyCameraIds);
           return DEVICE_ERROR;
       }
321
    
322 323
       auto sptrDevice = deviceBackup_.find(cameraId);
       if (sptrDevice == deviceBackup_.end()) {
324 325 326
   #ifdef CAMERA_BUILT_ON_OHOS_LITE
           deviceBackup_[cameraId] = cameraDevice;
   #else
327
           deviceBackup_[cameraId] = cameraDevice.get();
328
   #endif
329 330 331
       }
       device = deviceBackup_[cameraId];
       cameraDevice->SetStatus(true);
332 333 334
       CAMERA_LOGD("open camera success.");
       DFX_LOCAL_HITRACE_END;
       return HDI::Camera::V1_0::NO_ERROR;
335 336 337
   }
   ```

338
5. 获取流
339 340 341

   CameraDeviceImpl定义了GetStreamOperator、UpdateSettings、SetResultMode和GetEnabledResult等方法,获取流操作方法如下:

342
   ```c++
343 344
   int32_t CameraDeviceImpl::GetStreamOperator(const sptr<IStreamOperatorCallback>& callbackObj,
       sptr<IStreamOperator>& streamOperator)
345
   {
346 347 348
       HDI_DEVICE_PLACE_A_WATCHDOG;
       DFX_LOCAL_HITRACE_BEGIN;
       if (callbackObj == nullptr) {
349 350 351
           CAMERA_LOGW("input callback is null.");
           return INVALID_ARGUMENT;
       }
352 353
    
       spCameraDeciceCallback_ = callbackObj;
354
       if (spStreamOperator_ == nullptr) {
355
   #ifdef CAMERA_BUILT_ON_OHOS_LITE
356
           // 这里创建一个spStreamOperator_ 对象传递给调用者,以便对stream进行各种操作
357 358 359 360
           spStreamOperator_ = std::make_shared<StreamOperator>(spCameraDeciceCallback_, shared_from_this());
   #else
           spStreamOperator_ = new(std::nothrow) StreamOperator(spCameraDeciceCallback_, shared_from_this());
   #endif
361 362 363 364
           if (spStreamOperator_ == nullptr) {
               CAMERA_LOGW("create stream operator failed.");
               return DEVICE_ERROR;
           }
365
           spStreamOperator_->Init();
366 367 368
           ismOperator_ = spStreamOperator_;
       }
       streamOperator = ismOperator_;
369 370 371 372 373
   #ifndef CAMERA_BUILT_ON_OHOS_LITE
       CAMERA_LOGI("CameraDeviceImpl %{public}s: line: %{public}d", __FUNCTION__, __LINE__);
       pipelineCore_->GetStreamPipelineCore()->SetCallback(
           [this](const std::shared_ptr<CameraMetadata> &metadata) {
           OnMetadataChanged(metadata);
374
       });
375 376 377
   #endif
       DFX_LOCAL_HITRACE_END;
       return HDI::Camera::V1_0::NO_ERROR;
378 379 380
   }
   ```

381
6. 创建流
382 383 384

   调用CreateStreams创建流前需要填充StreamInfo结构体,具体内容如下:

385
   ```c++
386 387 388 389 390
   using StreamInfo = struct _StreamInfo {
       int streamId_; 
       int width_;  // 数据流宽
       int height_; // 数据流高
       int format_; // 数据流格式,如PIXEL_FMT_YCRCB_420_SP
391
       int dataSpace_; 
392 393
       StreamIntent intent_; // StreamIntent 如PREVIEW
       bool tunneledMode_;
394
       BufferProducerSequenceable bufferQueue_; // 数据流bufferQueue可用streamCustomer->CreateProducer()接口创建
395 396 397 398 399
       int minFrameDuration_;
       EncodeType encodeType_;
   };
   ```

400
   CreateStreams()接口是StreamOperator(StreamOperatorImpl类是StreamOperator的基类)类中的方法,该接口的主要作用是创建一个StreamBase对象,通过StreamBase的Init方法初始化CreateBufferPool等操作。
401

402
   ```c++
403
   int32_t StreamOperator::CreateStreams(const std::vector<StreamInfo>& streamInfos)
404
   {
405 406 407 408 409 410 411 412 413 414
       PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_);
       DFX_LOCAL_HITRACE_BEGIN;
       for (const auto& it : streamInfos) {
           CHECK_IF_NOT_EQUAL_RETURN_VALUE(CheckStreamInfo(it), true, INVALID_ARGUMENT);
           CAMERA_LOGI("streamId:%{public}d and format:%{public}d and width:%{public}d and height:%{public}d",
               it.streamId_, it.format_, it.width_, it.height_);
           if (streamMap_.count(it.streamId_) > 0) {
               CAMERA_LOGE("stream [id = %{public}d] has already been created.", it.streamId_);
               return INVALID_ARGUMENT;
           }
415
           std::shared_ptr<IStream> stream = StreamFactory::Instance().CreateShared( // 创建Stream实例
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
               IStream::g_availableStreamType[it.intent_], it.streamId_, it.intent_, pipelineCore_, messenger_);
           if (stream == nullptr) {
               CAMERA_LOGE("create stream [id = %{public}d] failed.", it.streamId_);
               return INSUFFICIENT_RESOURCES;
           }
           StreamConfiguration scg;
           StreamInfoToStreamConfiguration(scg, it);
           RetCode rc = stream->ConfigStream(scg);
           if (rc != RC_OK) {
               CAMERA_LOGE("configure stream %{public}d failed", it.streamId_);
               return INVALID_ARGUMENT;
           }
           if (!scg.tunnelMode && (it.bufferQueue_)->producer_ != nullptr) {
               CAMERA_LOGE("stream [id:%{public}d] is not tunnel mode, can't bind a buffer producer", it.streamId_);
               return INVALID_ARGUMENT;
           }
           if ((it.bufferQueue_)->producer_ != nullptr) {
               auto tunnel = std::make_shared<StreamTunnel>();
               CHECK_IF_PTR_NULL_RETURN_VALUE(tunnel, INSUFFICIENT_RESOURCES);
               rc = tunnel->AttachBufferQueue((it.bufferQueue_)->producer_);
               CHECK_IF_NOT_EQUAL_RETURN_VALUE(rc, RC_OK, INVALID_ARGUMENT);
               if (stream->AttachStreamTunnel(tunnel) != RC_OK) {
                   CAMERA_LOGE("attach buffer queue to stream [id = %{public}d] failed", it.streamId_);
                   return INVALID_ARGUMENT;
               }
           }
           {
               std::lock_guard<std::mutex> l(streamLock_);
               streamMap_[stream->GetStreamId()] = stream;
           }
           CAMERA_LOGI("create stream success [id:%{public}d] [type:%{public}s]", stream->GetStreamId(),
                       IStream::g_availableStreamType[it.intent_].c_str());
448
       }
449 450 451
       DFX_LOCAL_HITRACE_END;
       return HDI::Camera::V1_0::NO_ERROR;
    }
452 453
   ```

454
7. 配置流
455 456 457

   CommitStreams()是配置流的接口,必须在创建流之后调用,其主要作用是初始化Pipeline和创建Pipeline。

458
   ```c++
459
   int32_t StreamOperator::CommitStreams(OperationMode mode, const std::vector<uint8_t>& modeSetting)
460
   {
461 462 463 464 465 466
       CAMERA_LOGV("enter");
       CHECK_IF_PTR_NULL_RETURN_VALUE(streamPipeline_, DEVICE_ERROR);
       PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_);
       if (modeSetting.empty()) {
           CAMERA_LOGE("input vector is empty");
           return INVALID_ARGUMENT;
467
       }
468
       DFX_LOCAL_HITRACE_BEGIN;
469
   
470 471 472 473 474
       std::vector<StreamConfiguration> configs = {};
       {
           std::lock_guard<std::mutex> l(streamLock_);
           std::transform(streamMap_.begin(), streamMap_.end(), std::back_inserter(configs),
               [](auto &iter) { return iter.second->GetStreamAttribute(); });
475
       }
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    
       std::shared_ptr<CameraMetadata> setting;
       MetadataUtils::ConvertVecToMetadata(modeSetting, setting);
       DynamicStreamSwitchMode method = streamPipeline_->CheckStreamsSupported(mode, setting, configs);
       if (method == DYNAMIC_STREAM_SWITCH_NOT_SUPPORT) {
           return INVALID_ARGUMENT;
       }
       if (method == DYNAMIC_STREAM_SWITCH_NEED_INNER_RESTART) {
           std::lock_guard<std::mutex> l(streamLock_);
           for (auto it : streamMap_) {
               it.second->StopStream();
           }
       }
       {
           std::lock_guard<std::mutex> l(streamLock_);
           for (auto it : streamMap_) {
               if (it.second->CommitStream() != RC_OK) {
                   CAMERA_LOGE("commit stream [id = %{public}d] failed.", it.first);
                   return DEVICE_ERROR;
               }
           }
       }
498
       RetCode rc = streamPipeline_->PreConfig(setting); // 设备流配置
499
       if (rc != RC_OK) {
500
           CAMERA_LOGE("prepare mode settings failed");
501 502
           return DEVICE_ERROR;
       }
503
       rc = streamPipeline_->CreatePipeline(mode); // 创建一个pipeline
504 505 506 507
       if (rc != RC_OK) {
           CAMERA_LOGE("create pipeline failed.");
           return INVALID_ARGUMENT;
       }
508 509 510
    
       DFX_LOCAL_HITRACE_END;
       return HDI::Camera::V1_0::NO_ERROR;
511 512 513
   }
   ```

514
8. 捕获图像
515 516 517

   在调用Capture()接口前需要先填充CaptureInfo结构体,具体内容如下:

518
   ```c++
519
   using CaptureInfo = struct _CaptureInfo {
520
       int[] streamIds_; // 需要Capture的streamIds
521 522
       unsigned char[]  captureSetting_; // 这里填充camera ability 可通过CameraHost 的GetCameraAbility()接口获取
       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 532 533 534 535 536 537 538 539 540
       CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT);
       PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_);
       DFX_LOCAL_HITRACE_BEGIN;
    
       for (auto id : info.streamIds_) {
           std::lock_guard<std::mutex> l(streamLock_);
           auto it = streamMap_.find(id);
           if (it == streamMap_.end()) {
               return INVALID_ARGUMENT;
           }
541
       }
542
    
543
       {
544 545 546 547 548
           std::lock_guard<std::mutex> l(requestLock_);
           auto itr = requestMap_.find(captureId);
           if (itr != requestMap_.end()) {
               return INVALID_ARGUMENT;
           }
549
       }
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
    
       std::shared_ptr<CameraMetadata> captureSetting;
       MetadataUtils::ConvertVecToMetadata(info.captureSetting_, captureSetting);
       CaptureSetting setting = captureSetting;
       auto request =
           std::make_shared<CaptureRequest>(captureId, info.streamIds_.size(), setting,
                                             info.enableShutterCallback_, isStreaming);
       for (auto id : info.streamIds_) {
           RetCode rc = streamMap_[id]->AddRequest(request);
           if (rc != RC_OK) {
               return DEVICE_ERROR;
           }
       }
    
       {
           std::lock_guard<std::mutex> l(requestLock_);
           requestMap_[captureId] = request;
567
       }
568
       return HDI::Camera::V1_0::NO_ERROR;
569 570 571
   }  
   ```

572
9. 取消捕获和释放离线流
573

574
   StreamOperator类中的CancelCapture()接口的主要作用是根据captureId取消数据流的捕获。
575

576
   ```c++
577
   int32_t StreamOperator::CancelCapture(int32_t captureId)
578
   {
579 580 581 582 583
       CHECK_IF_EQUAL_RETURN_VALUE(captureId < 0, true, INVALID_ARGUMENT);
       PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_);
       DFX_LOCAL_HITRACE_BEGIN;
    
       std::lock_guard<std::mutex> l(requestLock_);
584
       auto itr = requestMap_.find(captureId); // 根据captureId 在Map中查找对应的CameraCapture对象
585 586 587 588 589
       if (itr == requestMap_.end()) {
           CAMERA_LOGE("can't cancel capture [id = %{public}d], this capture doesn't exist", captureId);
           return INVALID_ARGUMENT;
       }
    
590
       RetCode rc = itr->second->Cancel(); // 调用CameraCapture中Cancel方法结束数据捕获
591 592 593
       if (rc != RC_OK) {
           return DEVICE_ERROR;
       }
594
       requestMap_.erase(itr); // 擦除该CameraCapture对象
595 596 597
    
       DFX_LOCAL_HITRACE_END;
       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 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
       PLACE_A_NOKILL_WATCHDOG(requestTimeoutCB_);
       DFX_LOCAL_HITRACE_BEGIN;
       for (auto id : streamIds) {
           std::lock_guard<std::mutex> l(streamLock_);
           auto it = streamMap_.find(id);
           if (it == streamMap_.end()) {
               continue;
           }
           if (it->second->IsRunning()) {
               it->second->StopStream();
           }
           it->second->DumpStatsInfo();
           streamMap_.erase(it);
       }
    
       for (auto id : streamIds) {
           CHECK_IF_EQUAL_RETURN_VALUE(id < 0, true, INVALID_ARGUMENT);
       }
    
       DFX_LOCAL_HITRACE_END;
       return HDI::Camera::V1_0::NO_ERROR;
627 628 629
   }
   ```

630
10. 关闭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/master/camera/hal/init)。
637

638
1. 在main函数中构造一个CameraDemo 对象,该对象中有对Camera初始化、启停流、释放等控制的方法。下面mainDemo->InitSensors()函数为初始化CameraHost,mainDemo->InitCameraDevice()函数为初始化CameraDevice。
639

640
   ```c++
641 642 643
   int main(int argc, char** argv)
   {
       RetCode rc = RC_OK;
644
       auto mainDemo = std::make_shared<CameraDemo>();
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
       rc = mainDemo->InitSensors(); // 初始化CameraHost
       if (rc == RC_ERROR) {
           CAMERA_LOGE("main test: mainDemo->InitSensors() error\n");
           return -1;
       }
   
       rc = mainDemo->InitCameraDevice(); // 初始化CameraDevice
       if (rc == RC_ERROR) {
           CAMERA_LOGE("main test: mainDemo->InitCameraDevice() error\n");
           return -1;
       }
   
       rc = PreviewOn(0, mainDemo); // 配流和启流
       if (rc != RC_OK) {
           CAMERA_LOGE("main test: PreviewOn() error demo exit");
           return -1;
       }
   
       ManuList(mainDemo, argc, argv); // 打印菜单到控制台
   
       return RC_OK;
   }
   ```

   初始化CameraHost函数实现如下,这里调用了HDI接口ICameraHost::Get()去获取demoCameraHost,并对其设置回调函数。

671
   ```c++
672
   RetCode OhosCameraDemo::InitSensors()
673
   {
674 675 676 677 678 679 680 681 682 683 684 685 686
       int rc = 0;
   
       CAMERA_LOGD("demo test: InitSensors enter");
    
       if (demoCameraHost_ != nullptr) {
           return RC_OK;
       }
   #ifdef CAMERA_BUILT_ON_OHOS_LITE
       demoCameraHost_ = OHOS::Camera::CameraHost::CreateCameraHost();
   #else
       constexpr const char *DEMO_SERVICE_NAME = "camera_service";
       demoCameraHost_ = ICameraHost::Get(DEMO_SERVICE_NAME, false);
   #endif
687 688 689 690
       if (demoCameraHost_ == nullptr) {
           CAMERA_LOGE("demo test: ICameraHost::Get error");
           return RC_ERROR;
       }
691 692 693 694 695 696
    
   #ifdef CAMERA_BUILT_ON_OHOS_LITE
       hostCallback_ = std::make_shared<DemoCameraHostCallback>();
   #else
       hostCallback_ = new DemoCameraHostCallback();
   #endif
697
       rc = demoCameraHost_->SetCallback(hostCallback_);
698 699 700 701 702 703 704
       if (rc != HDI::Camera::V1_0::NO_ERROR) {
           CAMERA_LOGE("demo test: demoCameraHost_->SetCallback(hostCallback_) error");
           return RC_ERROR;
       }
    
       CAMERA_LOGD("demo test: InitSensors exit");
    
705 706 707 708 709 710
       return RC_OK;
   }
   ```

   初始化CameraDevice函数实现如下,这里调用了GetCameraIds(cameraIds_),GetCameraAbility(cameraId, ability_),OpenCamera(cameraIds_.front(), callback, demoCameraDevice_)等接口实现了demoCameraHost的获取。

711
   ```c++
712
   RetCode OhosCameraDemo::InitCameraDevice()
713
   {
714 715 716 717 718 719 720 721 722
       int rc = 0;
    
       CAMERA_LOGD("demo test: InitCameraDevice enter");
    
       if (demoCameraHost_ == nullptr) {
           CAMERA_LOGE("demo test: InitCameraDevice demoCameraHost_ == nullptr");
           return RC_ERROR;
       }
    
723
       (void)demoCameraHost_->GetCameraIds(cameraIds_);
724 725 726
       if (cameraIds_.empty()) {
           return RC_ERROR;
       }
727
       const std::string cameraId = cameraIds_.front();
728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
       demoCameraHost_->GetCameraAbility(cameraId, cameraAbility_);
    
       MetadataUtils::ConvertVecToMetadata(cameraAbility_, ability_);
    
       GetFaceDetectMode(ability_);
       GetFocalLength(ability_);
       GetAvailableFocusModes(ability_);
       GetAvailableExposureModes(ability_);
       GetExposureCompensationRange(ability_);
       GetExposureCompensationSteps(ability_);
       GetAvailableMeterModes(ability_);
       GetAvailableFlashModes(ability_);
       GetMirrorSupported(ability_);
       GetStreamBasicConfigurations(ability_);
       GetFpsRange(ability_);
       GetCameraPosition(ability_);
       GetCameraType(ability_);
       GetCameraConnectionType(ability_);
       GetFaceDetectMaxNum(ability_);
    
   #ifdef CAMERA_BUILT_ON_OHOS_LITE
       std::shared_ptr<CameraDeviceCallback> callback = std::make_shared<CameraDeviceCallback>();
   #else
       sptr<DemoCameraDeviceCallback> callback = new DemoCameraDeviceCallback();
   #endif
753
       rc = demoCameraHost_->OpenCamera(cameraIds_.front(), callback, demoCameraDevice_);
754 755 756 757 758 759 760
       if (rc != HDI::Camera::V1_0::NO_ERROR || demoCameraDevice_ == nullptr) {
           CAMERA_LOGE("demo test: InitCameraDevice OpenCamera failed");
           return RC_ERROR;
       }
    
       CAMERA_LOGD("demo test: InitCameraDevice exit");
    
761 762 763
       return RC_OK;
   }   
   ```
764

765
2. 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 771 772
       RetCode rc = RC_OK;
       CAMERA_LOGD("main test: PreviewOn enter");
    
773
       rc = mainDemo->StartPreviewStream(); // 配置preview流
774 775 776 777 778 779
       if (rc != RC_OK) {
           CAMERA_LOGE("main test: PreviewOn StartPreviewStream error");
           return RC_ERROR;
       }
    
       if (mode == 0) {
780
           rc = mainDemo->StartCaptureStream(); // 配置capture流
781 782 783 784 785
           if (rc != RC_OK) {
               CAMERA_LOGE("main test: PreviewOn StartCaptureStream error");
               return RC_ERROR;
           }
       } else {
786
           rc = mainDemo->StartVideoStream(); // 配置video流
787 788 789 790 791 792 793 794 795 796 797 798 799
           if (rc != RC_OK) {
               CAMERA_LOGE("main test: PreviewOn StartVideoStream error");
               return RC_ERROR;
           }
       }
    
       rc = mainDemo->CaptureON(STREAM_ID_PREVIEW, CAPTURE_ID_PREVIEW, CAPTURE_PREVIEW);
       if (rc != RC_OK) {
           CAMERA_LOGE("main test: PreviewOn mainDemo->CaptureON() preview error");
           return RC_ERROR;
       }
    
       CAMERA_LOGD("main test: PreviewOn exit");
800 801 802 803 804 805 806 807
       return RC_OK;
   }           
   ```

   StartCaptureStream()、StartVideoStream()和StartPreviewStream()接口都会调用CreateStream()接口,只是传入的参数不同。

   CreateStream()方法调用HDI接口去配置和创建流,首先调用HDI接口去获取StreamOperation对象,然后创建一个StreamInfo。调用CreateStreams()和CommitStreams()实际创建流并配置流。

808
   ```c++
809 810
   RetCode OhosCameraDemo::CreateStream(const int streamId, std::shared_ptr<StreamCustomer> &streamCustomer,
       StreamIntent intent)
811
   {
812 813 814
       int rc = 0;
       CAMERA_LOGD("demo test: CreateStream enter");
    
815
       GetStreamOpt(); // 获取StreamOperator对象
816 817
       if (streamOperator_ == nullptr) {
           CAMERA_LOGE("demo test: CreateStream GetStreamOpt() is nullptr\n");
818 819
           return RC_ERROR;
       }
820 821 822
    
       StreamInfo streamInfo = {0};
    
823
       SetStreamInfo(streamInfo, streamCustomer, streamId, intent); // 填充StreamInfo流
824 825
       if (streamInfo.bufferQueue_->producer_ == nullptr) {
           CAMERA_LOGE("demo test: CreateStream CreateProducer(); is nullptr\n");
826 827
           return RC_ERROR;
       }
828 829 830 831
    
       std::vector<StreamInfo> streamInfos;
       streamInfos.push_back(streamInfo);
    
832
       rc = streamOperator_->CreateStreams(streamInfos); // 创建流
833
       if (rc != HDI::Camera::V1_0::NO_ERROR) {
834 835 836
           CAMERA_LOGE("demo test: CreateStream CreateStreams error\n");
           return RC_ERROR;
       }
837

838 839
       rc = streamOperator_->CommitStreams(NORMAL, cameraAbility_);
       if (rc != HDI::Camera::V1_0::NO_ERROR) {
840
           CAMERA_LOGE("demo test: CreateStream CommitStreams error\n");
841 842
           std::vector<int> streamIds;
           streamIds.push_back(streamId);
843 844 845
           streamOperator_->ReleaseStreams(streamIds);
           return RC_ERROR;
       }
846

847 848
       CAMERA_LOGD("demo test: CreateStream exit");
    
849 850 851 852
       return RC_OK;
   }
   ```

853
   CaptureON()接口调用streamOperator的Capture()方法获取Camera数据并轮转buffer,拉起一个线程接收相应类型的数据。
854

855
   ```c++
856 857
   RetCode OhosCameraDemo::CaptureON(const int streamId,
       const int captureId, CaptureMode mode)
858
   {
859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
       CAMERA_LOGI("demo test: CaptureON enter streamId == %{public}d and captureId == %{public}d and mode == %{public}d",
           streamId, captureId, mode);
       std::lock_guard<std::mutex> l(metaDatalock_);
       if (mode == CAPTURE_SNAPSHOT) {
           constexpr double latitude = 27.987500; // dummy data: Qomolangma latitde
           constexpr double longitude = 86.927500; // dummy data: Qomolangma longituude
           constexpr double altitude = 8848.86; // dummy data: Qomolangma altitude
           constexpr size_t entryCapacity = 100;
           constexpr size_t dataCapacity = 2000;
           captureSetting_ = std::make_shared<CameraSetting>(entryCapacity, dataCapacity);
           captureQuality_ = OHOS_CAMERA_JPEG_LEVEL_HIGH;
           captureOrientation_ = OHOS_CAMERA_JPEG_ROTATION_270;
           mirrorSwitch_ = OHOS_CAMERA_MIRROR_ON;
           gps_.push_back(latitude);
           gps_.push_back(longitude);
           gps_.push_back(altitude);
           captureSetting_->addEntry(OHOS_JPEG_QUALITY, static_cast<void*>(&captureQuality_),
               sizeof(captureQuality_));
           captureSetting_->addEntry(OHOS_JPEG_ORIENTATION, static_cast<void*>(&captureOrientation_),
               sizeof(captureOrientation_));
           captureSetting_->addEntry(OHOS_CONTROL_CAPTURE_MIRROR, static_cast<void*>(&mirrorSwitch_),
               sizeof(mirrorSwitch_));
           captureSetting_->addEntry(OHOS_JPEG_GPS_COORDINATES, gps_.data(), gps_.size());
       }
    
       std::vector<uint8_t> setting;
       MetadataUtils::ConvertMetadataToVec(captureSetting_, setting);
       captureInfo_.streamIds_ = {streamId};
       if (mode == CAPTURE_SNAPSHOT) {
           captureInfo_.captureSetting_ = setting;
       } else {
           captureInfo_.captureSetting_ = cameraAbility_;
       }
       captureInfo_.enableShutterCallback_ = false;
    
894
       int rc = streamOperator_->Capture(captureId, captureInfo_, true); // 实际capture开始,buffer轮转开始
895 896 897 898 899 900
       if (rc != HDI::Camera::V1_0::NO_ERROR) {
           CAMERA_LOGE("demo test: CaptureStart Capture error\n");
           streamOperator_->ReleaseStreams(captureInfo_.streamIds_);
           return RC_ERROR;
       }
    
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 906 907 908
               StoreImage(addr, size);
           });
       } else if (mode == CAPTURE_VIDEO) {
           OpenVideoFile();
909
    
910
           streamCustomerVideo_->ReceiveFrameOn([this](void* addr, const uint32_t size) { // 创建video线程通过StoreImage回调接收传递上来的buffer
911 912 913
               StoreVideo(addr, size);
           });
       }
914 915
       CAMERA_LOGD("demo test: CaptureON exit");
    
916 917 918
       return RC_OK;
   }
   ```
919

920
3. ManuList()函数从控制台通过fgets()接口获取字符,不同字符所对应demo支持的功能不同,并打印出该demo所支持功能的菜单。
921

922
   ```c++
923
   static void ManuList(const std::shared_ptr<OhosCameraDemo>& mainDemo,
924 925 926
       const int argc, char** argv)
   {
       int idx, c;
927 928 929 930
       bool isAwb = true;
       const char *shortOptions = "h:cwvaeqof:";
       c = getopt_long(argc, argv, shortOptions, LONG_OPTIONS, &idx);
       while (1) {
931 932
           switch (c) {
               case 'h':
933
                   c = PutMenuAndGetChr(); // 打印菜单
934
                   break;
935
               case 'f':
936
                   FlashLightTest(mainDemo); // 手电筒功能测试
937 938 939
                   c = PutMenuAndGetChr();
                   break;
               case 'o':
940
                   OfflineTest(mainDemo); // Offline功能测试
941 942 943
                   c = PutMenuAndGetChr();
                   break;
               case 'c':
944
                   CaptureTest(mainDemo); // Capture功能测试
945 946
                   c = PutMenuAndGetChr();
                   break;
947
               case 'w': // AWB功能测试
948
                   if (isAwb) {
949 950 951 952
                       mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_INCANDESCENT);
                   } else {
                       mainDemo->SetAwbMode(OHOS_CAMERA_AWB_MODE_OFF);
                   }
953
                   isAwb = !isAwb;
954 955
                   c = PutMenuAndGetChr();
                   break;
956
               case 'a': // AE功能测试
957 958 959
                   mainDemo->SetAeExpo();
                   c = PutMenuAndGetChr();
                   break;
960
               case 'e': // Metadata测试
961 962 963
                   mainDemo->SetMetadata();
                   c = PutMenuAndGetChr();
                   break;
964
               case 'v': // VIDEO功能测试
965 966 967
                   VideoTest(mainDemo);
                   c = PutMenuAndGetChr();
                   break;
968
               case 'q': // 退出demo
969 970
                   PreviewOff(mainDemo);
                   mainDemo->QuitDemo();
971
                   return;
972 973 974 975 976 977 978 979 980 981 982
               default:
                   CAMERA_LOGE("main test: command error please retry input command");
                   c = PutMenuAndGetChr();
                   break;
           }
       }
   }
   ```

   PutMenuAndGetChr()接口打印了demo程序的菜单,并调用fgets()等待从控制台输入命令,内容如下:

983
   ```c++
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004
   static int PutMenuAndGetChr(void)
   {
       constexpr uint32_t inputCount = 50;
       int c = 0;
       char strs[inputCount];
       Usage(stdout);
       CAMERA_LOGD("pls input command(input -q exit this app)\n");
       fgets(strs, inputCount, stdin);
   
       for (int i = 0; i < inputCount; i++) {
           if (strs[i] != '-') {
               c = strs[i];
               break;
           }
       }
       return c;
   }
   ```

   控制台输出菜单详情如下:

1005
   ```c++
1006 1007 1008 1009 1010
   "Options:\n"
   "-h | --help          Print this message\n"
   "-o | --offline       stream offline test\n"
   "-c | --capture       capture one picture\n"
   "-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 1015 1016
   "-f | --Set Flashlight        Set flashlight ON 5s OFF\n"
   "-q | --quit          stop preview and quit this app\n");
   ```
1017

1018
4. 编译用例         
1019
   在drivers/peripheral/camera/hal/BUILD.gn文件中的deps中添加“init:ohos_camera_demo”,示例代码如下:
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
   ```
   deps = [
       "buffer_manager:camera_buffer_manager",
       "device_manager:camera_device_manager",
       "hdi_impl:camera_host_service_1.0",
       "pipeline_core:camera_pipeline_core",
       "utils:camera_utils",
       "init:ohos_camera_demo",
       ]
   ```
1030

1031
   以RK3568为例:        
1032 1033
   1. 执行全量编译命令./build.sh --product-name rk3568 --ccache,生成可执行二进制文件ohos_camera_demo,路径为:out/rk3568/packages/phone/vendor/bin/。        
   2. 将可执行文件ohos_camera_demo导入开发板,修改权限直接运行即可。