• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//@ts-nocheck
2/*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import camera from '@ohos.multimedia.camera';
18import image from '@ohos.multimedia.image';
19import media from '@ohos.multimedia.media';
20import deviceInfo from '@ohos.deviceInfo';
21
22import { CameraId } from '../setting/settingitem/CameraId';
23import { Log } from '../utils/Log';
24import ThumbnailGetter from './ThumbnailGetter';
25import SaveCameraAsset from './SaveCameraAsset';
26import { SettingManager } from '../setting/SettingManager';
27import { CameraPlatformCapability } from './CameraPlatformCapability';
28import ReportUtil from '../utils/ReportUtil';
29import { GlobalContext } from '../utils/GlobalContext';
30
31const TAG = '[CameraService]:';
32
33const DEFAULT_VIDEO_FRAME_RATE = 30;
34const FRONT_CAMERA_POSITION = 2;
35const CAMERA_CONNECT_TYPE = 2;
36
37export interface FunctionCallBack {
38  onCapturePhotoOutput(): void
39
40  onCaptureSuccess(thumbnail: any, resourceUri: any): void
41
42  onCaptureFailure(): void
43
44  onRecordSuccess(thumbnail: any): void
45
46  onRecordFailure(): void
47
48  thumbnail(thumbnail: any): void
49}
50
51export interface VideoCallBack {
52  videoUri(videoUri: any): void
53
54  onRecodeError(errorMsg: any): void
55}
56
57type Callback = (args?: any) => void
58
59class CameraInformation {
60  deviceName: string;
61  cameraId: string;
62}
63
64export class CameraService {
65  public mImageSize = {
66    imageWidth: 1920,
67    imageHeight: 1080
68  }
69  public mVideoFrameSize = {
70    frameWidth: 1920,
71    frameHeight: 1080
72  }
73  private mCameraId: string = CameraId.BACK;
74  private mFileAssetId = 0;
75  private mCameraManager!: camera.CameraManager;
76  private mCameraIdMap: Map<string, string> = new Map();
77  private mLocalCameraMap: Map<string, string> = new Map();
78  private mCameraMap: Map<string, CameraInformation> = new Map();
79  private curCameraName = '';
80  private mCameraCount = 0;
81  private mCameraInput!: camera.CameraInput;
82  private mCaptureSession!: camera.CaptureSession;
83  private mPreviewOutput!: camera.PreviewOutput;
84  private mPhotoOutPut!: camera.PhotoOutput;
85  private mImageReceiver!: image.ImageReceiver;
86  private mVideoOutput!: camera.VideoOutput;
87  private mAVRecorder!: media.AVRecorder;
88  private mThumbnail!: image.PixelMap;
89  private mIsStartRecording = false;
90  private mSaveCameraAsset = new SaveCameraAsset();
91  private mThumbnailGetter = new ThumbnailGetter();
92  private camerasCache: any = null;
93  private outputCapability: camera.CameraOutputCapability = null;
94  private mVideoConfig: any = {
95    audioSourceType: 1,
96    videoSourceType: 1,
97    profile: {
98      audioBitrate: 48000,
99      audioChannels: 2,
100      audioCodec: 'audio/mp4a-latm',
101      audioSampleRate: 48000,
102      durationTime: 1000,
103      fileFormat: 'mp4',
104      videoBitrate: 5000000,
105      videoCodec: 'video/avc',
106      videoFrameWidth: 640,
107      videoFrameHeight: 480,
108      videoFrameRate: 30
109    },
110    url: 'file:///data/media/01.mp4',
111    orientationHint: 0,
112    maxSize: 100,
113    maxDuration: 500,
114    rotation: 0
115  }
116  private mCaptureSetting: any = {
117    rotation: 0,
118    quality: 1,
119    mirror: false
120  }
121
122  private constructor() {
123  }
124
125  public static getInstance(): CameraService {
126    if (!globalThis?.sInstanceCameraService) {
127      globalThis.sInstanceCameraService = new CameraService();
128    }
129    return globalThis.sInstanceCameraService;
130  }
131
132  public async initCamera(cameraId: string): Promise<number> {
133    Log.start(`${TAG} initCamera`);
134    if (!this.mCameraManager) {
135      try {
136        this.mCameraManager = camera.getCameraManager(GlobalContext.get().getCameraAbilityContext());
137        const cameras = this.mCameraManager.getSupportedCameras();
138        this.camerasCache = cameras;
139        this.mCameraCount = cameras.length;
140        if (cameras) {
141          Log.info(`${TAG} getCameras success.`);
142          for (let i = 0; i < cameras.length; i++) {
143            Log.info(`${TAG} camera_id: ${cameras[i].cameraId}  cameraPosition: ${cameras[i].cameraPosition}
144              cameraType: ${cameras[i].cameraType} connectionType: ${cameras[i].connectionType}`);
145            if (cameras[i].cameraPosition === FRONT_CAMERA_POSITION && cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
146              this.mLocalCameraMap.set('front', 'true');
147            }
148            if (cameras[i].cameraPosition !== FRONT_CAMERA_POSITION && cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
149              this.mLocalCameraMap.set('back', 'true');
150            }
151          }
152          // TODO 根据底层信息匹配cameraId 目前默认第0个是back, 第1个是front
153          this.mCameraIdMap.set(CameraId.BACK, cameras[0].cameraId);
154          if (cameras.length > 1 && cameras[1].connectionType !== 2) {
155            this.mCameraIdMap.set(CameraId.FRONT, cameras[1].cameraId);
156          } else {
157            this.mCameraIdMap.set(CameraId.FRONT, cameras[0].cameraId);
158          }
159        }
160      } catch (error) {
161        Log.error(`${TAG} initCamera failed: ${JSON.stringify(error)}`);
162        ReportUtil.writeFaultLog(error);
163      }
164    }
165    this.curCameraName = cameraId;
166    await this.createCameraInput(cameraId, 'init');
167
168    Log.info(`${TAG} deviceType = ${deviceInfo.deviceType}`);
169    if (deviceInfo.deviceType == 'default') {
170      this.mVideoConfig.videoSourceType = 1;
171    } else {
172      this.mVideoConfig.videoSourceType = 0;
173    }
174    Log.end(`${TAG} initCamera`);
175    return this.mCameraCount;
176  }
177
178  public getCameraManager(): camera.CameraManager {
179    return this.mCameraManager;
180  }
181
182  public getCameraIdMap(): Map<string, string> {
183    return this.mCameraIdMap;
184  }
185
186  public getLocalCameraMap(): Map<string, string> {
187    return this.mLocalCameraMap;
188  }
189
190  public getCameraMap(): Map<string, CameraInformation> {
191    return this.mCameraMap;
192  }
193
194  public getCameraCount(): number {
195    return this.mCameraCount;
196  }
197
198  public async createCameraInput(cameraName: string, callType?: string) {
199    Log.start(`${TAG} createCameraInput`);
200    this.mCameraId = cameraName;
201    this.curCameraName = cameraName;
202    if (callType === 'modeChange' || callType === 'init') {
203      let targetCamera = this.camerasCache.filter(item => item.connectionType !== 2);
204      if (targetCamera && targetCamera.length <= 1 && cameraName === 'BACK') {
205        this.curCameraName = 'FRONT';
206        this.mCameraId = 'FRONT';
207      }
208    }
209    if (this.mCameraInput) {
210      await this.mCameraInput.release();
211    }
212    let id;
213    if (cameraName == CameraId.FRONT || cameraName == CameraId.BACK) {
214      id = this.mCameraIdMap.get(cameraName);
215    } else {
216      id = this.mCameraMap.get(cameraName).cameraId;
217    }
218    Log.info(`${TAG} createCameraInput id = ${id}`);
219    try {
220      let cameras = await this.getCameraLists();
221      let targetCamera = cameras.find(item => item.cameraId === id);
222      this.outputCapability = this.mCameraManager.getSupportedOutputCapability(targetCamera);
223      this.mCameraInput = this.mCameraManager.createCameraInput(targetCamera);
224      await this.mCameraInput.open();
225      const platformCapability = CameraPlatformCapability.getInstance();
226      await platformCapability.calcSupportedSizes(this.mCameraInput, this.outputCapability);
227      SettingManager.getInstance().setCameraPlatformCapability(platformCapability);
228    } catch (error) {
229      Log.error(`${TAG} createCameraInput failed: ${JSON.stringify(error)}`);
230      ReportUtil.writeFaultLog(error);
231    }
232    Log.end(`${TAG} createCameraInput`);
233  }
234
235  public async releaseCameraInput() {
236    Log.start(`${TAG} releaseCameraInput`);
237    if (this.mCameraInput) {
238      try {
239        await this.mCameraInput.release();
240      } catch (error) {
241        Log.error(`${TAG} releaseCameraInput failed: ${JSON.stringify(error)}`);
242        ReportUtil.writeFaultLog(error);
243      }
244      this.mCameraInput = null;
245    }
246    Log.end(`${TAG} releaseCameraInput`);
247  }
248
249  public async createPreviewOutput(surfaceId: string, mode: string) {
250    Log.start(`${TAG} createPreviewOutput`);
251    const size = SettingManager.getInstance().getPreviewSize(mode);
252    Log.info(`${TAG} createPreviewOutput size.width = ${size.width} size.height = ${size.height}`);
253    GlobalContext.get().getXComponentController().setXComponentSurfaceSize({
254      surfaceWidth: size.width,
255      surfaceHeight: size.height
256    });
257    let previewProfiles = this.outputCapability.previewProfiles;
258    let previewProfile;
259    if (deviceInfo.deviceType == 'default') {
260      previewProfile = previewProfiles[0];
261    } else {
262      Log.info(`${TAG} previewProfiles length.` + previewProfiles.length);
263      previewProfile = previewProfiles.find(item => item.size.width === size.width &&
264        item.size.height === size.height && item.format === 1003);
265    }
266    await this.releasePreviewOutput();
267    try {
268      this.mPreviewOutput = this.mCameraManager.createPreviewOutput(previewProfile, surfaceId);
269    } catch (error) {
270      Log.error(`${TAG} createPreviewOutput failed: ${JSON.stringify(error)}`);
271      ReportUtil.writeFaultLog(error);
272    }
273    Log.end(`${TAG} createPreviewOutput`);
274  }
275
276  public async releasePreviewOutput() {
277    Log.start(`${TAG} releasePreviewOutput`);
278    if (this.mPreviewOutput) {
279      try {
280        await this.mPreviewOutput.release();
281        this.mPreviewOutput = null;
282      } catch (error) {
283        Log.error(`${TAG} releasePreviewOutput failed: ${JSON.stringify(error)}`);
284        ReportUtil.writeFaultLog(error);
285      }
286    }
287    Log.end(`${TAG} releasePreviewOutput`);
288  }
289
290  public async createPhotoOutput(functionCallback: FunctionCallBack) {
291    Log.start(`${TAG} createPhotoOutput`);
292    const size = SettingManager.getInstance().getImageSize();
293    Log.info(`${TAG} createPhotoOutput size.width = ${size.width} size.height = ${size.height}`);
294    this.mImageReceiver = image.createImageReceiver(size.width, size.height, image.ImageFormat.JPEG, 8);
295    const surfaceId = await this.mImageReceiver.getReceivingSurfaceId();
296    Log.info(`${TAG} createPhotoOutput surfaceId: ${surfaceId}.`);
297    let photoProfiles = this.outputCapability.photoProfiles;
298    let photoProfile;
299    if (deviceInfo.deviceType == 'default') {
300      photoProfile = photoProfiles[0];
301    } else {
302      Log.info(`${TAG} videoProfiles length.` + photoProfiles.length);
303      photoProfile = photoProfiles.find(item => item.size.width === size.width && item.size.height === size.height);
304    }
305    try {
306      this.mPhotoOutPut = this.mCameraManager.createPhotoOutput(photoProfile, surfaceId);
307    } catch (error) {
308      Log.error(`${TAG} createPhotoOutput failed: ${JSON.stringify(error)}`);
309      ReportUtil.writeFaultLog(error);
310    }
311    Log.info(`${TAG} createPhotoOutput mPhotoOutPut: ${this.mPhotoOutPut}.`);
312    this.mSaveCameraAsset.saveImage(this.mImageReceiver, 40, 40, this.mThumbnailGetter, functionCallback);
313    Log.end(`${TAG} createPhotoOutput`);
314  }
315
316  public async releasePhotoOutput() {
317    Log.start(`${TAG} releasePhotoOutput`);
318    if (this.mPhotoOutPut) {
319      try {
320        await this.mPhotoOutPut.release();
321        this.mPhotoOutPut = null;
322      } catch (error) {
323        Log.error(`${TAG} releasePhotoOutput failed: ${JSON.stringify(error)}`);
324        ReportUtil.writeFaultLog(error);
325      }
326    }
327    if (this.mImageReceiver) {
328      await this.mImageReceiver.release();
329      this.mImageReceiver = null;
330    }
331    Log.end(`${TAG} releasePhotoOutput`);
332  }
333
334  public async createSession(surfaceId: string, isVideo: boolean) {
335    Log.start(`${TAG} createSession`);
336    GlobalContext.get().setObject('isSessionCreating', true)
337    this.mCaptureSession = this.mCameraManager.createCaptureSession();
338    GlobalContext.get().setObject('isSessionCreating', false)
339    Log.info(`${TAG} createSession captureSession: ${this.mCaptureSession}, cameraInput: ${this.mCameraInput},
340    videoOutPut: ${this.mVideoOutput}, photoOutPut: ${this.mPhotoOutPut},  mPreviewOutput: ${this.mPreviewOutput}`);
341    Log.info(`${TAG} createSession beginConfig.`);
342    Log.start(Log.STREAM_DISTRIBUTION);
343    try {
344      this.mCaptureSession?.beginConfig();
345      await new Promise((resolve) => setTimeout(resolve, 1));
346      Log.info(`${TAG} createSession addInput.`);
347      this.mCaptureSession?.addInput(this.mCameraInput);
348      if (!isVideo) {
349        Log.info(`${TAG} createSession photo addOutput.`);
350        this.mCaptureSession?.addOutput(this.mPhotoOutPut);
351      }
352      Log.info(`${TAG} createSession preview addOutput.`);
353      this.mCaptureSession?.addOutput(this.mPreviewOutput);
354    } catch (error) {
355      Log.error(`${TAG} createSession failed: ${JSON.stringify(error)}`);
356      if (error) {
357        ReportUtil.write(ReportUtil.CAMERA_ERROR);
358      }
359    }
360    Log.info(`${TAG} createSession commitConfig.`);
361    Log.start(Log.OPEN_CAMERA);
362    try {
363      await this.mCaptureSession?.commitConfig();
364      Log.end(Log.OPEN_CAMERA);
365      Log.end(Log.STREAM_DISTRIBUTION);
366      await this.mCaptureSession?.start();
367    } catch (err) {
368      if (err) {
369        ReportUtil.write(ReportUtil.OPEN_FAIL);
370      }
371    }
372    if (GlobalContext.get().getT<boolean>('cameraStartFlag') && (new Date().getTime() - GlobalContext.get().getT<number>('cameraStartTime')) > 2000) {
373      ReportUtil.write(ReportUtil.START_TIMEOUT);
374    }
375    GlobalContext.get().setObject('cameraStartFlag', false);
376    Log.end(`${TAG} createSession`);
377  }
378
379  public async releaseSession() {
380    Log.start(`${TAG} releaseSession`);
381    if (this.mCaptureSession) {
382      try {
383        await this.mCaptureSession.stop();
384        await this.mCaptureSession.release();
385        this.mCaptureSession = null;
386      } catch (error) {
387        Log.error(`${TAG} releaseSession failed: ${JSON.stringify(error)}`);
388        ReportUtil.writeFaultLog(error);
389      }
390    }
391    Log.end(`${TAG} releaseSession`);
392  }
393
394  public async startPreview() {
395    Log.start(`${TAG} startPreview`);
396    if (!this.mCaptureSession) {
397      return;
398    }
399    try {
400      await this.mCaptureSession.start();
401    } catch (error) {
402      Log.error(`${TAG} startPreview failed: ${JSON.stringify(error)}`);
403      ReportUtil.writeFaultLog(error);
404    }
405    Log.end(`${TAG} startPreview`);
406  }
407
408  public async stopPreview() {
409    Log.start(`${TAG} stopPreview`);
410    if (!this.mCaptureSession) {
411      return;
412    }
413    try {
414      await this.mCaptureSession.stop();
415    } catch (error) {
416      Log.error(`${TAG} stopPreview failed: ${JSON.stringify(error)}`);
417      ReportUtil.writeFaultLog(error);
418    }
419    Log.end(`${TAG} stopPreview`);
420  }
421
422  public async takePicture() {
423    Log.start(`${TAG} takePicture`);
424    ReportUtil.write(ReportUtil.CAPTURE);
425    if (!this.mCaptureSession) {
426      Log.info(`${TAG} takePicture session is release`);
427      return;
428    }
429    if (!this.mPhotoOutPut) {
430      Log.info(`${TAG} takePicture photoOutPut is release`);
431      return;
432    }
433    if (this.mCameraId === CameraId.FRONT) {
434      this.mCaptureSetting.mirror = SettingManager.getInstance().getSelfMirror();
435    }
436    const locationData = SettingManager.getInstance().getCurGeoLocation();
437    if (locationData) {
438      this.mCaptureSetting.location = {
439        latitude: locationData.latitude,
440        longitude: locationData.longitude,
441        altitude: locationData.altitude
442      }
443    }
444    Log.info(`${TAG} takePicture captureSetting ${JSON.stringify(this.mCaptureSetting)}`);
445    // todo modify the location and mirror config
446    try {
447      this.mPhotoOutPut.capture(this.mCaptureSetting);
448    } catch (err) {
449      if (err) {
450        ReportUtil.write(ReportUtil.CAPTURE_FAIL);
451      }
452    }
453    Log.end(`${TAG} takePicture`);
454    if ((new Date().getTime() - GlobalContext.get().getT<number>('startCaptureTime')) > 2000) {
455      ReportUtil.write(ReportUtil.CAPTURE_TIMEOUT);
456    }
457  }
458
459  public async createVideoOutput(functionCallBack: VideoCallBack) {
460    Log.start(`${TAG} createVideoOutput`);
461    this.mFileAssetId = await this.mSaveCameraAsset.createVideoFd(functionCallBack);
462    if (this.mFileAssetId === undefined) {
463      Log.error(`${TAG} createVideoOutput error: mFileAssetId undefined`);
464      functionCallBack.onRecodeError('createVideoOutput error: mFileAssetId undefined');
465    }
466    this.mVideoConfig.url = `fd://${this.mFileAssetId.toString()}`;
467    await media.createAVRecorder().then((recorder) => {
468      Log.info(`${TAG} createVideoOutput createAVRecorder record: ${recorder}`);
469      this.mAVRecorder = recorder;
470    });
471    const size = SettingManager.getInstance().getVideoSize();
472    if (this.mAVRecorder != null) {
473      this.mAVRecorder.on('error', (error) => {
474        if (error) {
475          Log.error(`${TAG} createVideoOutput error: ${JSON.stringify(error)}`);
476          functionCallBack.onRecodeError(`createVideoOutput error: ${JSON.stringify(error)}`);
477        }
478      });
479      Log.info(`${TAG} createVideoOutput size = ${JSON.stringify(size)}`);
480      this.mVideoConfig.profile.videoFrameWidth = size.width;
481      this.mVideoConfig.profile.videoFrameHeight = size.height;
482      const locationData = SettingManager.getInstance().getCurGeoLocation();
483      if (locationData) {
484        this.mVideoConfig.location = {
485          latitude: locationData.latitude,
486          longitude: locationData.longitude
487        };
488      }
489
490      if (deviceInfo.deviceType != 'tablet') {
491        if (this.curCameraName === 'BACK') {
492          this.mVideoConfig.rotation = 90;
493        } else {
494          this.mVideoConfig.rotation = 270;
495        }
496      }
497      Log.info(`${TAG} createVideoOutput mVideoConfig =  ${JSON.stringify(this.mVideoConfig)}.`);
498      await this.mAVRecorder.prepare(this.mVideoConfig);
499      Log.info(`${TAG} createVideoOutput AVRecorder.prepare succeed.`);
500    } else {
501      Log.error(`${TAG} createVideoOutput createAVRecorder failed.`);
502      return;
503    }
504
505    let profileVideo;
506    if (deviceInfo.deviceType == 'default') {
507      profileVideo = this.outputCapability.videoProfiles[0];
508    } else {
509      let videoProfiles = this.outputCapability.videoProfiles;
510      Log.info(`${TAG} videoProfiles length.` + videoProfiles.length);
511      profileVideo = videoProfiles.find(item =>
512      item.size.width === size.width && item.size.height === size.height
513        && item.frameRateRange.min === DEFAULT_VIDEO_FRAME_RATE && item.frameRateRange.max === DEFAULT_VIDEO_FRAME_RATE
514      );
515    }
516
517    const videoId = await this.mAVRecorder.getInputSurface();
518    Log.info(`${TAG} createVideoOutput profileVideo =  ${JSON.stringify(profileVideo)}.`);
519    try {
520      this.mVideoOutput = this.mCameraManager.createVideoOutput(profileVideo, videoId);
521    } catch (error) {
522      Log.error(`${TAG} createVideoOutput failed: ${JSON.stringify(error)}`);
523      ReportUtil.writeFaultLog(error);
524    }
525    Log.end(`${TAG} createVideoOutput`);
526  }
527
528  public async releaseVideoOutput() {
529    Log.start(`${TAG} releaseVideoOutput`);
530    if (this.mVideoOutput) {
531      Log.info(`${TAG} releaseVideoOutput start`);
532      try {
533        await this.mVideoOutput.release();
534      } catch (error) {
535        Log.error(`${TAG} releaseVideoOutput failed: ${JSON.stringify(error)}`);
536        ReportUtil.writeFaultLog(error);
537      }
538      Log.info(`${TAG} releaseVideoOutput end`);
539      this.mVideoOutput = null;
540    }
541    Log.end(`${TAG} releaseVideoOutput`);
542  }
543
544  public async StartRecording(functionCallBack: VideoCallBack) {
545    let startRecordingTime = new Date().getTime();
546    Log.start(`${TAG} StartRecording`);
547    Log.info(`${TAG} StartRecording codec ${this.mVideoConfig.profile.videoCodec}`);
548    ReportUtil.write(ReportUtil.VIDEO_RECORD);
549    try {
550      await this.mCaptureSession.stop();
551      this.mCaptureSession.beginConfig();
552      if (this.mVideoOutput) {
553        await this.mCaptureSession.removeOutput(this.mVideoOutput);
554        Log.info(`${TAG} old videoOutput has been removed.`);
555      }
556      await this.createVideoOutput(functionCallBack);
557      this.mCaptureSession.addOutput(this.mVideoOutput);
558      Log.info(`${TAG} StartRecording addOutput finished.`);
559      await this.mCaptureSession.commitConfig();
560      Log.info(`${TAG} StartRecording commitConfig finished.`);
561      await this.mCaptureSession.start();
562      Log.info(`${TAG} StartRecording Session.start finished.`);
563    } catch (err) {
564      GlobalContext.get().setObject('startRecordingFlag', false);
565      ReportUtil.writeFaultLog(error);
566      Log.error(`${TAG} remove videoOutput ${err}`);
567    }
568    await this.mVideoOutput.start().then(() => {
569      Log.info(`${TAG} videoOutput.start()`);
570    });
571    await this.mAVRecorder.start().then(() => {
572      Log.info(`${TAG} AVRecorder.start()`);
573    });
574    this.mIsStartRecording = true;
575    if (new Date().getTime() - startRecordingTime > 2000) {
576      ReportUtil.write(ReportUtil.START_RECORD_TIMEOUT);
577    }
578    Log.end(`${TAG} StartRecording`);
579  }
580
581  public async stopRecording(): Promise<PixelMap | undefined> {
582    Log.start(Log.STOP_RECORDING);
583    let stopRecordingTime = new Date().getTime();
584    ReportUtil.write(ReportUtil.STOP_RECORD);
585    if (!this.mVideoOutput || !this.mAVRecorder) {
586      Log.error(`${TAG} stopRecording error videoOutPut: ${this.mVideoOutput},
587              AVRecorder: ${this.mAVRecorder} .`);
588      return undefined;
589    }
590    this.mIsStartRecording = false;
591    try {
592      await this.mAVRecorder.stop();
593      await this.mAVRecorder.release();
594    } catch (err) {
595      Log.error(`${TAG} stop AVRecorder ${err}`);
596    }
597
598    try {
599      await this.mVideoOutput.stop();
600    } catch (err) {
601      Log.error(`${TAG} stop videoOutput ${err}`);
602    }
603
604    if (this.mFileAssetId != undefined) {
605      await this.mSaveCameraAsset.videoPrepareFile.close(this.mFileAssetId);
606      this.mFileAssetId = undefined;
607      Log.info(`${TAG} fileAsset.close().`);
608    }
609    Log.start(Log.UPDATE_VIDEO_THUMBNAIL);
610    const thumbnailPixelMap: PixelMap | undefined = await this.mThumbnailGetter.getThumbnailInfo(40, 40);
611    Log.end(Log.UPDATE_VIDEO_THUMBNAIL);
612    if (new Date().getTime() - stopRecordingTime > 2000) {
613      ReportUtil.write(ReportUtil.FINISH_RECORD_TIMEOUT);
614    }
615    Log.end(Log.STOP_RECORDING);
616    return thumbnailPixelMap;
617  }
618
619  public async pauseRecording() {
620    Log.start(`${TAG} pauseRecording`);
621    if (!this.mVideoOutput || !this.mAVRecorder) {
622      Log.error(`${TAG} pauseRecording error videoOutPut: ${this.mVideoOutput},
623              AVRecorder: ${this.mAVRecorder} .`);
624      return;
625    }
626    try {
627      await this.mAVRecorder.pause();
628      await this.mVideoOutput.stop();
629    } catch (error) {
630      Log.error(`${TAG} pauseRecording failed: ${JSON.stringify(error)}`);
631    }
632    Log.end(`${TAG} pauseRecording`);
633  }
634
635  public async resumeRecording() {
636    Log.start(`${TAG} resumeRecording`);
637    if (!this.mVideoOutput || !this.mAVRecorder) {
638      Log.error(`${TAG} resumeRecording error videoOutPut: ${this.mVideoOutput},
639              AVRecorder: ${this.mAVRecorder} .`);
640      return;
641    }
642    await this.mVideoOutput.start().then(() => {
643      Log.info(`${TAG} videoOutput.start()`);
644    }).catch((error) => {
645      Log.error(`${TAG} resumeRecording mVideoOutput start failed: ${JSON.stringify(error)}`);
646    });
647    await this.mAVRecorder.resume();
648    Log.end(`${TAG} resumeRecording`);
649  }
650
651  public async releaseRecording() {
652    Log.start(`${TAG} releaseRecording`);
653    if (!this.mAVRecorder) {
654      Log.info(`${TAG} AVRecorder has not been created.`);
655      return;
656    }
657    if (this.mIsStartRecording) {
658      await this.stopRecording();
659    }
660    await this.mAVRecorder.release().then(() => {
661      Log.info(`${TAG} AVRecorder.release() success.`);
662      this.mAVRecorder = undefined;
663    });
664    Log.end(`${TAG} releaseRecording`);
665  }
666
667  public async releaseCamera() {
668    Log.start(`${TAG} releaseCamera`);
669    await this.releaseRecording();
670    await this.releaseVideoOutput();
671    await this.releasePhotoOutput();
672    await this.releaseSession();
673    Log.end(`${TAG} releaseCamera`);
674  }
675
676  public async setZoomRatio(zoomRatio: number) {
677    Log.info(`${TAG} setZoomRatio invoke E ${zoomRatio}`);
678    if (!this.mCaptureSession) {
679      Log.info(`${TAG} setZoomRatio mCaptureSession is release`);
680      return;
681    }
682    try {
683      this.mCaptureSession.setZoomRatio(zoomRatio);
684    } catch (error) {
685      Log.error(`${TAG} setZoomRatio failed: ${JSON.stringify(error)}`);
686    }
687    Log.info(`${TAG} setZoomRatio invoke X.`);
688  }
689
690  public async getZoomRatio(): Promise<number> {
691    Log.info(`${TAG} getZoomRatio invoke E.`);
692    if (!this.mCaptureSession) {
693      Log.info(`${TAG} getZoomRatio mCaptureSession is release`);
694      return 1;
695    }
696    Log.info(`${TAG} getZoomRatio invoke X.`);
697    return this.mCaptureSession.getZoomRatio();
698  }
699
700  public async setVideoConfig(videoConfig: any) {
701    Log.info(`${TAG} setVideoConfig invoke E.`);
702    if (videoConfig) {
703      this.mVideoConfig = videoConfig;
704    } else {
705      Log.info(`${TAG} setVideoConfig videoConfig is null.`);
706    }
707    Log.info(`${TAG} setVideoConfig invoke X.`);
708  }
709
710  public async setCaptureSetting(captureSetting: any) {
711    Log.info(`${TAG} setCaptureSetting invoke E.`);
712    if (captureSetting) {
713      this.mCaptureSetting = captureSetting;
714    } else {
715      Log.info(`${TAG} setCaptureSetting captureSetting is null.`);
716    }
717    Log.info(`${TAG} setCaptureSetting invoke X.`);
718  }
719
720  public getThumbnail(functionCallBack: FunctionCallBack): image.PixelMap {
721    Log.start(`${TAG} getThumbnail`);
722    this.mThumbnailGetter.getThumbnailInfo(40, 40).then((thumbnail) => {
723      functionCallBack.thumbnail(thumbnail);
724      Log.end(`${TAG} getThumbnail`);
725    });
726    return this.mThumbnail;
727  }
728
729  public getCameraName(): string {
730    return this.curCameraName;
731  }
732
733  public setCameraId(name: string): void {
734    this.curCameraName = name;
735  }
736
737  public getPhotoUri() {
738    return this.mSaveCameraAsset.getPhotoUri();
739  }
740
741  public getRecentFileUri(): string {
742    return this.mThumbnailGetter.getRecentFileUri();
743  }
744
745  private async getCameraLists() {
746    const cameras = this.mCameraManager.getSupportedCameras();
747    this.camerasCache = cameras;
748    return cameras;
749  }
750}