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