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