1## <center>OpenHarmony**相机性能提升开发指导**</center>
2
3# 概述
4
5​	相机启动性能受限于底层器件上点、流程Pipeline初始化等耗时操作影响,本文档旨在为开发者提供更进一步功能,提升相机启动速度以及拍照返回缩略图速度。相关能力与底层器件相关,不代表所有硬件均支持相关特性。
6
7​	相关特性分别在打开相机设备过程、配流过程以及拍照过程中。本文档针对三个场景分别进行介绍
8
9# 预热启动
10
11## 场景描述
12
13​	普通情况下相机应用的启动是用户通过点击桌面相机图标触发的。桌面应用感知用户点击相机图标,然后通知应用管理器启动对应的相机应用(进程),这个过程是比较耗时的。进入相机应用后,开始进入相机启动流程。经典的相机启动过程会经过,“相机设备打开”,“配置数据流”,“启动数据流等”,这也是一个耗时的过程。
14
15​	相机启动方案是把“相机设备打开”这个动作提前到相机应用启动之前,即在用户点击相机图标,还没等相机应用启动的时候,触发相机设备打开的动作,从而缩短相机应用内启动相机的流程,加速相机启动。使用预热启动前后的相机应用流程对比如下:
16
17![image-20230524105824546](../figures/prelaunch-scene.png)
18
19
20
21## 接口描述
22
23### isPrelaunchSupported
24
25isPrelaunchSupported(camera: CameraDevice) : boolean
26
27在setPrelaunchConfig接口使用前调用,用于判断指定cameraDevice是否支持预热启动。
28
29**系统能力:** SystemCapability.Multimedia.Camera.Core
30
31**参数:**
32
33| 参数名 | 类型         | 必填 | 说明       |
34| ------ | ------------ | ---- | ---------- |
35| camera | CameraDevice | 是   | 相机信息。 |
36
37**返回值:**
38
39| 类型    | 说明                                 |
40| ------- | ------------------------------------ |
41| boolean | 返回指定cameraDevice是否支持预热启动 |
42
43**错误码:**
44
45不涉及
46
47**示例:**
48
49```js
50import camera from '@ohos.multimedia.camera'
51
52this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
53let cameras = this.cameraManager.getSupportedCameras()
54if(this.cameraManager.isPrelaunchSupported(cameras[0])) {
55     this.cameraManager.setPrelaunchConfig({cameraDevice: cameras[0]});
56}
57```
58
59### setPrelaunchConfig
60
61setPrelaunchConfig(camera: CameraDevice) : void
62
63配置相机预热参数,指定相机设备(待扩展流参数信息等)。
64用户操作会产生下一次进入相机的预热配置变化,或是退出相机时,向相机服务发送预热配置参数。
65
66**需要权限:** ohos.permission.CAMERA
67
68**系统能力:** SystemCapability.Multimedia.Camera.Core
69
70**参数:**
71
72| 参数名 | 类型         | 必填 | 说明       |
73| ------ | ------------ | ---- | ---------- |
74| camera | CameraDevice | 是   | 相机信息。 |
75
76**返回值:**
77
7879
80**错误码:**
81
82| 类型    | 说明                                 |
83| ------- | ------------------------------------ |
84| BusinessError  | 7400101 缺少参数或者参数类型错误 <br />7400102 权限校验失败 |
85
86**示例:**
87
88```js
89import camera from '@ohos.multimedia.camera'
90
91this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
92let cameras = this.cameraManager.getSupportedCameras()
93if(this.cameraManager.isPrelaunchSupported(cameras[0])) {
94    try {
95    	this.cameraManager.setPrelaunchConfig({cameraDevice: cameras[0]});
96    } catch (error) {
97        HiLog.e(TAG, `catch error: ${JSON.stringify(error)}`)
98    }
99}
100```
101```json
102"requestPermissions": [
103      {
104        "name": "ohos.permission.CAMERA"
105      }
106]
107```
108
109### prelaunch
110prelaunch() : void
111
112用户点击系统相机图标,拉起相机应用同时调用,下发预热请求,使能相机预热启动。
113
114**需要权限:** ohos.permission.CAMERA
115
116**系统能力:** SystemCapability.Multimedia.Camera.Core
117
118**参数:**
119
120121
122**返回值:**
123
124125
126**错误码:**
127
128| 类型    | 说明                                 |
129| ------- | ------------------------------------ |
130| BusinessError  | 7400102 权限校验失败 |
131
132**示例:**
133
134```js
135import camera from '@ohos.multimedia.camera'
136
137this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
138try {
139   this.cameraManager.prelaunch();
140} catch (error) {
141    HiLog.e(TAG, `catch error: ${JSON.stringify(error)}`)
142}
143```
144```json
145"requestPermissions": [
146      {
147        "name": "ohos.permission.CAMERA"
148      }
149]
150```
151
152### PrelaunchConfig
153新增参数类型,预热配置参数,当前sensor级别预热,待扩展流预热参数
154
155**示例:**
156
157```js
158this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
159let cameras = this.cameraManager.getSupportedCameras()
160this.prelaunchConfig: PrelaunchConfig = {
161    cameraDevice: cameras[0]
162}
163if(this.cameraManager.isPrelaunchSupported(cameras[0])) {
164     this.cameraManager.setPrelaunchConfig(this.prelaunchConfig);
165}
166```
167
168
169## 调用流程
170
171启动方案调用流程图建议如下:
172
173![image-20230524100713046](../figures/prelaunch-sequence-diagram.png)
174
175## 注意事项
176
177*  预热启动方案相关API均为SystemAPI,如若使用,需申请系统应用权限,app-feature级别设置为hos_system_app。
178
179
180
181# 延时配流
182
183## 场景描述
184
185经典的相机启动过程经过“相机设备打开”、“配置数据流”、“启动数据流”等流程,而配流启流之前需要得到图形组件的surfaceId。
186
187延时配流方案是把配流启流与surface解耦,在组件尚未给应用surface之前,可以先进行配流启流,只需要在启流结束之前提供surface,可以提升启动速度,防止影响其他启动优化方案的落地。
188
189![image-20230529093514951](../figures/deferred-surface-scene.png)
190
191## 接口描述
192
193### createDeferredPreviewOutput
194
195createDeferredPreviewOutput(profile: Profile): Promise\<PreviewOutput\>
196
197创建延迟预览输出对象,在配流时替代普通的预览输出对象加入数据流。
198
199**系统能力:** SystemCapability.Multimedia.Camera.Core
200
201**参数:**
202
203| 类型    | 说明                 |
204| ------- | -------------------- |
205| Profile | 相机预览流的配置文件 |
206
207**返回值:**
208
209| 类型          | 说明               |
210| ------------- | ------------------ |
211| PreviewOutput | 返回预览输出对象。 |
212
213**错误码:**
214
215不涉及
216
217**示例:**
218
219```js
220import camera from '@ohos.multimedia.camera';
221
222function getDeferredPreviewOutput(context: Context, previewProfile: camera.Profile): Promise<PreviewOutput> {
223  const cameraManager = camera.getCameraManager(context);
224  const output: Promise<PreviewOutput> = 	 cameraManager.createDeferredPreviewOutput(previewProfile);
225  return output;
226}
227```
228
229### addDeferredSurface
230
231addDeferredSurface(surfaceId: string): Promise\<void\>
232
233配置延迟预览的Surface,可以在session.commitConfig()配流和session.start()启流之后运行。
234
235**系统能力:** SystemCapability.Multimedia.Camera.Core
236
237**参数:**
238
239| 类型   | 说明                  |
240| ------ | --------------------- |
241| string | 预览使用的surfaceId。 |
242
243**返回值:**
244
245246
247**错误码:**
248
249| 类型          | 说明                  |
250| ------------- | --------------------- |
251| BusinessError | 7400104 session未配置 |
252
253**示例**:
254
255```js
256import camera from '@ohos.multimedia.camera';
257
258function async preview(context: Context, cameraInfo: camera.Device, previewProfile: camera.Profile, photoProfile: camera.Profile, surfaceId: string): Promise<void> {
259  const cameraManager: camera.CameraManager = camera.getCameraManager(context);
260  const cameraInput camera.CameraInput = await cameraManager.createCameraInput(cameraInfo)
261  const previewOutput: camera.PreviewOutput = await cameraManager.createDeferredPreviewOutput(previewProfile);
262  const photoOutput: camera.PhotoOutput = await cameraManager.createPhotoOutput(photoProfile);
263  const session: camera.CaptureSession  = await this.mCameraManager.createCaptureSession();
264  await session.beginConfig();
265  await session.addInput(cameraInput);
266  await session.addOutput(previewOutput);
267  await session.addOutput(photoOutput);
268  await session.commitConfig();
269  await session.start();
270  await previewOutput.addDeferredSurface(surfaceId);
271}
272```
273
274## 调用流程
275
276![image-20230529103448268](../figures/deferred-surface-sequence-diagram.png)
277
278## 注意事项
279
280* 延时配流方案相关API均为SystemAPI,如若使用,需申请系统应用权限,app-feature级别设置为hos_system_app。
281
282
283
284# 快速缩略图
285## 场景描述
286
287相机拍照性能依赖算法处理的速度,算法链越复杂、效果就越好,但同时处理时间就越长。要能够从拍照流程上进行优化,既满足后处理算法处理的要求,又不要阻塞前台的拍照速度。
288
289通过相机快速缩略图技术,相机拍照可单独输出拇指缩略图,在真图没有上来前,提前上报一张缩略图给应用去显示,提升shot2see用户感知拍照速度。
290
291## 接口描述
292
293### isQuickThumbnailSupported
294
295isQuickThumbnailSupported() : boolean
296
297是否支持快速缩略图。
298
299CaptureSession.addOutput(photoOutput: PhotoOutput)、CaptureSession.addInput(cameraInput: CameraInput)之后,CaptureSession.commitConfig()之前生效。
300
301**系统能力:** SystemCapability.Multimedia.Camera.Core
302
303**参数:**
304
305306
307**返回值:**
308
309| 类型    | 说明                                             |
310| ------- | ------------------------------------------------ |
311| boolean | 返回当前CaptureSession中拍照流是否支持快速缩略图 |
312
313**错误码:**
314
315| 类型          | 说明                  |
316| ------------- | --------------------- |
317| BusinessError | 7400104 session未配置 |
318
319**示例:**
320
321```js
322import camera from '@ohos.multimedia.camera'
323
324this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
325let cameras = this.cameraManager.getSupportedCameras()
326// 创建CaptureSession实例
327this.captureSession = await this.cameraManager.createCaptureSession()
328// 开始配置会话
329await this.captureSession.beginConfig()
330// 把CameraInput加入到会话
331this.mCameraInput = await this.cameraManager.createCameraInput(cameras[0])
332await this.cameraInput.open()
333await this.captureSession.addInput(this.cameraInput)
334// 把PhotoOutPut加入到会话
335this.photoOutPut = await this.cameraManager.createPhotoOutput(photoProfile, surfaceId)
336await this.captureSession.addOutput(this.photoOutPut)
337
338boolean isSupported = this.photoOutPut.isQuickThumbnailSupported()
339```
340
341### enableQuickThumbnail
342
343enableQuickThumbnail (enabled:bool): void
344
345使能/去使能快速缩略图。
346
347CaptureSession.addOutput(photoOutput: PhotoOutput)、CaptureSession.addInput(cameraInput: CameraInput)之后,CaptureSession.commitConfig()之前生效。
348
349**系统能力:** SystemCapability.Multimedia.Camera.Core
350
351**参数:**
352
353| 参数名  | 类型    | 必填 | 说明               |
354| ------- | ------- | ---- | ------------------ |
355| enabled | boolean | 是   | 是否使能快速缩略图 |
356
357**返回值:**
358
359360
361**错误码:**
362
363| 类型    | 说明                                 |
364| ------- | ------------------------------------ |
365| BusinessError  | 7400104 session未配置 |
366
367**示例:**
368
369```js
370import camera from '@ohos.multimedia.camera'
371
372this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
373let cameras = this.cameraManager.getSupportedCameras()
374// 创建CaptureSession实例
375this.captureSession = await this.cameraManager.createCaptureSession()
376// 开始配置会话
377await this.captureSession.beginConfig()
378// 把CameraInput加入到会话
379this.cameraInput = await this.cameraManager.createCameraInput(cameras[0])
380await this.cameraInput.open()
381await this.captureSession.addInput(this.cameraInput)
382// 把PhotoOutPut加入到会话
383this.photoOutPut = await this.cameraManager.createPhotoOutput(photoProfile, surfaceId)
384await this.captureSession.addOutput(this.photoOutPut)
385boolean isSupported = this.photoOutPut.isQuickThumbnailSupported()
386if (isSupported) {
387    // 使能快速缩略图
388    this.photoOutPut.enableQuickThumbnail(true)
389}
390```
391
392### on
393on (type: "quickThumbnail", callback: AsyncCallback<thumbnail: PixelMap>): void
394
395配置相机缩略图回调接口
396
397在enableQuickThumbnail(true)使能快速缩略图之后监听生效。
398
399**系统能力:** SystemCapability.Multimedia.Camera.Core
400
401**参数:**
402
403| 参数名 | 类型   | 必填 | 说明         |
404| ------ | ------ | ---- | ------------ |
405| type   | String | 是   | 监听事件类型 |
406| callback    | Function | 是   | 回调函数,返回PixelMap |
407
408**返回值:**
409
410411
412**错误码:**
413
414不涉及
415
416**示例:**
417
418```js
419import camera from '@ohos.multimedia.camera'
420
421this.cameraManager = camera.getCameraManager(globalThis.abilityContext);
422let cameras = this.cameraManager.getSupportedCameras()
423// 创建CaptureSession实例
424this.captureSession = await this.cameraManager.createCaptureSession()
425// 开始配置会话
426await this.captureSession.beginConfig()
427// 把CameraInput加入到会话
428this.cameraInput = await this.cameraManager.createCameraInput(cameras[0])
429await this.cameraInput.open()
430await this.captureSession.addInput(this.cameraInput)
431// 把PhotoOutPut加入到会话
432this.photoOutPut = await this.cameraManager.createPhotoOutput(photoProfile, surfaceId)
433await this.captureSession.addOutput(this.photoOutPut)
434boolean isSupported = this.photoOutPut.isQuickThumbnailSupported()
435if (isSupported) {
436    // 使能快速缩略图
437    this.photoOutPut.enableQuickThumbnail(true)
438}
439this.photoOutPut.on('quickThumbnail', (err, pixelmap) => {
440    if (err || pixelmap === undefined) {
441        Logger.error(this.tag, 'photoOutPut on thumbnail failed ')
442        return
443    }
444    // 显示或保存pixelmap
445    this.showOrSavePicture(pixelmap)
446})
447```
448
449
450## 调用流程
451
452启动方案调用流程图建议如下:
453
454![image-20230524113602445](../figures/quick-thumbnail-sequence-diagram.png)
455
456## 注意事项
457
458*  快缩缩略图方案相关API均为SystemAPI,如若使用,需申请系统应用权限,app-feature级别设置为hos_system_app。
459*  isQuickThumbnailSupported及enableQuickThumbnail 接口需要在CaptureSession.addOutput(photoOutput: PhotoOutput)、CaptureSession.addInput(cameraInput: CameraInput)之后,CaptureSession.commitConfig()之前生效。
460*  on (type: "quickThumbnail", callback: AsyncCallback<thumbnail: PixelMap>)接口需要在enableQuickThumbnail (true)之后生效。