1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the 'License'); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an 'AS IS' BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15// @ts-nocheck 16import camera from '@ohos.multimedia.camera'; 17import image from '@ohos.multimedia.image'; 18import media from '@ohos.multimedia.media'; 19import { BusinessError } from '@ohos.base'; 20import Logger from '../model/Logger'; 21import { Constants } from '../common/Constants'; 22import photoAccessHelper from '@ohos.file.photoAccessHelper'; 23import fs from '@ohos.file.fs'; 24import { GlobalContext } from '../common/GlobalContext'; 25import type { CameraConfig } from '../common/CameraConfig'; 26import colorSpaceManager from '@ohos.graphics.colorSpaceManager'; 27 28const cameraSize = { 29 width: 1280, 30 height: 720 31}; 32 33enum PhotoOrientation { 34 ORIENTATION_0 = 0, 35 ORIENTATION_1, 36 ORIENTATION_2, 37 ORIENTATION_3 38} 39 40enum CaptureMode { 41 OLD_CAPTURE = 0, 42 NEW_CAPTURE, 43 NEW_DEFERRED_PHOTO 44} 45 46enum CameraMode { 47 NORMAL = 0, 48 VIDEO, 49 PORTRAIT, 50 SUPER_STAB, 51 NIGHT 52} 53 54function mockInterface(): void { 55 if (!camera.SceneFeatureType) { 56 camera.SceneFeatureType = { MOON_CAPTURE_BOOST: 0 }; 57 } 58 if (!camera.SceneMode) { 59 camera.SceneMode = { 60 NORMAL_PHOTO: 1, 61 NORMAL_VIDEO: 2, 62 PORTRAIT_PHOTO: 3, 63 NIGHT_PHOTO: 4 64 }; 65 } 66} 67 68const TAG: string = 'CameraService'; 69 70class CameraService { 71 private captureMode: CaptureMode = CaptureMode.OLD_CAPTURE; 72 private cameraManager: camera.CameraManager | undefined = undefined; 73 private cameras: Array<camera.CameraDevice> | undefined = undefined; 74 private sceneModes: Array<camera.SceneMode> | undefined = undefined; 75 private cameraOutputCapability: camera.CameraOutputCapability | undefined = undefined; 76 private cameraInput: camera.CameraInput | undefined = undefined; 77 private previewOutput: camera.PreviewOutput | undefined = undefined; 78 private photoOutPut: camera.PhotoOutput | undefined = undefined; 79 private photoSession: camera.PhotoSession | undefined = undefined; 80 private videoSession: camera.VideoSession | undefined = undefined; 81 private portraitSession: camera.PortraitPhotoSession | undefined = undefined; 82 private nightSession: camera.NightPhotoSession | undefined = undefined; 83 private mReceiver: image.ImageReceiver | undefined = undefined; 84 private fileAsset: photoAccessHelper.PhotoAsset | undefined = undefined; 85 private fd: number = -1; 86 private videoRecorder: media.AVRecorder | undefined = undefined; 87 private videoOutput: camera.VideoOutput | undefined = undefined; 88 private handleTakePicture: (photoUri: string) => void | undefined = undefined; 89 private videoConfig: media.AVRecorderConfig = { 90 audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, 91 videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, 92 profile: { 93 audioBitrate: 48000, 94 audioChannels: 2, 95 audioCodec: media.CodecMimeType.AUDIO_AAC, 96 audioSampleRate: 48000, 97 fileFormat: media.ContainerFormatType.CFT_MPEG_4, 98 videoBitrate: 512000, 99 videoCodec: media.CodecMimeType.VIDEO_AVC, 100 videoFrameWidth: 640, 101 videoFrameHeight: 480, 102 videoFrameRate: Constants.VIDEO_FRAME_30 103 }, 104 url: '', 105 rotation: 270 106 }; 107 private videoProfiles: Array<camera.VideoProfile>; 108 private videoProfileObj: camera.VideoProfile = { 109 format: 1003, 110 size: { 111 width: 1920, 112 height: 1080 113 }, 114 frameRateRange: { 115 min: Constants.VIDEO_FRAME_30, 116 max: Constants.VIDEO_FRAME_30 117 } 118 }; 119 private defaultProfile: camera.Profile = { 120 format: 1003, 121 size: { 122 width: 1920, 123 height: 1080 124 } 125 }; 126 private photoProfileObj: camera.Profile = { 127 format: 1003, 128 size: { 129 width: 1920, 130 height: 1080 131 } 132 }; 133 private previewProfileObj: camera.Profile = { 134 format: 1003, 135 size: { 136 width: 1920, 137 height: 1080 138 } 139 }; 140 private photoRotationMap = { 141 rotation0: 0, 142 rotation90: 90, 143 rotation180: 180, 144 rotation270: 270, 145 }; 146 private videoOutputStatus: boolean = false; 147 private colorEffect: camera.ColorEffectType | undefined = undefined; 148 private cameraMode: number = 0; 149 private accessHelper: photoAccessHelper.PhotoAccessHelper; 150 private globalContext: GlobalContext = GlobalContext.get(); 151 private isFirstRecord = true; 152 private isMoonCaptureBoostSupported: Boolean = false; 153 private depthDataOutput: camera.DepthDataOutput | undefined = undefined; 154 private depthProfiles: Array<camera.DepthProfile>; 155 private depthProfileObj: camera.Profile; 156 157 constructor() { 158 mockInterface(); 159 this.accessHelper = photoAccessHelper.getPhotoAccessHelper(this.globalContext.getCameraSettingContext()); 160 // image capacity 161 let imageCapacity = 8; 162 try { 163 this.mReceiver = image.createImageReceiver(cameraSize.width, cameraSize.height, image.ImageFormat.JPEG, imageCapacity); 164 Logger.debug(TAG, `createImageReceiver value: ${this.mReceiver}`); 165 // debug版本可能监听进不来 166 this.mReceiver.on('imageArrival', (): void => { 167 Logger.debug(TAG, 'imageArrival start'); 168 this.mReceiver.readNextImage((errCode: BusinessError, imageObj: image.Image): void => { 169 Logger.info(TAG, 'readNextImage start'); 170 Logger.info(TAG, `err: ${JSON.stringify(errCode)}`); 171 if (errCode || imageObj === undefined) { 172 Logger.error(TAG, 'readNextImage failed'); 173 return; 174 } 175 imageObj.getComponent(image.ComponentType.JPEG, (errCode: BusinessError, component: image.Component): void => { 176 Logger.debug(TAG, 'getComponent start'); 177 Logger.info(TAG, `err: ${JSON.stringify(errCode)}`); 178 if (errCode || component === undefined) { 179 Logger.info(TAG, 'getComponent failed'); 180 return; 181 } 182 let buffer: ArrayBuffer; 183 if (component.byteBuffer) { 184 buffer = component.byteBuffer; 185 } else { 186 Logger.error(TAG, 'component byteBuffer is undefined'); 187 } 188 this.savePicture(buffer, imageObj); 189 }); 190 }); 191 }); 192 } catch (error) { 193 let err = error as BusinessError; 194 Logger.error(TAG, `savePicture err: ${JSON.stringify(err)}`); 195 } 196 } 197 198 /** 199 * 读取图像 200 */ 201 async savePicture(buffer: ArrayBuffer, img: image.Image): Promise<void> { 202 try { 203 Logger.info(TAG, 'savePicture start'); 204 let fileName = `${Date.now()}.jpg`; 205 let fileAsset = await this.accessHelper.createAsset(fileName); 206 let imgPhotoUri: string = fileAsset.uri; 207 const fd = await fileAsset.open('rw'); 208 await fs.write(fd, buffer); 209 await fileAsset.close(fd); 210 await img.release(); 211 Logger.info(TAG, 'savePicture End'); 212 if (this.handleTakePicture) { 213 this.handleTakePicture(imgPhotoUri); 214 } 215 } catch (error) { 216 let err = error as BusinessError; 217 Logger.error(TAG, `savePicture err: ${JSON.stringify(err)}`); 218 } 219 } 220 221 /** 222 * 判断两浮点数是否相等 223 */ 224 withinErrorMargin(left: number, right: number): boolean { 225 // 底数 226 let baseNumber = 2; 227 // 指数 228 let indexNumber = 2; 229 return Math.abs(left - right) < Number.EPSILON * Math.pow(baseNumber, indexNumber); 230 } 231 232 switchProfiles(profiles: camera.CameraOutputCapability): void { 233 let previewProfiles: Array<camera.Profile> = profiles.previewProfiles; 234 let videoProfiles: Array<camera.Profile> = profiles.videoProfiles; 235 let photoProfiles: Array<camera.Profile> = profiles.photoProfiles; 236 let depthProfiles: Array<camera.Profile> = profiles.depthProfiles; 237 let isValidProfiles = true; 238 if (!previewProfiles || previewProfiles.length < 1) { 239 isValidProfiles = false; 240 } 241 if (isValidProfiles && (!photoProfiles || photoProfiles.length < 1)) { 242 isValidProfiles = false; 243 } 244 if (isValidProfiles && this.cameraMode !== CameraMode.PORTRAIT && (!videoProfiles || videoProfiles.length < 1)) { 245 isValidProfiles = false; 246 } 247 if (!isValidProfiles) { 248 Logger.error('Profile is invalid'); 249 return; 250 } 251 let defaultAspectRatio: number = AppStorage.get<number>('defaultAspectRatio'); 252 let previewProfileObj: camera.Profile; 253 let photoProfileObj: camera.Profile; 254 let depthProfileObj: camera.Profile; 255 if (!depthProfiles) { 256 depthProfileObj = depthProfiles[0]; 257 } 258 const deviceType = AppStorage.get<string>('deviceType'); 259 switch (this.cameraMode) { 260 case CameraMode.PORTRAIT: 261 previewProfileObj = previewProfiles.find((profile: camera.Profile) => { 262 return profile.size.height === this.defaultProfile.size.height && 263 profile.size.width === this.defaultProfile.size.width; 264 }); 265 Logger.info(`previewProfileObj: ${JSON.stringify(previewProfileObj)}`); 266 this.previewProfileObj = previewProfileObj; 267 photoProfileObj = photoProfiles.find((profile: camera.Profile) => { 268 return profile.size.height === this.defaultProfile.size.height && 269 profile.size.width === this.defaultProfile.size.width; 270 }); 271 Logger.info(`photoProfileObj: ${JSON.stringify(photoProfileObj)}`); 272 this.photoProfileObj = photoProfileObj; 273 break; 274 case CameraMode.SUPER_STAB: 275 previewProfileObj = previewProfiles.find((profile: camera.Profile) => { 276 return profile.size.height === this.defaultProfile.size.height && 277 profile.size.width === this.defaultProfile.size.width; 278 }); 279 Logger.info(`previewProfileObj: ${JSON.stringify(previewProfileObj)}`); 280 this.previewProfileObj = previewProfileObj; 281 photoProfileObj = photoProfiles.find((profile: camera.Profile) => { 282 return profile.size.height === this.defaultProfile.size.height && 283 profile.size.width === this.defaultProfile.size.width; 284 }); 285 Logger.info(`photoProfileObj: ${JSON.stringify(photoProfileObj)}`); 286 this.photoProfileObj = photoProfileObj; 287 this.videoProfileObj = { 288 format: 1003, 289 size: { 290 width: 1920, 291 height: 1080 292 }, 293 frameRateRange: { 294 min: 60, 295 max: 60 296 } 297 }; 298 let videoProfileObj = videoProfiles.find((profile: camera.VideoProfile) => { 299 return profile.size.height === this.videoProfileObj.size.height && 300 profile.size.width === this.videoProfileObj.size.width && 301 profile.frameRateRange.min === this.videoProfileObj.frameRateRange.min && 302 profile.frameRateRange.max === this.videoProfileObj.frameRateRange.max; 303 }); 304 Logger.info(`videoProfileObj: ${JSON.stringify(videoProfileObj)}`); 305 if (!videoProfileObj) { 306 Logger.error('videoProfileObj not supported'); 307 } 308 break; 309 case CameraMode.NIGHT: 310 previewProfileObj = previewProfiles.find((profile: camera.Profile) => { 311 return profile.size.height === this.defaultProfile.size.height && 312 profile.size.width === this.defaultProfile.size.width; 313 }); 314 Logger.info(`previewProfileObj: ${JSON.stringify(previewProfileObj)}`); 315 this.previewProfileObj = previewProfileObj; 316 photoProfileObj = photoProfiles.find((profile: camera.Profile) => { 317 return profile.size.height === this.defaultProfile.size.height && 318 profile.size.width === this.defaultProfile.size.width; 319 }); 320 Logger.info(`photoProfileObj: ${JSON.stringify(photoProfileObj)}`); 321 this.photoProfileObj = photoProfileObj; 322 break; 323 case CameraMode.NORMAL: 324 case CameraMode.VIDEO: 325 default: 326 for (let index = profiles.previewProfiles.length - 1; index >= 0; index--) { 327 const previewProfile = profiles.previewProfiles[index]; 328 if (this.withinErrorMargin(defaultAspectRatio, previewProfile.size.width / previewProfile.size.height)) { 329 if (previewProfile.size.width <= Constants.PHOTO_MAX_WIDTH && 330 previewProfile.size.height <= Constants.PHOTO_MAX_WIDTH) { 331 let previewProfileTemp = { 332 format: deviceType === Constants.DEFAULT ? previewProfile.format : this.defaultProfile.format, 333 size: { 334 width: previewProfile.size.width, 335 height: previewProfile.size.height 336 } 337 }; 338 this.previewProfileObj = previewProfileTemp; 339 Logger.debug(TAG, `previewProfileObj: ${JSON.stringify(this.previewProfileObj)}`); 340 break; 341 } 342 } 343 } 344 for (let index = profiles.videoProfiles.length - 1; index >= 0; index--){ 345 let videoProfile = profiles.videoProfiles[index]; 346 if (this.withinErrorMargin(defaultAspectRatio, videoProfile.size.width / videoProfile.size.height)) { 347 if (videoProfile.size.width <= Constants.PHOTO_MAX_WIDTH && 348 videoProfile.size.height <= Constants.PHOTO_MAX_WIDTH) { 349 this.videoProfileObj = videoProfile; 350 Logger.debug(TAG, `videoProfileObj: ${JSON.stringify(this.videoProfileObj)}`); 351 break; 352 } 353 } 354 } 355 for (let index = profiles.photoProfiles.length - 1; index >= 0; index--) { 356 const photoProfile = profiles.photoProfiles[index]; 357 if (this.withinErrorMargin(defaultAspectRatio, photoProfile.size.width / photoProfile.size.height)) { 358 if (photoProfile.size.width <= Constants.PHOTO_MAX_WIDTH && 359 photoProfile.size.height <= Constants.PHOTO_MAX_WIDTH) { 360 let photoProfileTemp = { 361 format: photoProfile.format, 362 size: { 363 width: photoProfile.size.width, 364 height: photoProfile.size.height 365 } 366 }; 367 this.photoProfileObj = photoProfileTemp; 368 Logger.debug(TAG, `photoProfileObj: ${JSON.stringify(this.photoProfileObj)}`); 369 break; 370 } 371 } 372 } 373 } 374 if (deviceType === Constants.DEFAULT) { 375 let cameraConfig = this.globalContext.getObject('cameraConfig') as CameraConfig; 376 for (let index = this.videoProfiles.length - 1; index >= 0; index--) { 377 const videoProfileObj = this.videoProfiles[index]; 378 if (this.withinErrorMargin(defaultAspectRatio, videoProfileObj.size.width / videoProfileObj.size.height)) { 379 if (videoProfileObj.size.width <= Constants.VIDEO_MAX_WIDTH && 380 videoProfileObj.size.height <= Constants.VIDEO_MAX_WIDTH) { 381 let videoProfileTemp = { 382 format: videoProfileObj.format, 383 size: { 384 width: videoProfileObj.size.width, 385 height: videoProfileObj.size.height 386 }, 387 frameRateRange: { 388 min: Constants.VIDEO_FRAME_30, 389 max: Constants.VIDEO_FRAME_30 390 } 391 }; 392 if ((cameraConfig.videoFrame === 0 ? Constants.VIDEO_FRAME_15 : Constants.VIDEO_FRAME_30) === 393 videoProfileObj.frameRateRange.min) { 394 videoProfileTemp.frameRateRange.min = videoProfileObj.frameRateRange.min; 395 videoProfileTemp.frameRateRange.max = videoProfileObj.frameRateRange.max; 396 this.videoProfileObj = videoProfileTemp; 397 Logger.info(TAG, `videoProfileObj: ${JSON.stringify(this.videoProfileObj)}`); 398 break; 399 } 400 Logger.info(TAG, `videoProfileTemp: ${JSON.stringify(videoProfileTemp)}`); 401 this.videoProfileObj = videoProfileTemp; 402 } 403 } 404 } 405 } 406 } 407 408 setCameraMode(cameraMode: number): void { 409 this.cameraMode = cameraMode; 410 } 411 412 initProfile(cameraDeviceIndex: number): void { 413 let profiles; 414 if (this.cameraMode === CameraMode.PORTRAIT) { 415 profiles = this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex], camera.SceneMode.PORTRAIT_PHOTO); 416 } else { 417 profiles = this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex]); 418 } 419 this.videoProfiles = profiles.videoProfiles; 420 this.switchProfiles(profiles); 421 } 422 423 /** 424 * 初始化 425 */ 426 async initCamera(surfaceId: string, cameraDeviceIndex: number): Promise<void> { 427 try { 428 this.isFirstRecord = true; 429 // 获取传入摄像头 430 Logger.debug(TAG, `initCamera cameraDeviceIndex: ${cameraDeviceIndex}`); 431 await this.releaseCamera(); 432 // 获取相机管理器实例 433 this.getCameraManagerFn(); 434 if (this.cameraMode === CameraMode.PORTRAIT || this.cameraMode === CameraMode.NIGHT) { 435 this.getModeManagerFn(); 436 } 437 // 获取支持指定的相机设备对象 438 this.getSupportedCamerasFn(); 439 if (this.cameraMode === CameraMode.PORTRAIT || this.cameraMode === CameraMode.NIGHT) { 440 this.getSupportedModeFn(cameraDeviceIndex); 441 } 442 this.initProfile(cameraDeviceIndex); 443 // 创建previewOutput输出对象 444 this.createPreviewOutputFn(this.previewProfileObj, surfaceId); 445 // 创建depthOutput输出对象 446 if (this.depthProfileObj) { 447 this.createDepthDataOutputFn(this.depthProfileObj); 448 } 449 // 监听预览事件 450 this.previewOutputCallBack(); 451 if (this.cameraMode === CameraMode.SUPER_STAB || this.cameraMode === CameraMode.VIDEO) { 452 await this.createAVRecorder(); 453 await this.createVideoOutput(); 454 // 监听录像事件 455 this.onVideoOutputChange(); 456 } 457 // 创建photoOutPut输出对象 458 let mSurfaceId = await this.mReceiver.getReceivingSurfaceId(); 459 this.createPhotoOutputFn(this.photoProfileObj, mSurfaceId); 460 // 拍照监听事件 461 this.photoOutPutCallBack(); 462 // 创建cameraInput输出对象 463 this.createCameraInputFn(this.cameras[cameraDeviceIndex]); 464 // 打开相机 465 await this.cameraInputOpenFn(); 466 // 镜头状态回调 467 this.onCameraStatusChange(); 468 // 监听CameraInput的错误事件 469 this.onCameraInputChange(); 470 // 会话流程 471 if (this.cameraMode === CameraMode.PORTRAIT) { 472 await this.portraitSessionFlowFn(); 473 } else if (this.cameraMode === CameraMode.NIGHT) { 474 await this.nightSessionFlowFn(); 475 } else if (this.cameraMode === CameraMode.VIDEO) { 476 await this.videoSessionFlowFn(); 477 } else { 478 await this.photoSessionFlowFn(); 479 } 480 } catch (error) { 481 let err = error as BusinessError; 482 Logger.error(TAG, `initCamera fail: ${JSON.stringify(err)}`); 483 } 484 } 485 486 isVideoFrameSupportedFn(videoFrame: number): boolean { 487 let videoProfile: camera.VideoProfile | undefined = this.videoProfiles.find((videoProfile: camera.VideoProfile) => { 488 return videoProfile.size.height === this.videoProfileObj.size.height && 489 videoProfile.size.width === this.videoProfileObj.size.width && 490 videoProfile.format === this.videoProfileObj.format && 491 videoProfile.frameRateRange.min === videoFrame && 492 videoProfile.frameRateRange.max === videoFrame; 493 }); 494 return videoProfile === undefined ? false : true; 495 } 496 497 /** 498 * 是否支持摄像头切换 499 */ 500 isCameraSwitchSupportedFn(): boolean { 501 return this.cameraManager.getSupportedCameras().length > 1; 502 } 503 504 /** 505 * 曝光 506 */ 507 isExposureModeSupportedFn(aeMode: camera.ExposureMode): boolean { 508 // 检测曝光模式是否支持 509 let isSupported: boolean = false; 510 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 511 if (!session) { 512 return isSupported; 513 } 514 isSupported = session.isExposureModeSupported(aeMode); 515 Logger.info(TAG, `isExposureModeSupported success, isSupported: ${isSupported}`); 516 return isSupported; 517 } 518 519 setExposureMode(aeMode: camera.ExposureMode): void { 520 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 521 if (!session) { 522 return; 523 } 524 session.setExposureMode(aeMode); 525 let exposureMode: camera.ExposureMode | undefined = undefined; 526 exposureMode = session.getExposureMode(); 527 Logger.info(TAG, `getExposureMode success, exposureMode: ${exposureMode}`); 528 } 529 530 /** 531 * 曝光区域 532 */ 533 isMeteringPoint(point: camera.Point): void { 534 // 获取当前曝光模式 535 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 536 if (!session) { 537 return; 538 } 539 let exposureMode: camera.ExposureMode | undefined = undefined; 540 exposureMode = session.getExposureMode(); 541 Logger.info(TAG, `getExposureMode success, exposureMode: ${exposureMode}`); 542 session.setMeteringPoint(point); 543 let exposurePoint: camera.Point | undefined = undefined; 544 exposurePoint = session.getMeteringPoint(); 545 Logger.info(TAG, `getMeteringPoint exposurePoint: ${JSON.stringify(exposurePoint)}`); 546 } 547 548 /** 549 * 曝光补偿 550 */ 551 isExposureBiasRange(exposureBias: number): void { 552 Logger.debug(TAG, `setExposureBias value ${exposureBias}`); 553 // 查询曝光补偿范围 554 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 555 if (!session) { 556 return; 557 } 558 let biasRangeArray: Array<number> = []; 559 biasRangeArray = session.getExposureBiasRange(); 560 Logger.debug(TAG, `getExposureBiasRange success, biasRangeArray: ${JSON.stringify(biasRangeArray)}`); 561 // 设置曝光补偿 562 session.setExposureBias(exposureBias); 563 } 564 565 /** 566 * 是否支持对应对焦模式 567 */ 568 isFocusModeSupported(focusMode: camera.FocusMode): boolean { 569 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 570 if (!session) { 571 return false; 572 } 573 return session.isFocusModeSupported(focusMode); 574 } 575 576 /** 577 * 对焦模式 578 */ 579 isFocusMode(focusMode: camera.FocusMode): void { 580 // 检测对焦模式是否支持 581 let isSupported = this.isFocusModeSupported(focusMode); 582 Logger.info(TAG, `isFocusModeSupported isSupported: ${JSON.stringify(isSupported)}`); 583 // 设置对焦模式 584 if (!isSupported) { 585 return; 586 } 587 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 588 if (!session) { 589 return; 590 } 591 session.setFocusMode(focusMode); 592 } 593 594 /** 595 * 焦点 596 */ 597 isFocusPoint(point: camera.Point): void { 598 // 设置焦点 599 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 600 if (!session) { 601 return; 602 } 603 session.setFocusPoint(point); 604 Logger.info(TAG, 'setFocusPoint success'); 605 // 获取当前的焦点 606 let nowPoint: camera.Point | undefined = undefined; 607 nowPoint = session.getFocusPoint(); 608 Logger.info(TAG, `getFocusPoint success, nowPoint: ${JSON.stringify(nowPoint)}`); 609 } 610 611 /** 612 * 闪关灯 613 */ 614 hasFlashFn(flashMode: camera.FlashMode): void { 615 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 616 if (!session) { 617 return; 618 } 619 // 检测是否有闪关灯 620 let hasFlash = session.hasFlash(); 621 Logger.debug(TAG, `hasFlash success, hasFlash: ${hasFlash}`); 622 // 检测闪光灯模式是否支持 623 let isFlashModeSupported = session.isFlashModeSupported(flashMode); 624 Logger.debug(TAG, `isFlashModeSupported success, isFlashModeSupported: ${isFlashModeSupported}`); 625 // 设置闪光灯模式 626 session.setFlashMode(flashMode); 627 // 获取当前设备的闪光灯模式 628 let nowFlashMode = session.getFlashMode(); 629 Logger.debug(TAG, `getFlashMode success, nowFlashMode: ${nowFlashMode}`); 630 } 631 632 getSession(): camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession | undefined { 633 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = undefined; 634 if (this.cameraMode === CameraMode.PORTRAIT) { 635 session = this.portraitSession; 636 } else if (this.cameraMode === CameraMode.NIGHT) { 637 session = this.nightSession; 638 } else if (this.cameraMode === CameraMode.VIDEO) { 639 session = this.videoSession; 640 } else { 641 session = this.photoSession; 642 } 643 return session; 644 } 645 646 isSupportZoom() { 647 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 648 let zoomRatioRange = session.getZoomRatioRange(); 649 return zoomRatioRange != undefined; 650 } 651 652 /** 653 * 变焦 654 */ 655 setZoomRatioFn(zoomRatio: number): void { 656 Logger.info(TAG, `setZoomRatioFn value ${zoomRatio}`); 657 // 获取支持的变焦范围 658 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 659 if (!session) { 660 return; 661 } 662 try { 663 let zoomRatioRange = session.getZoomRatioRange(); 664 Logger.info(TAG, `getZoomRatioRange success: ${JSON.stringify(zoomRatioRange)}`); 665 } catch (error) { 666 let err = error as BusinessError; 667 Logger.error(TAG, `getZoomRatioRange fail: ${JSON.stringify(err)}`); 668 } 669 670 try { 671 session.setZoomRatio(zoomRatio); 672 Logger.info(TAG, 'setZoomRatioFn success'); 673 } catch (error) { 674 let err = error as BusinessError; 675 Logger.error(TAG, `setZoomRatioFn fail: ${JSON.stringify(err)}`); 676 } 677 678 try { 679 let nowZoomRatio = session.getZoomRatio(); 680 Logger.info(TAG, `getZoomRatio nowZoomRatio: ${JSON.stringify(nowZoomRatio)}`); 681 } catch (error) { 682 let err = error as BusinessError; 683 Logger.error(TAG, `getZoomRatio fail: ${JSON.stringify(err)}`); 684 } 685 } 686 687 /** 688 * 防抖 689 */ 690 isVideoStabilizationModeSupportedFn(videoStabilizationMode: camera.VideoStabilizationMode): boolean { 691 // 查询是否支持指定的视频防抖模式 692 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 693 let isVideoStabilizationModeSupported: boolean = session.isVideoStabilizationModeSupported(videoStabilizationMode); 694 Logger.info(TAG, `isVideoStabilizationModeSupported success: ${JSON.stringify(isVideoStabilizationModeSupported)}`); 695 return isVideoStabilizationModeSupported; 696 } 697 698 setVideoStabilizationMode(videoStabilizationMode: camera.VideoStabilizationMode): void { 699 // 设置视频防抖 700 Logger.info(TAG, `setVideoStabilizationMode: ${videoStabilizationMode}`); 701 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 702 session.setVideoStabilizationMode(videoStabilizationMode); 703 let nowVideoStabilizationMod: camera.VideoStabilizationMode = session.getActiveVideoStabilizationMode(); 704 Logger.info(TAG, `getActiveVideoStabilizationMode nowVideoStabilizationMod: ${nowVideoStabilizationMod}`); 705 } 706 707 /** 708 * 是否支持夜景模式 709 */ 710 isNightModeSupportedFn(): boolean { 711 let isSupportNightMode: boolean = this.sceneModes.indexOf(CameraMode.NIGHT) >= 0; 712 Logger.info(TAG, `isSupportNightMode success: ${JSON.stringify(isSupportNightMode)}`); 713 return isSupportNightMode; 714 } 715 716 /** 717 * 是否支持人像模式 718 */ 719 isPortraitModeSupportedFn(): boolean { 720 let isSupportPortraitMode: boolean = this.sceneModes.indexOf(CameraMode.PORTRAIT) >= 0; 721 Logger.info(TAG, `isSupportPortraitMode success: ${JSON.stringify(isSupportPortraitMode)}`); 722 return isSupportPortraitMode; 723 } 724 725 /** 726 * 是否支持镜像 727 */ 728 isMirrorSupportedFn(): void { 729 let isSupported = this.photoOutPut.isMirrorSupported(); 730 Logger.info(TAG, `isMirrorSupported success Bol: ${JSON.stringify(isSupported)}`); 731 } 732 733 setTakePictureCallback(callback: (photoUri: string) => void): void { 734 this.handleTakePicture = callback; 735 } 736 737 /** 738 * 照片方向判断 739 */ 740 onChangeRotation(): number { 741 let cameraConfig = (this.globalContext.getObject('cameraConfig') as CameraConfig); 742 switch (cameraConfig.photoOrientation) { 743 case PhotoOrientation.ORIENTATION_1: 744 return this.photoRotationMap.rotation90; 745 case PhotoOrientation.ORIENTATION_2: 746 return this.photoRotationMap.rotation180; 747 case PhotoOrientation.ORIENTATION_3: 748 return this.photoRotationMap.rotation270; 749 case PhotoOrientation.ORIENTATION_0: 750 default: 751 return this.photoRotationMap.rotation0; 752 } 753 } 754 755 /** 756 * 照片地理位置逻辑 ,后续需要靠定位实现 目前传入固定值 757 */ 758 onChangeLocation(): { 759 latitude: number, 760 longitude: number, 761 altitude: number 762 } { 763 let cameraConfig = (this.globalContext.getObject('cameraConfig') as CameraConfig); 764 if (cameraConfig.locationBol) { 765 return { 766 // 位置信息,经纬度 767 latitude: 12.9698, 768 longitude: 77.7500, 769 altitude: 1000 770 }; 771 } 772 return { 773 latitude: 0, 774 longitude: 0, 775 altitude: 0 776 }; 777 } 778 779 /** 780 * 拍照 781 */ 782 async takePicture(mirrorBol?: boolean): Promise<void> { 783 Logger.info(TAG, 'takePicture start'); 784 mirrorBol = mirrorBol || false; 785 this.isMirrorSupportedFn(); 786 let cameraConfig = (this.globalContext.getObject('cameraConfig') as CameraConfig); 787 let photoSettings = { 788 rotation: this.onChangeRotation(), 789 quality: cameraConfig.photoQuality, 790 location: this.onChangeLocation(), 791 mirror: cameraConfig.mirrorBol 792 }; 793 Logger.debug(TAG, `takePicture photoSettings:${JSON.stringify(photoSettings)}`); 794 await this.photoOutPut.capture(photoSettings); 795 Logger.info(TAG, 'takePicture end'); 796 } 797 798 /** 799 * 开启深度流 800 */ 801 async startDepthDataOutput(depthDataOutput: camera.DepthDataOutput): Promise<void> { 802 Logger.info(TAG, 'startDepthDataOutput'); 803 if (!depthDataOutput) { 804 Logger.error(TAG, 'depthDataOutput Undefined'); 805 return; 806 } 807 try { 808 await depthDataOutput.start(); 809 } catch (err) { 810 const error = err as BusinessError; 811 Logger.error(TAG, `depthDataOutputStart error:${error.code};${error.message}`); 812 } 813 } 814 815 /** 816 * 停止深度流 817 */ 818 async stopDepthDataOutput(depthDataOutput: camera.DepthDataOutput): Promise<void> { 819 Logger.info(TAG, 'stopDepthDataOutput'); 820 if (!depthDataOutput) { 821 Logger.error(TAG, 'depthDataOutput Undefined'); 822 return; 823 } 824 try { 825 await depthDataOutput.stop(); 826 } catch (err) { 827 const error = err as BusinessError; 828 Logger.error(TAG, `depthDataOutputStop error:${error.code};${error.message}`); 829 } 830 } 831 832 /** 833 * 接收深度数据 834 */ 835 depthDataOutputOnDataAvailable(depthDataOutput: camera.DepthDataOutput, 836 callback?: (err: BusinessError, data: camera.DepthData) => void): void { 837 Logger.info(TAG, 'depthDataOutputOnDataAvailable'); 838 if (!depthDataOutput) { 839 Logger.error(TAG, 'depthDataOutput Undefined'); 840 return; 841 } 842 depthDataOutput.on('depthDataAvailable', (err: BusinessError, data: camera.DepthData) => { 843 callback?.(err, data); 844 // 获取到的深度图数据处理后,需要将对应的图像Buffer释放 845 this.releaseDepthData(data); 846 }); 847 } 848 849 /** 850 * 释放深度图数据 851 */ 852 releaseDepthData(depthData: camera.DepthData): void { 853 if (!depthData) { 854 Logger.error(TAG, 'depthData Undefined'); 855 return; 856 } 857 try { 858 if (!depthData.depthMap) { 859 Logger.error(TAG, 'depthMap Undefined'); 860 } 861 depthData.release(); 862 } catch (err) { 863 const error = err as BusinessError; 864 Logger.error(TAG, `releaseDepthData error:${error.code};${error.message}`); 865 } 866 } 867 868 /** 869 * 监听深度输出流事件回调 870 */ 871 depthDataOutputOnEvent(depthDataOutput: camera.DepthDataOutput, 872 errCallback?: (err: BusinessError) => void): void { 873 Logger.info(TAG, 'depthDataOutputOnEvent'); 874 if (!depthDataOutput) { 875 Logger.error(TAG, 'depthDataOutput Undefined'); 876 return; 877 } 878 depthDataOutput.on('error', (err: BusinessError) => { 879 Logger.error(TAG, 'depthDataOutput error'); 880 errCallback?.(err); 881 }); 882 } 883 884 /** 885 * 取消监听深度输出流事件回调 886 */ 887 depthDataOutputOffEvent(depthDataOutput: camera.DepthDataOutput): void { 888 Logger.info(TAG, 'depthDataOutputOffEvent'); 889 if (!depthDataOutput) { 890 Logger.error(TAG, 'depthDataOutput Undefined'); 891 return; 892 } 893 depthDataOutput.off('depthDataAvailable'); 894 depthDataOutput.off('error'); 895 } 896 897 async prepareAVRecorder(): Promise<void> { 898 await this.initUrl(); 899 let deviceType = AppStorage.get<string>('deviceType'); 900 if (deviceType === Constants.DEFAULT) { 901 this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_ES; 902 } 903 if (deviceType === Constants.PHONE) { 904 this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV; 905 this.videoConfig.profile.videoCodec = media.CodecMimeType.VIDEO_AVC; 906 this.videoConfig.rotation = this.photoRotationMap.rotation90; 907 } 908 if (deviceType === Constants.TABLET) { 909 this.videoConfig.videoSourceType = media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV; 910 } 911 this.videoConfig.profile.videoFrameWidth = this.videoProfileObj.size.width; 912 this.videoConfig.profile.videoFrameHeight = this.videoProfileObj.size.height; 913 this.videoConfig.profile.videoFrameRate = this.videoProfileObj.frameRateRange.max; 914 Logger.info(TAG, `prepareAVRecorder deviceType: ${deviceType}, videoSourceType: ${JSON.stringify(this.videoConfig)}`); 915 await this.videoRecorder.prepare(this.videoConfig).catch((err: { code?: number }): void => { 916 Logger.error(TAG, `prepareAVRecorder prepare err: ${JSON.stringify(err)}`); 917 }); 918 } 919 920 async getAVRecorderSurfaceId(): Promise<string> { 921 return await this.videoRecorder.getInputSurface(); 922 } 923 924 async createAVRecorder(): Promise<void> { 925 this.videoRecorder = await media.createAVRecorder(); 926 } 927 928 /** 929 * 配置videoOutput流 930 */ 931 async createVideoOutput(): Promise<void> { 932 Logger.info(TAG, 'createVideoOutput start'); 933 await this.prepareAVRecorder(); 934 let videoId = await this.getAVRecorderSurfaceId(); 935 Logger.debug(TAG, `createVideoOutput videoProfileObj: ${JSON.stringify(this.videoProfileObj)}`); 936 this.videoOutput = this.cameraManager.createVideoOutput(this.videoProfileObj, videoId); 937 Logger.info(TAG, 'createVideoOutput end'); 938 } 939 940 /** 941 * 暂停录制 942 */ 943 async pauseVideo(): Promise<void> { 944 await this.videoRecorder.pause().then((): void => { 945 this.videoOutput.stop(); 946 this.videoOutputStatus = false; 947 Logger.info(TAG, 'pauseVideo success'); 948 }).catch((err: BusinessError): void => { 949 Logger.error(TAG, `pauseVideo failed: ${JSON.stringify(err)}`); 950 }); 951 } 952 953 /** 954 * 恢复视频录制 955 */ 956 async resumeVideo(): Promise<void> { 957 this.videoOutput.start().then((): void => { 958 this.videoOutputStatus = true; 959 Logger.info(TAG, 'resumeVideo start'); 960 this.videoRecorder.resume().then((): void => { 961 Logger.info(TAG, 'resumeVideo success'); 962 }).catch((err: { code?: number }): void => { 963 Logger.error(TAG, `resumeVideo failed: ${JSON.stringify(err)}`); 964 }); 965 }); 966 } 967 968 /** 969 * 初始化录制适配地址 970 */ 971 async initUrl(): Promise<void> { 972 let fileName = `${Date.now()}.mp4`; 973 this.fileAsset = await this.accessHelper.createAsset(fileName); 974 this.fd = await this.fileAsset.open('rw'); 975 this.videoConfig.url = `fd://${this.fd.toString()}`; 976 } 977 978 /** 979 * 开始录制 980 */ 981 async startVideo(): Promise<void> { 982 try { 983 Logger.info(TAG, 'startVideo begin'); 984 await this.videoOutput.start(); 985 this.videoOutputStatus = true; 986 if (!this.isFirstRecord) { 987 await this.prepareAVRecorder(); 988 await this.getAVRecorderSurfaceId(); 989 } 990 await this.videoRecorder.start(); 991 this.isFirstRecord = false; 992 AppStorage.setOrCreate<boolean>('isRecorder', true); 993 Logger.info(TAG, 'startVideo end'); 994 } catch (error) { 995 let err = error as BusinessError; 996 Logger.error(TAG, `startVideo err: ${JSON.stringify(err)}`); 997 } 998 } 999 1000 async releaseVideoRecorder(): Promise<void> { 1001 if (this.videoRecorder) { 1002 try { 1003 await this.videoRecorder.release(); 1004 this.videoOutputStatus = false; 1005 AppStorage.setOrCreate<boolean>('isRecorder', false); 1006 } catch (error) { 1007 let err = error as BusinessError; 1008 Logger.error(TAG, 'stopVideo err: ' + JSON.stringify(err)); 1009 } 1010 } 1011 } 1012 1013 /** 1014 * 停止录制 1015 */ 1016 async stopVideo(): Promise<photoAccessHelper.PhotoAsset> { 1017 let isRecorder: boolean = AppStorage.get<boolean>('isRecorder'); 1018 if (!isRecorder) { 1019 Logger.info(TAG, 'not in recording'); 1020 return undefined; 1021 } 1022 try { 1023 Logger.info(TAG, 'stopVideo start'); 1024 AppStorage.setOrCreate<boolean>('isRecorder', false); 1025 if (this.videoRecorder) { 1026 await this.videoRecorder.stop(); 1027 } 1028 if (this.videoOutputStatus) { 1029 await this.videoOutput.stop(); 1030 this.videoOutputStatus = false; 1031 } 1032 if (this.fileAsset) { 1033 await this.fileAsset.close(this.fd); 1034 return this.fileAsset; 1035 } 1036 return undefined; 1037 } catch (error) { 1038 let err = error as BusinessError; 1039 Logger.error(TAG, 'stopVideo err: ' + JSON.stringify(err)); 1040 return undefined; 1041 } 1042 } 1043 1044 /** 1045 * 释放会话及其相关参数 1046 */ 1047 async releaseCamera(): Promise<void> { 1048 Logger.info(TAG, 'releaseCamera is called'); 1049 await this.stopVideo(); 1050 await this.releaseVideoRecorder(); 1051 if (this.previewOutput) { 1052 try { 1053 await this.previewOutput.stop(); 1054 await this.previewOutput.release(); 1055 } catch (error) { 1056 let err = error as BusinessError; 1057 Logger.error(TAG, `previewOutput release fail: error: ${JSON.stringify(err)}`); 1058 } finally { 1059 this.previewOutput = null; 1060 } 1061 1062 } 1063 if (this.photoOutPut) { 1064 try { 1065 await this.photoOutPut.release(); 1066 } catch (error) { 1067 let err = error as BusinessError; 1068 Logger.error(TAG, `photoOutPut release fail: error: ${JSON.stringify(err)}`); 1069 } finally { 1070 this.photoOutPut = null; 1071 } 1072 } 1073 if (this.videoOutput) { 1074 try { 1075 await this.videoOutput.release(); 1076 } catch (error) { 1077 let err = error as BusinessError; 1078 Logger.error(TAG, `videoOutput release fail: error: ${JSON.stringify(err)}`); 1079 } finally { 1080 this.videoOutput = null; 1081 } 1082 } 1083 if (this.portraitSession) { 1084 try { 1085 await this.portraitSession.release(); 1086 } catch (error) { 1087 let err = error as BusinessError; 1088 Logger.error(TAG, `portraitSession release fail: error: ${JSON.stringify(err)}`); 1089 } finally { 1090 this.portraitSession = null; 1091 } 1092 } 1093 if (this.nightSession) { 1094 try { 1095 await this.nightSession.release(); 1096 } catch (error) { 1097 let err = error as BusinessError; 1098 Logger.error(TAG, `nightSession release fail: error: ${JSON.stringify(err)}`); 1099 } finally { 1100 this.nightSession = null; 1101 } 1102 } 1103 if (this.photoSession) { 1104 try { 1105 await this.photoSession.release(); 1106 } catch (error) { 1107 let err = error as BusinessError; 1108 Logger.error(TAG, `photoSession release fail: error: ${JSON.stringify(err)}`); 1109 } finally { 1110 this.photoSession = null; 1111 } 1112 } 1113 if (this.videoSession) { 1114 try { 1115 await this.videoSession.release(); 1116 } catch (error) { 1117 let err = error as BusinessError; 1118 Logger.error(TAG, `videoSession release fail: error: ${JSON.stringify(err)}`); 1119 } finally { 1120 this.videoSession = null; 1121 } 1122 } 1123 if (this.cameraInput) { 1124 try { 1125 await this.cameraInput.close(); 1126 } catch (error) { 1127 let err = error as BusinessError; 1128 Logger.error(TAG, `cameraInput close fail: error: ${JSON.stringify(err)}`); 1129 } finally { 1130 this.cameraInput = null; 1131 } 1132 } 1133 Logger.info(TAG, 'releaseCamera success'); 1134 } 1135 1136 /** 1137 * 获取相机管理器实例 1138 */ 1139 getCameraManagerFn(): void { 1140 if (this.cameraManager) { 1141 return; 1142 } 1143 try { 1144 this.cameraManager = camera.getCameraManager(GlobalContext.get().getCameraSettingContext()); 1145 Logger.info(TAG, `getCameraManager success: ${this.cameraManager}`); 1146 } catch (error) { 1147 let err = error as BusinessError; 1148 Logger.error(TAG, `getCameraManager failed: ${JSON.stringify(err)}`); 1149 } 1150 } 1151 1152 getModeManagerFn(): void { 1153 try { 1154 this.cameraManager = camera.getCameraManager(GlobalContext.get().getCameraSettingContext()); 1155 Logger.info(TAG, `getModeManagerFn success: ${this.cameraManager}`); 1156 } catch (error) { 1157 let err = error as BusinessError; 1158 Logger.error(TAG, `getModeManagerFn failed: ${JSON.stringify(err)}`); 1159 } 1160 } 1161 1162 /** 1163 * 获取支持指定的相机设备对象 1164 */ 1165 getSupportedCamerasFn(): void { 1166 try { 1167 this.cameras = this.cameraManager.getSupportedCameras(); 1168 Logger.info(TAG, `getSupportedCameras success: ${this.cameras}, length: ${this.cameras.length}`); 1169 } catch (error) { 1170 let err = error as BusinessError; 1171 Logger.error(TAG, `getSupportedCameras failed: ${JSON.stringify(err)}`); 1172 } 1173 } 1174 1175 getSupportedModeFn(cameraIndex: number): void { 1176 try { 1177 this.sceneModes = this.cameraManager.getSupportedSceneModes(this.cameras[cameraIndex]); 1178 Logger.info(TAG, `getSupportedModeFn success: ${this.sceneModes}, length: ${this.sceneModes.length}`); 1179 } catch (error) { 1180 let err = error as BusinessError; 1181 Logger.error(TAG, `getSupportedModeFn failed: ${JSON.stringify(err)}`); 1182 } 1183 } 1184 1185 /** 1186 * 查询相机设备在模式下支持的输出能力 1187 */ 1188 async getSupportedOutputCapabilityFn(cameraDeviceIndex: number): Promise<void> { 1189 this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(this.cameras[cameraDeviceIndex]); 1190 } 1191 1192 /** 1193 * 创建previewOutput输出对象 1194 */ 1195 createPreviewOutputFn(photoProfileObj: camera.Profile, surfaceId: string): void { 1196 try { 1197 this.previewOutput = this.cameraManager.createPreviewOutput(photoProfileObj, surfaceId); 1198 Logger.info(TAG, `createPreviewOutput success: ${this.previewOutput}`); 1199 } catch (error) { 1200 let err = error as BusinessError; 1201 Logger.error(TAG, `createPreviewOutput failed: ${JSON.stringify(err)}`); 1202 } 1203 } 1204 1205 /** 1206 * 创建photoOutPut输出对象 1207 */ 1208 createPhotoOutputFn(photoProfileObj: camera.Profile, surfaceId: string): void { 1209 Logger.info(TAG, `createPhotoOutputFn photoProfiles: ${JSON.stringify(photoProfileObj)} ,captureMode: ${this.captureMode}, surfaceId: ${surfaceId}`); 1210 switch (this.captureMode) { 1211 case CaptureMode.OLD_CAPTURE: 1212 this.photoOutPut = this.cameraManager.createPhotoOutput(photoProfileObj, surfaceId); 1213 break; 1214 case CaptureMode.NEW_CAPTURE: 1215 case CaptureMode.NEW_DEFERRED_PHOTO: 1216 this.photoOutPut = this.cameraManager.createPhotoOutput(photoProfileObj); 1217 if (this.photoOutPut == null) { 1218 Logger.error(TAG, 'createPhotoOutputFn createPhotoOutput failed'); 1219 } 1220 break; 1221 } 1222 } 1223 1224 /** 1225 * 创建depthDataOutput输出对象 1226 */ 1227 createDepthDataOutputFn(depthProfileObj: camera.Profile): void { 1228 try { 1229 this.depthDataOutput = this.cameraManager.createDepthDataOutput(depthProfileObj); 1230 Logger.info(TAG, `createDepthDataOutput success: ${this.depthDataOutput}`); 1231 } catch (error) { 1232 let err = error as BusinessError; 1233 Logger.error(TAG, `createDepthDataOutput failed: ${JSON.stringify(err)}`); 1234 } 1235 } 1236 1237 /** 1238 * 创建cameraInput输出对象 1239 */ 1240 createCameraInputFn(cameraDevice: camera.CameraDevice): void { 1241 Logger.info(TAG, 'createCameraInputFn is called.'); 1242 try { 1243 this.cameraInput = this.cameraManager.createCameraInput(cameraDevice); 1244 } catch (err) { 1245 1246 } 1247 } 1248 1249 /** 1250 * 打开相机 1251 */ 1252 async cameraInputOpenFn(): Promise<void> { 1253 try { 1254 await this.cameraInput.open(); 1255 Logger.info(TAG, 'cameraInput open success'); 1256 } catch (error) { 1257 let err = error as BusinessError; 1258 Logger.error(TAG, `createCameraInput failed : ${JSON.stringify(err)}`); 1259 } 1260 } 1261 1262 /** 1263 * 处理望月信息 1264 */ 1265 configMoonCaptureBoost(): void { 1266 try { 1267 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1268 this.isMoonCaptureBoostSupported = 1269 session.isSceneFeatureSupported(camera.SceneFeatureType.MOON_CAPTURE_BOOST); 1270 if (this.isMoonCaptureBoostSupported) { 1271 session.on('featureDetectionStatus', camera.SceneFeatureType.MOON_CAPTURE_BOOST, 1272 (error, statusObject) => { 1273 Logger.info(TAG, 1274 `on featureDetectionStatus featureType:${statusObject.featureType} detected:${statusObject.detected}`); 1275 if (statusObject.featureType === camera.SceneFeatureType.MOON_CAPTURE_BOOST) { 1276 let status = statusObject.detected; 1277 Logger.info(TAG, `on moonCaptureBoostStatus change:${status}`); 1278 AppStorage.setOrCreate('moonCaptureComponentIsShow', status); 1279 if (!status) { 1280 this.setMoonCaptureBoostEnable(status); 1281 } 1282 } 1283 }); 1284 } 1285 } catch (error) { 1286 let err = error as BusinessError; 1287 Logger.error(TAG, `isMoonCaptureBoostSupported fail: error code ${err.code}`); 1288 } 1289 } 1290 1291 /** 1292 * 拍照会话流程 1293 */ 1294 async photoSessionFlowFn(): Promise<void> { 1295 try { 1296 Logger.info(TAG, "photoSessionFlowFn start"); 1297 // 创建PhotoSession实例 1298 this.photoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO); 1299 // 监听焦距的状态变化 1300 this.onFocusStateChange(); 1301 // 监听拍照会话的错误事件 1302 this.onCaptureSessionErrorChange(); 1303 // 开始配置会话 1304 this.photoSession.beginConfig(); 1305 // 把CameraInput加入到会话 1306 this.photoSession.addInput(this.cameraInput); 1307 // 把previewOutput加入到会话 1308 this.photoSession.addOutput(this.previewOutput); 1309 // 把photoOutPut加入到会话 1310 this.photoSession.addOutput(this.photoOutPut); 1311 // 把depthDataOutput加入到会话 1312 if (this.depthDataOutput) { 1313 this.photoSession.addOutput(this.depthDataOutput); 1314 } 1315 // hdr 拍照 1316 let hdrPhotoBol: boolean = (this.globalContext.getObject('cameraConfig') as CameraConfig).hdrPhotoBol; 1317 Logger.info(TAG, "hdrPhotoBol:" + hdrPhotoBol); 1318 if (hdrPhotoBol) { 1319 this.setColorSpace(this.photoSession, colorSpaceManager.ColorSpace.DISPLAY_P3); 1320 } else { 1321 this.setColorSpace(this.photoSession, colorSpaceManager.ColorSpace.SRGB); 1322 } 1323 // 提交配置信息 1324 await this.photoSession.commitConfig(); 1325 // 开始会话工作 1326 await this.photoSession.start(); 1327 } catch (error) { 1328 let err = error as BusinessError; 1329 Logger.error(TAG, `photoSessionFlowFn fail : ${JSON.stringify(err)}`); 1330 } 1331 } 1332 1333 /** 1334 * 录像会话流程 1335 */ 1336 async videoSessionFlowFn(): Promise<void> { 1337 try { 1338 Logger.info(TAG, "videoSessionFlowFn start"); 1339 // 创建VideoSession实例 1340 this.videoSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO); 1341 // 监听焦距的状态变化 1342 this.onFocusStateChange(); 1343 // 监听拍照会话的错误事件 1344 this.onCaptureSessionErrorChange(); 1345 // 开始配置会话 1346 this.videoSession.beginConfig(); 1347 // 把CameraInput加入到会话 1348 this.videoSession.addInput(this.cameraInput); 1349 // 把previewOutput加入到会话 1350 this.videoSession.addOutput(this.previewOutput); 1351 // 把photoOutPut加入到会话 1352 this.videoSession.addOutput(this.videoOutput); 1353 // 提交配置信息 1354 await this.videoSession.commitConfig(); 1355 // hdr 录像 1356 let hdrVideoBol: boolean = (this.globalContext.getObject('cameraConfig') as CameraConfig).hdrVideoBol; 1357 Logger.info(TAG, "hdrVideoBol:" + hdrVideoBol); 1358 if (hdrVideoBol) { 1359 this.setColorSpace(this.videoSession, colorSpaceManager.ColorSpace.BT2020_HLG); 1360 } else { 1361 this.setColorSpace(this.videoSession, colorSpaceManager.ColorSpace.BT709); 1362 } 1363 // 开始会话工作 1364 await this.videoSession.start(); 1365 } catch (error) { 1366 let err = error as BusinessError; 1367 Logger.error(TAG, `videoSessionFlowFn fail : ${JSON.stringify(err)}`); 1368 } 1369 } 1370 1371 async portraitSessionFlowFn(sceneModeIndex?: number): Promise<void> { 1372 try { 1373 // 创建PortraitSession实例 1374 this.portraitSession = this.cameraManager.createSession(camera.SceneMode.PORTRAIT_PHOTO); 1375 // 监听焦距的状态变化 1376 this.onFocusStateChange(); 1377 // 监听拍照会话的错误事件 1378 this.onCaptureSessionErrorChange(); 1379 // 开始配置会话 1380 this.portraitSession.beginConfig(); 1381 // 把CameraInput加入到会话 1382 this.portraitSession.addInput(this.cameraInput); 1383 // 把previewOutput加入到会话 1384 this.portraitSession.addOutput(this.previewOutput); 1385 // 把photoOutPut加入到会话 1386 this.portraitSession.addOutput(this.photoOutPut); 1387 if (this.captureMode === CaptureMode.NEW_DEFERRED_PHOTO) { 1388 if (this.isDeferredImageDeliverySupported(camera.DeferredDeliveryImageType.PHOTO)) { 1389 this.deferImageDeliveryFor(camera.DeferredDeliveryImageType.PHOTO); 1390 this.isDeferredImageDeliveryEnabled(camera.DeferredDeliveryImageType.PHOTO); 1391 } 1392 } 1393 1394 // 提交配置信息 1395 await this.portraitSession.commitConfig(); 1396 1397 // 处理变焦条信息 1398 try { 1399 let range: Array<number> = this.portraitSession.getZoomRatioRange(); 1400 Logger.info(TAG, `getZoomRatioRange:${range}`); 1401 if (range) { 1402 AppStorage.setOrCreate('zoomRatioMin', range[0]); 1403 AppStorage.setOrCreate('zoomRatioMax', range[1]); 1404 } 1405 } catch (error) { 1406 let err = error as BusinessError; 1407 Logger.error(TAG, `getZoomRatioRange fail: error code ${err.code}`); 1408 } 1409 // 开始会话工作 1410 await this.portraitSession.start(); 1411 this.isFocusMode((this.globalContext.getObject('cameraConfig') as CameraConfig).focusMode); 1412 Logger.info(TAG, 'portraitSessionFlowFn success'); 1413 } catch (error) { 1414 let err = error as BusinessError; 1415 Logger.error(TAG, `portraitSessionFlowFn fail : ${JSON.stringify(err)}`); 1416 } 1417 } 1418 1419 async nightSessionFlowFn(sceneModeIndex?: number): Promise<void> { 1420 try { 1421 // 创建PortraitSession实例 1422 this.nightSession = this.cameraManager.createSession(camera.SceneMode.NIGHT_PHOTO); 1423 // 监听焦距的状态变化 1424 this.onFocusStateChange(); 1425 // 监听拍照会话的错误事件 1426 this.onCaptureSessionErrorChange(); 1427 // 开始配置会话 1428 this.nightSession.beginConfig(); 1429 // 把CameraInput加入到会话 1430 this.nightSession.addInput(this.cameraInput); 1431 // 把previewOutput加入到会话 1432 this.nightSession.addOutput(this.previewOutput); 1433 // 把photoOutPut加入到会话 1434 this.nightSession.addOutput(this.photoOutPut); 1435 if (this.captureMode === CaptureMode.NEW_DEFERRED_PHOTO) { 1436 if (this.isDeferredImageDeliverySupported(camera.DeferredDeliveryImageType.PHOTO)) { 1437 this.deferImageDeliveryFor(camera.DeferredDeliveryImageType.PHOTO); 1438 this.isDeferredImageDeliveryEnabled(camera.DeferredDeliveryImageType.PHOTO); 1439 } 1440 } 1441 1442 // 提交配置信息 1443 await this.nightSession.commitConfig(); 1444 1445 // 处理变焦条信息 1446 try { 1447 let range: Array<number> = this.nightSession.getZoomRatioRange(); 1448 Logger.info(TAG, `getZoomRatioRange:${range}`); 1449 if (range) { 1450 AppStorage.setOrCreate('zoomRatioMin', range[0]); 1451 AppStorage.setOrCreate('zoomRatioMax', range[1]); 1452 } 1453 } catch (error) { 1454 let err = error as BusinessError; 1455 Logger.error(TAG, `getZoomRatioRange fail: error code ${err.code}`); 1456 } 1457 // 开始会话工作 1458 await this.nightSession.start(); 1459 this.isFocusMode((this.globalContext.getObject('cameraConfig') as CameraConfig).focusMode); 1460 Logger.info(TAG, 'nightSessionFlowFn success'); 1461 } catch (error) { 1462 let err = error as BusinessError; 1463 Logger.error(TAG, `nightSessionFlowFn fail : ${JSON.stringify(err)}`); 1464 } 1465 } 1466 1467 setColorSpace(session: camera.PhotoSession | camera.VideoSession, colorSpace: colorSpaceManager.ColorSpace): void { 1468 try { 1469 Logger.info(TAG, `setColorSpace enter`); 1470 let colorSpaces: Array<colorSpaceManager.ColorSpace> = session.getSupportedColorSpaces(); 1471 let isSupportedUseColorSpaces = colorSpaces.indexOf(colorSpace); 1472 if (isSupportedUseColorSpaces) { 1473 Logger.info(TAG, `setColorSpace ${colorSpace} start`); 1474 session.setColorSpace(colorSpace); 1475 Logger.info(TAG, `setColorSpace ${colorSpace} success`); 1476 return; 1477 } 1478 } catch (error) { 1479 let err = error as BusinessError; 1480 Logger.error(TAG, `setColorSpace fail : ${JSON.stringify(err)}`); 1481 } 1482 } 1483 1484 setPortraitEffect(): void { 1485 try { 1486 this.portraitSession.setPortraitEffect(camera.PortraitEffect.CIRCLES); 1487 } catch (error) { 1488 let err = error as BusinessError; 1489 Logger.error(TAG, `setPortraitEffect error code: ${err.code}`); 1490 } 1491 this.getPortraitEffect(); 1492 } 1493 1494 getPortraitEffect(): void { 1495 try { 1496 let portraitEffect = this.portraitSession.getPortraitEffect(); 1497 Logger.info(TAG, `getPortraitEffect portraitEffect: ${portraitEffect}`); 1498 } catch (error) { 1499 let err = error as BusinessError; 1500 Logger.error(TAG, `setPortraitEffect error code: ${err.code}`); 1501 } 1502 } 1503 1504 setMoonCaptureBoostEnable(moonCaptureBoostEnable: Boolean): boolean { 1505 Logger.info(TAG, 'moonCaptureBoostEnable is called.'); 1506 let session: camera.CaptureSession = this.getSession(); 1507 if (!session) { 1508 return false; 1509 } 1510 try { 1511 session.enableSceneFeature(camera.SceneFeatureType.MOON_CAPTURE_BOOST, moonCaptureBoostEnable); 1512 AppStorage.setOrCreate<boolean>('moonCaptureComponentEnable', moonCaptureBoostEnable); 1513 } catch (error) { 1514 let err = error as BusinessError; 1515 Logger.error(TAG, `setMoonCaptureBoostEnable fail: error code ${err.code}`); 1516 return false; 1517 } 1518 return true; 1519 } 1520 1521 setColorEffect(colorEffect: camera.ColorEffectType): void { 1522 Logger.info(TAG, 'setColorEffect is called.'); 1523 if (this.photoSession || this.videoSession || this.portraitSession || this.nightSession) { 1524 let res: Array<camera.ColorEffectType> | undefined = []; 1525 res = this.getSupportedColorEffects(); 1526 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1527 if (!session) { 1528 return; 1529 } 1530 for (let i = 0; i < res.length; i++) { 1531 if (res[i] === colorEffect) { 1532 Logger.info(TAG, 'setColorEffect success.'); 1533 session.setColorEffect(colorEffect); 1534 this.colorEffect = colorEffect; 1535 return; 1536 } 1537 } 1538 Logger.error(TAG, `setColorEffect fail: The colorEffect ${colorEffect} was not found`); 1539 } 1540 } 1541 1542 getColorEffect(): camera.ColorEffectType | undefined { 1543 Logger.info(TAG, 'getColorEffect is called.'); 1544 let colorEffect: camera.ColorEffectType | undefined = undefined; 1545 if (this.photoSession || this.videoSession || this.portraitSession || this.nightSession) { 1546 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1547 if (!session) { 1548 return colorEffect; 1549 } 1550 try { 1551 colorEffect = session.getColorEffect(); 1552 } catch (error) { 1553 let err = error as BusinessError; 1554 Logger.error(TAG, `setColorEffect fail: error code ${err.code}`); 1555 } 1556 } 1557 return colorEffect; 1558 } 1559 1560 getSupportedColorEffects(): Array<camera.ColorEffectType> | undefined { 1561 Logger.info(TAG, 'getSupportedColorEffects is called.'); 1562 let res: Array<camera.ColorEffectType> | undefined = []; 1563 if (this.photoSession || this.videoSession || this.portraitSession || this.nightSession) { 1564 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1565 if (!session) { 1566 return res; 1567 } 1568 res = session.getSupportedColorEffects(); 1569 Logger.info(TAG, `getSupportedColorEffects length: ${res.length}`); 1570 } 1571 return res; 1572 } 1573 1574 /** 1575 * 监听拍照事件 1576 */ 1577 photoOutPutCallBack(): void { 1578 // 监听拍照开始 1579 this.photoOutPut.on('captureStart', (err: BusinessError, captureId: number): void => { 1580 Logger.info(TAG, `photoOutPutCallBack captureStart captureId success: ${captureId}`); 1581 }); 1582 // 监听拍照帧输出捕获 1583 // 获取时间戳转化异常 1584 this.photoOutPut.on('frameShutter', (err: BusinessError, frameShutterInfo: camera.FrameShutterInfo): void => { 1585 Logger.info(TAG, `photoOutPutCallBack frameShutter captureId: ${frameShutterInfo.captureId}, timestamp: ${frameShutterInfo.timestamp}`); 1586 }); 1587 // 监听拍照结束 1588 this.photoOutPut.on('captureEnd', (err: BusinessError, captureEndInfo: camera.CaptureEndInfo): void => { 1589 Logger.info(TAG, `photoOutPutCallBack captureEnd captureId: ${captureEndInfo.captureId}, frameCount: ${captureEndInfo.frameCount}`); 1590 }); 1591 this.photoOutPut.on('error', (data: BusinessError): void => { 1592 Logger.info(TAG, `photoOutPut data: ${JSON.stringify(data)}`); 1593 }); 1594 this.photoOutPut.on('photoAvailable', (err: BusinessError, photo: camera.Photo): void => { 1595 Logger.info(TAG, 'photoOutPutCallBack photoAvailable 3'); 1596 if (err) { 1597 Logger.info(TAG, `photoAvailable error: ${JSON.stringify(err)}.`); 1598 return; 1599 } 1600 let mainImage: image.Image = photo.main; 1601 AppStorage.setOrCreate('mainImage', mainImage); 1602 mainImage.getComponent(image.ComponentType.JPEG, (errCode: BusinessError, component: image.Component): void => { 1603 Logger.debug(TAG, 'getComponent start'); 1604 Logger.info(TAG, `err: ${JSON.stringify(errCode)}`); 1605 if (errCode || component === undefined) { 1606 Logger.info(TAG, 'getComponent failed'); 1607 return; 1608 } 1609 let buffer: ArrayBuffer; 1610 if (component.byteBuffer) { 1611 buffer = component.byteBuffer; 1612 } else { 1613 Logger.error(TAG, 'component byteBuffer is undefined'); 1614 } 1615 this.savePicture(buffer, mainImage); 1616 }); 1617 photo.release(); 1618 }); 1619 this.photoOutPut.on('deferredPhotoProxyAvailable', (err: BusinessError, proxyObj: camera.DeferredPhotoProxy): void => { 1620 if (err) { 1621 Logger.info(TAG, `deferredPhotoProxyAvailable error: ${JSON.stringify(err)}.`); 1622 return; 1623 } 1624 Logger.info(TAG, 'photoOutPutCallBack deferredPhotoProxyAvailable'); 1625 proxyObj.getThumbnail().then((thumbnail: image.PixelMap) => { 1626 AppStorage.setOrCreate('proxyThumbnail', thumbnail); 1627 }); 1628 this.saveDeferredPhoto(proxyObj); 1629 }); 1630 } 1631 1632 /** 1633 * 调用媒体库方式落盘缩略图 1634 */ 1635 async saveDeferredPhoto(proxyObj: camera.DeferredPhotoProxy): Promise<void> { 1636 try { 1637 // 创建 photoAsset 1638 let photoHelper = photoAccessHelper.getPhotoAccessHelper(this.globalContext.getCameraSettingContext()); 1639 let fileName = Date.now() + '.jpg'; 1640 let photoAsset = await photoHelper.createAsset(fileName); 1641 let imgPhotoUri: string = photoAsset.uri; 1642 // 将缩略图代理类传递给媒体库 1643 let mediaRequest: photoAccessHelper.MediaAssetChangeRequest = new photoAccessHelper.MediaAssetChangeRequest(photoAsset); 1644 mediaRequest.addResource(photoAccessHelper.ResourceType.PHOTO_PROXY, proxyObj); 1645 let res = await photoHelper.applyChanges(mediaRequest); 1646 this.handleTakePicture(imgPhotoUri); 1647 Logger.info(TAG, `saveDeferredPhoto res:${res}.`); 1648 } catch (err) { 1649 Logger.error(TAG, `Failed to saveDeferredPhoto. error: ${JSON.stringify(err)}`); 1650 } 1651 } 1652 1653 /** 1654 * 监听预览事件 1655 */ 1656 previewOutputCallBack(): void { 1657 Logger.info(TAG, 'previewOutputCallBack is called'); 1658 this.previewOutput.on('frameStart', (): void => { 1659 Logger.debug(TAG, 'Preview frame started'); 1660 }); 1661 this.previewOutput.on('frameEnd', (): void => { 1662 Logger.debug(TAG, 'Preview frame ended'); 1663 }); 1664 this.previewOutput.on('error', (previewOutputError: BusinessError): void => { 1665 Logger.info(TAG, `Preview output previewOutputError: ${JSON.stringify(previewOutputError)}`); 1666 }); 1667 } 1668 1669 /** 1670 * 监听录像事件 1671 */ 1672 onVideoOutputChange(): void { 1673 this.videoOutput.on('frameStart', (): void => { 1674 Logger.info(TAG, 'onVideoOutputChange frame started'); 1675 }); 1676 this.videoOutput.on('frameEnd', (): void => { 1677 Logger.info(TAG, 'onVideoOutputChange frame frameEnd'); 1678 }); 1679 this.videoOutput.on('error', (videoOutputError: BusinessError) => { 1680 Logger.error(TAG, `onVideoOutputChange fail: ${JSON.stringify(videoOutputError)}`); 1681 }); 1682 } 1683 1684 /** 1685 * 镜头状态回调 1686 */ 1687 onCameraStatusChange(): void { 1688 Logger.info(TAG, 'onCameraStatusChange is called'); 1689 this.cameraManager.on('cameraStatus', async (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo): Promise<void> => { 1690 Logger.info(TAG, `onCameraStatusChange cameraStatus success, cameraId: ${cameraStatusInfo.camera.cameraId}, status: ${cameraStatusInfo.status}`); 1691 }); 1692 } 1693 1694 /** 1695 * 监听CameraInput的错误事件 1696 */ 1697 onCameraInputChange(): void { 1698 try { 1699 this.cameraInput.on('error', this.cameras[(this.globalContext.getObject('cameraDeviceIndex') as number)], (cameraInputError: BusinessError): void => { 1700 Logger.info(TAG, `onCameraInputChange cameraInput error code: ${cameraInputError.code}`); 1701 }); 1702 } catch (error) { 1703 Logger.info(TAG, `onCameraInputChange cameraInput occur error: error`); 1704 } 1705 } 1706 1707 /** 1708 * 监听焦距的状态变化 1709 */ 1710 onFocusStateChange(): void { 1711 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1712 if (!session) { 1713 return; 1714 } 1715 session.on('focusStateChange', (err: BusinessError, focusState: camera.FocusState): void => { 1716 Logger.info(TAG, `onFocusStateChange captureSession focusStateChange success : ${focusState}`); 1717 }); 1718 } 1719 1720 /** 1721 * 监听拍照会话的错误事件 1722 */ 1723 onCaptureSessionErrorChange(): void { 1724 let session: camera.PortraitPhotoSession | camera.Session | camera.NightPhotoSession = this.getSession(); 1725 if (!session) { 1726 return; 1727 } 1728 session.on('error', (captureSessionError: BusinessError): void => { 1729 Logger.info(TAG, 'onCaptureSessionErrorChange captureSession fail: ' + JSON.stringify(captureSessionError.code)); 1730 }); 1731 1732 } 1733 1734 setCaptureMode(mode: number): void { 1735 this.captureMode = mode; 1736 } 1737 1738 getCaptureMode(): number { 1739 return this.captureMode; 1740 } 1741 1742 /** 1743 * 查询是否支持二阶段 1744 */ 1745 isDeferredImageDeliverySupported(deferredType: camera.DeferredDeliveryImageType): boolean { 1746 let res: boolean = this.photoOutPut.isDeferredImageDeliverySupported(deferredType); 1747 Logger.info(TAG, `isDeferredImageDeliverySupported deferredType:${deferredType} res: ${res}`); 1748 return res; 1749 } 1750 1751 /** 1752 * 查询是否已使能二阶段 1753 */ 1754 isDeferredImageDeliveryEnabled(deferredType: camera.DeferredDeliveryImageType): boolean { 1755 let res: boolean = this.photoOutPut.isDeferredImageDeliveryEnabled(deferredType); 1756 Logger.info(TAG, `isDeferredImageDeliveryEnabled deferredType:${deferredType} res: ${res}`); 1757 } 1758 1759 /** 1760 * 使能二阶段 1761 */ 1762 deferImageDeliveryFor(deferredType: camera.DeferredDeliveryImageType): void { 1763 Logger.info(TAG, `deferImageDeliveryFor type: ${deferredType}`); 1764 this.photoOutPut.deferImageDelivery(deferredType); 1765 } 1766 1767} 1768 1769export default new CameraService();