1## <center>OpenHarmony**相机性能提升开发指导**</center> 2 3# 概述 4 5 相机启动性能受限于底层器件上点、流程Pipeline初始化等耗时操作影响,本文档旨在为开发者提供更进一步功能,提升相机启动速度以及拍照返回缩略图速度。相关能力与底层器件相关,不代表所有硬件均支持相关特性。 6 7 相关特性分别在打开相机设备过程、配流过程以及拍照过程中。本文档针对三个场景分别进行介绍 8 9# 预热启动 10 11## 场景描述 12 13 普通情况下相机应用的启动是用户通过点击桌面相机图标触发的。桌面应用感知用户点击相机图标,然后通知应用管理器启动对应的相机应用(进程),这个过程是比较耗时的。进入相机应用后,开始进入相机启动流程。经典的相机启动过程会经过,“相机设备打开”,“配置数据流”,“启动数据流等”,这也是一个耗时的过程。 14 15 相机启动方案是把“相机设备打开”这个动作提前到相机应用启动之前,即在用户点击相机图标,还没等相机应用启动的时候,触发相机设备打开的动作,从而缩短相机应用内启动相机的流程,加速相机启动。使用预热启动前后的相机应用流程对比如下: 16 17 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 78无 79 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 120无 121 122**返回值:** 123 124无 125 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 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 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 245无 246 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 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 299在CaptureSession.addOutput(photoOutput: PhotoOutput)、CaptureSession.addInput(cameraInput: CameraInput)之后,CaptureSession.commitConfig()之前生效。 300 301**系统能力:** SystemCapability.Multimedia.Camera.Core 302 303**参数:** 304 305无 306 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 347在CaptureSession.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 359无 360 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 410无 411 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 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)之后生效。