• 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 &&
146              cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
147              this.mLocalCameraMap.set('front', 'true');
148            }
149            if (cameras[i].cameraPosition !== FRONT_CAMERA_POSITION &&
150              cameras[i].connectionType !== CAMERA_CONNECT_TYPE) {
151              this.mLocalCameraMap.set('back', 'true');
152            }
153          }
154          // TODO 根据底层信息匹配cameraId 目前默认第0个是back, 第1个是front
155          this.mCameraIdMap.set(CameraId.BACK, cameras[0].cameraId);
156          if (cameras.length > 1 && cameras[1].connectionType !== 2) {
157            this.mCameraIdMap.set(CameraId.FRONT, cameras[1].cameraId);
158          } else {
159            this.mCameraIdMap.set(CameraId.FRONT, cameras[0].cameraId);
160          }
161        }
162      } catch (error) {
163        Log.error(`${TAG} initCamera failed: ${JSON.stringify(error)}`);
164        ReportUtil.writeFaultLog(error);
165      }
166    }
167    this.curCameraName = cameraId;
168    await this.createCameraInput(cameraId, 'init');
169
170    Log.info(`${TAG} deviceType = ${deviceInfo.deviceType}`);
171    if (deviceInfo.deviceType == 'default') {
172      this.mVideoConfig.videoSourceType = 1;
173    } else {
174      this.mVideoConfig.videoSourceType = 0;
175    }
176    Log.end(`${TAG} initCamera`);
177    return this.mCameraCount;
178  }
179
180  public getCameraManager(): camera.CameraManager {
181    return this.mCameraManager;
182  }
183
184  public getCameraIdMap(): Map<string, string> {
185    return this.mCameraIdMap;
186  }
187
188  public getLocalCameraMap(): Map<string, string> {
189    return this.mLocalCameraMap;
190  }
191
192  public getCameraMap(): Map<string, CameraInformation> {
193    return this.mCameraMap;
194  }
195
196  public getCameraCount(): number {
197    return this.mCameraCount;
198  }
199
200  public async createCameraInput(cameraName: string, callType?: string) {
201    Log.start(`${TAG} createCameraInput`);
202    this.mCameraId = cameraName;
203    this.curCameraName = cameraName;
204    if (callType === 'modeChange' || callType === 'init') {
205      let targetCamera = this.camerasCache.filter(item => item.connectionType !== 2);
206      if (targetCamera && targetCamera.length <= 1 && cameraName === 'BACK') {
207        this.curCameraName = 'FRONT';
208        this.mCameraId = 'FRONT';
209      }
210    }
211    if (this.mCameraInput) {
212      await this.mCameraInput.release();
213    }
214    let id;
215    if (cameraName == CameraId.FRONT || cameraName == CameraId.BACK) {
216      id = this.mCameraIdMap.get(cameraName);
217    } else {
218      id = this.mCameraMap.get(cameraName).cameraId;
219    }
220    Log.info(`${TAG} createCameraInput id = ${id}`);
221    try {
222      let cameras = await this.getCameraLists();
223      let targetCamera = cameras.find(item => item.cameraId === id);
224      this.outputCapability = this.mCameraManager.getSupportedOutputCapability(targetCamera);
225      this.mCameraInput = this.mCameraManager.createCameraInput(targetCamera);
226      await this.mCameraInput.open();
227      const platformCapability = CameraPlatformCapability.getInstance();
228      await platformCapability.calcSupportedSizes(this.mCameraInput, this.outputCapability);
229      SettingManager.getInstance().setCameraPlatformCapability(platformCapability);
230    } catch (error) {
231      Log.error(`${TAG} createCameraInput failed: ${JSON.stringify(error)}`);
232      ReportUtil.writeFaultLog(error);
233    }
234    Log.end(`${TAG} createCameraInput`);
235  }
236
237  public async releaseCameraInput() {
238    Log.start(`${TAG} releaseCameraInput`);
239    if (this.mCameraInput) {
240      try {
241        await this.mCameraInput.release();
242      } catch (error) {
243        Log.error(`${TAG} releaseCameraInput failed: ${JSON.stringify(error)}`);
244        ReportUtil.writeFaultLog(error);
245      }
246      this.mCameraInput = null;
247    }
248    Log.end(`${TAG} releaseCameraInput`);
249  }
250
251  public async createPreviewOutput(surfaceId: string, mode: string) {
252    Log.start(`${TAG} createPreviewOutput`);
253    const size = SettingManager.getInstance().getPreviewSize(mode);
254    Log.info(`${TAG} createPreviewOutput size.width = ${size.width} size.height = ${size.height}`);
255    GlobalContext.get().getXComponentController().setXComponentSurfaceSize({
256      surfaceWidth: size.width,
257      surfaceHeight: size.height
258    });
259    let previewProfiles = this.outputCapability.previewProfiles;
260    let previewProfile;
261    if (deviceInfo.deviceType == 'default') {
262      previewProfile = previewProfiles[0];
263    } else {
264      Log.info(`${TAG} previewProfiles length.` + previewProfiles.length);
265      previewProfile = previewProfiles.find(item => item.size.width === size.width &&
266        item.size.height === size.height && item.format === 1003);
267    }
268    await this.releasePreviewOutput();
269    try {
270      this.mPreviewOutput = this.mCameraManager.createPreviewOutput(previewProfile, surfaceId);
271    } catch (error) {
272      Log.error(`${TAG} createPreviewOutput failed: ${JSON.stringify(error)}`);
273      ReportUtil.writeFaultLog(error);
274    }
275    Log.end(`${TAG} createPreviewOutput`);
276  }
277
278  public async releasePreviewOutput() {
279    Log.start(`${TAG} releasePreviewOutput`);
280    if (this.mPreviewOutput) {
281      try {
282        await this.mPreviewOutput.release();
283        this.mPreviewOutput = null;
284      } catch (error) {
285        Log.error(`${TAG} releasePreviewOutput failed: ${JSON.stringify(error)}`);
286        ReportUtil.writeFaultLog(error);
287      }
288    }
289    Log.end(`${TAG} releasePreviewOutput`);
290  }
291
292  public async createPhotoOutput(functionCallback: FunctionCallBack) {
293    Log.start(`${TAG} createPhotoOutput`);
294    const size = SettingManager.getInstance().getImageSize();
295    Log.info(`${TAG} createPhotoOutput size.width = ${size.width} size.height = ${size.height}`);
296    this.mImageReceiver = image.createImageReceiver(size.width, size.height, image.ImageFormat.JPEG, 8);
297    const surfaceId = await this.mImageReceiver.getReceivingSurfaceId();
298    Log.info(`${TAG} createPhotoOutput surfaceId: ${surfaceId}.`);
299    let photoProfiles = this.outputCapability.photoProfiles;
300    let photoProfile;
301    if (deviceInfo.deviceType == 'default') {
302      photoProfile = photoProfiles[0];
303    } else {
304      Log.info(`${TAG} videoProfiles length.` + photoProfiles.length);
305      photoProfile = photoProfiles.find(item => item.size.width === size.width && item.size.height === size.height);
306    }
307    try {
308      this.mPhotoOutPut = this.mCameraManager.createPhotoOutput(photoProfile, surfaceId);
309    } catch (error) {
310      Log.error(`${TAG} createPhotoOutput failed: ${JSON.stringify(error)}`);
311      ReportUtil.writeFaultLog(error);
312    }
313    Log.info(`${TAG} createPhotoOutput mPhotoOutPut: ${this.mPhotoOutPut}.`);
314    this.mSaveCameraAsset.saveImage(this.mImageReceiver, 40, 40, this.mThumbnailGetter, functionCallback);
315    Log.end(`${TAG} createPhotoOutput`);
316  }
317
318  public async releasePhotoOutput() {
319    Log.start(`${TAG} releasePhotoOutput`);
320    if (this.mPhotoOutPut) {
321      try {
322        await this.mPhotoOutPut.release();
323        this.mPhotoOutPut = null;
324      } catch (error) {
325        Log.error(`${TAG} releasePhotoOutput failed: ${JSON.stringify(error)}`);
326        ReportUtil.writeFaultLog(error);
327      }
328    }
329    if (this.mImageReceiver) {
330      await this.mImageReceiver.release();
331      this.mImageReceiver = null;
332    }
333    Log.end(`${TAG} releasePhotoOutput`);
334  }
335
336  public async createSession(surfaceId: string, isVideo: boolean) {
337    Log.start(`${TAG} createSession`);
338    GlobalContext.get().setObject('isSessionCreating', true)
339    this.mCaptureSession = this.mCameraManager.createCaptureSession();
340    GlobalContext.get().setObject('isSessionCreating', false)
341    Log.info(`${TAG} createSession captureSession: ${this.mCaptureSession}, cameraInput: ${this.mCameraInput},
342    videoOutPut: ${this.mVideoOutput}, photoOutPut: ${this.mPhotoOutPut},  mPreviewOutput: ${this.mPreviewOutput}`);
343    Log.info(`${TAG} createSession beginConfig.`);
344    Log.start(Log.STREAM_DISTRIBUTION);
345    try {
346      this.mCaptureSession?.beginConfig();
347      await new Promise((resolve) => setTimeout(resolve, 1));
348      Log.info(`${TAG} createSession addInput.`);
349      this.mCaptureSession?.addInput(this.mCameraInput);
350      if (!isVideo) {
351        Log.info(`${TAG} createSession photo addOutput.`);
352        this.mCaptureSession?.addOutput(this.mPhotoOutPut);
353      }
354      Log.info(`${TAG} createSession preview addOutput.`);
355      this.mCaptureSession?.addOutput(this.mPreviewOutput);
356    } catch (error) {
357      Log.error(`${TAG} createSession failed: ${JSON.stringify(error)}`);
358      if (error) {
359        ReportUtil.write(ReportUtil.CAMERA_ERROR);
360      }
361    }
362    Log.info(`${TAG} createSession commitConfig.`);
363    Log.start(Log.OPEN_CAMERA);
364    try {
365      await this.mCaptureSession?.commitConfig();
366      Log.end(Log.OPEN_CAMERA);
367      Log.end(Log.STREAM_DISTRIBUTION);
368      await this.mCaptureSession?.start();
369    } catch (err) {
370      if (err) {
371        ReportUtil.write(ReportUtil.OPEN_FAIL);
372      }
373    }
374    if (GlobalContext.get().getT<boolean>('cameraStartFlag') &&
375      (new Date().getTime() - GlobalContext.get().getT<number>('cameraStartTime')) > 2000) {
376      ReportUtil.write(ReportUtil.START_TIMEOUT);
377    }
378    GlobalContext.get().setObject('cameraStartFlag', false);
379    Log.end(`${TAG} createSession`);
380  }
381
382  public async releaseSession() {
383    Log.start(`${TAG} releaseSession`);
384    if (this.mCaptureSession) {
385      try {
386        await this.mCaptureSession.stop();
387        await this.mCaptureSession.release();
388        this.mCaptureSession = null;
389      } catch (error) {
390        Log.error(`${TAG} releaseSession failed: ${JSON.stringify(error)}`);
391        ReportUtil.writeFaultLog(error);
392      }
393    }
394    Log.end(`${TAG} releaseSession`);
395  }
396
397  public async startPreview() {
398    Log.start(`${TAG} startPreview`);
399    if (!this.mCaptureSession) {
400      return;
401    }
402    try {
403      await this.mCaptureSession.start();
404    } catch (error) {
405      Log.error(`${TAG} startPreview failed: ${JSON.stringify(error)}`);
406      ReportUtil.writeFaultLog(error);
407    }
408    Log.end(`${TAG} startPreview`);
409  }
410
411  public async stopPreview() {
412    Log.start(`${TAG} stopPreview`);
413    if (!this.mCaptureSession) {
414      return;
415    }
416    try {
417      await this.mCaptureSession.stop();
418    } catch (error) {
419      Log.error(`${TAG} stopPreview failed: ${JSON.stringify(error)}`);
420      ReportUtil.writeFaultLog(error);
421    }
422    Log.end(`${TAG} stopPreview`);
423  }
424
425  public async takePicture() {
426    Log.start(`${TAG} takePicture`);
427    ReportUtil.write(ReportUtil.CAPTURE);
428    if (!this.mCaptureSession) {
429      Log.info(`${TAG} takePicture session is release`);
430      return;
431    }
432    if (!this.mPhotoOutPut) {
433      Log.info(`${TAG} takePicture photoOutPut is release`);
434      return;
435    }
436    if (this.mCameraId === CameraId.FRONT) {
437      this.mCaptureSetting.mirror = SettingManager.getInstance().getSelfMirror();
438    }
439    const locationData = SettingManager.getInstance().getCurGeoLocation();
440    if (locationData) {
441      this.mCaptureSetting.location = {
442        latitude: locationData.latitude,
443        longitude: locationData.longitude,
444        altitude: locationData.altitude
445      }
446    }
447    Log.info(`${TAG} takePicture captureSetting ${JSON.stringify(this.mCaptureSetting)}`);
448    // todo modify the location and mirror config
449    try {
450      this.mPhotoOutPut.capture(this.mCaptureSetting);
451    } catch (err) {
452      if (err) {
453        ReportUtil.write(ReportUtil.CAPTURE_FAIL);
454      }
455    }
456    Log.end(`${TAG} takePicture`);
457    if ((new Date().getTime() - GlobalContext.get().getT<number>('startCaptureTime')) > 2000) {
458      ReportUtil.write(ReportUtil.CAPTURE_TIMEOUT);
459    }
460  }
461
462  public async createVideoOutput(functionCallBack: VideoCallBack) {
463    Log.start(`${TAG} createVideoOutput`);
464    this.mFileAssetId = await this.mSaveCameraAsset.createVideoFd(functionCallBack);
465    if (this.mFileAssetId === undefined) {
466      Log.error(`${TAG} createVideoOutput error: mFileAssetId undefined`);
467      functionCallBack.onRecodeError('createVideoOutput error: mFileAssetId undefined');
468    }
469    this.mVideoConfig.url = `fd://${this.mFileAssetId.toString()}`;
470    await media.createAVRecorder().then((recorder) => {
471      Log.info(`${TAG} createVideoOutput createAVRecorder record: ${recorder}`);
472      this.mAVRecorder = recorder;
473    });
474    const size = SettingManager.getInstance().getVideoSize();
475    if (this.mAVRecorder != null) {
476      this.mAVRecorder.on('error', (error) => {
477        if (error) {
478          Log.error(`${TAG} createVideoOutput error: ${JSON.stringify(error)}`);
479          functionCallBack.onRecodeError(`createVideoOutput error: ${JSON.stringify(error)}`);
480        }
481      });
482      Log.info(`${TAG} createVideoOutput size = ${JSON.stringify(size)}`);
483      this.mVideoConfig.profile.videoFrameWidth = size.width;
484      this.mVideoConfig.profile.videoFrameHeight = size.height;
485      const locationData = SettingManager.getInstance().getCurGeoLocation();
486      if (locationData) {
487        this.mVideoConfig.location = {
488          latitude: locationData.latitude,
489          longitude: locationData.longitude
490        };
491      }
492
493      if (deviceInfo.deviceType != 'tablet') {
494        if (this.curCameraName === 'BACK') {
495          this.mVideoConfig.rotation = 90;
496        } else {
497          this.mVideoConfig.rotation = 270;
498        }
499      }
500      Log.info(`${TAG} createVideoOutput mVideoConfig =  ${JSON.stringify(this.mVideoConfig)}.`);
501      await this.mAVRecorder.prepare(this.mVideoConfig);
502      Log.info(`${TAG} createVideoOutput AVRecorder.prepare succeed.`);
503    } else {
504      Log.error(`${TAG} createVideoOutput createAVRecorder failed.`);
505      return;
506    }
507
508    let profileVideo;
509    if (deviceInfo.deviceType == 'default') {
510      profileVideo = this.outputCapability.videoProfiles[0];
511    } else {
512      let videoProfiles = this.outputCapability.videoProfiles;
513      Log.info(`${TAG} videoProfiles length.` + videoProfiles.length);
514      profileVideo = videoProfiles.find(item =>
515      item.size.width === size.width && item.size.height === size.height
516        && item.frameRateRange.min === DEFAULT_VIDEO_FRAME_RATE && item.frameRateRange.max === DEFAULT_VIDEO_FRAME_RATE
517      );
518    }
519
520    const videoId = await this.mAVRecorder.getInputSurface();
521    Log.info(`${TAG} createVideoOutput profileVideo =  ${JSON.stringify(profileVideo)}.`);
522    try {
523      this.mVideoOutput = this.mCameraManager.createVideoOutput(profileVideo, videoId);
524    } catch (error) {
525      Log.error(`${TAG} createVideoOutput failed: ${JSON.stringify(error)}`);
526      ReportUtil.writeFaultLog(error);
527    }
528    Log.end(`${TAG} createVideoOutput`);
529  }
530
531  public async releaseVideoOutput() {
532    Log.start(`${TAG} releaseVideoOutput`);
533    if (this.mVideoOutput) {
534      Log.info(`${TAG} releaseVideoOutput start`);
535      try {
536        await this.mVideoOutput.release();
537      } catch (error) {
538        Log.error(`${TAG} releaseVideoOutput failed: ${JSON.stringify(error)}`);
539        ReportUtil.writeFaultLog(error);
540      }
541      Log.info(`${TAG} releaseVideoOutput end`);
542      this.mVideoOutput = null;
543    }
544    Log.end(`${TAG} releaseVideoOutput`);
545  }
546
547  public async StartRecording(functionCallBack: VideoCallBack) {
548    let startRecordingTime = new Date().getTime();
549    Log.start(`${TAG} StartRecording`);
550    Log.info(`${TAG} StartRecording codec ${this.mVideoConfig.profile.videoCodec}`);
551    ReportUtil.write(ReportUtil.VIDEO_RECORD);
552    try {
553      await this.mCaptureSession.stop();
554      this.mCaptureSession.beginConfig();
555      if (this.mVideoOutput) {
556        await this.mCaptureSession.removeOutput(this.mVideoOutput);
557        Log.info(`${TAG} old videoOutput has been removed.`);
558      }
559      await this.createVideoOutput(functionCallBack);
560      this.mCaptureSession.addOutput(this.mVideoOutput);
561      Log.info(`${TAG} StartRecording addOutput finished.`);
562      await this.mCaptureSession.commitConfig();
563      Log.info(`${TAG} StartRecording commitConfig finished.`);
564      await this.mCaptureSession.start();
565      Log.info(`${TAG} StartRecording Session.start finished.`);
566    } catch (err) {
567      GlobalContext.get().setObject('startRecordingFlag', false);
568      ReportUtil.writeFaultLog(error);
569      Log.error(`${TAG} remove videoOutput ${err}`);
570    }
571    await this.mVideoOutput.start().then(() => {
572      Log.info(`${TAG} videoOutput.start()`);
573    });
574    await this.mAVRecorder.start().then(() => {
575      Log.info(`${TAG} AVRecorder.start()`);
576    });
577    this.mIsStartRecording = true;
578    if (new Date().getTime() - startRecordingTime > 2000) {
579      ReportUtil.write(ReportUtil.START_RECORD_TIMEOUT);
580    }
581    Log.end(`${TAG} StartRecording`);
582  }
583
584  public async stopRecording(): Promise<PixelMap | undefined> {
585    Log.start(Log.STOP_RECORDING);
586    let stopRecordingTime = new Date().getTime();
587    ReportUtil.write(ReportUtil.STOP_RECORD);
588    if (!this.mVideoOutput || !this.mAVRecorder) {
589      Log.error(`${TAG} stopRecording error videoOutPut: ${this.mVideoOutput},
590              AVRecorder: ${this.mAVRecorder} .`);
591      return undefined;
592    }
593    this.mIsStartRecording = false;
594    try {
595      await this.mAVRecorder.stop();
596      await this.mAVRecorder.release();
597    } catch (err) {
598      Log.error(`${TAG} stop AVRecorder ${err}`);
599    }
600
601    try {
602      await this.mVideoOutput.stop();
603    } catch (err) {
604      Log.error(`${TAG} stop videoOutput ${err}`);
605    }
606
607    if (this.mFileAssetId != undefined) {
608      await this.mSaveCameraAsset.videoPrepareFile.close(this.mFileAssetId);
609      this.mFileAssetId = undefined;
610      Log.info(`${TAG} fileAsset.close().`);
611    }
612    Log.start(Log.UPDATE_VIDEO_THUMBNAIL);
613    const thumbnailPixelMap: PixelMap | undefined = await this.mThumbnailGetter.getThumbnailInfo(40, 40);
614    Log.end(Log.UPDATE_VIDEO_THUMBNAIL);
615    if (new Date().getTime() - stopRecordingTime > 2000) {
616      ReportUtil.write(ReportUtil.FINISH_RECORD_TIMEOUT);
617    }
618    Log.end(Log.STOP_RECORDING);
619    return thumbnailPixelMap;
620  }
621
622  public async pauseRecording() {
623    Log.start(`${TAG} pauseRecording`);
624    if (!this.mVideoOutput || !this.mAVRecorder) {
625      Log.error(`${TAG} pauseRecording error videoOutPut: ${this.mVideoOutput},
626              AVRecorder: ${this.mAVRecorder} .`);
627      return;
628    }
629    try {
630      await this.mAVRecorder.pause();
631      await this.mVideoOutput.stop();
632    } catch (error) {
633      Log.error(`${TAG} pauseRecording failed: ${JSON.stringify(error)}`);
634    }
635    Log.end(`${TAG} pauseRecording`);
636  }
637
638  public async resumeRecording() {
639    Log.start(`${TAG} resumeRecording`);
640    if (!this.mVideoOutput || !this.mAVRecorder) {
641      Log.error(`${TAG} resumeRecording error videoOutPut: ${this.mVideoOutput},
642              AVRecorder: ${this.mAVRecorder} .`);
643      return;
644    }
645    await this.mVideoOutput.start().then(() => {
646      Log.info(`${TAG} videoOutput.start()`);
647    }).catch((error) => {
648      Log.error(`${TAG} resumeRecording mVideoOutput start failed: ${JSON.stringify(error)}`);
649    });
650    await this.mAVRecorder.resume();
651    Log.end(`${TAG} resumeRecording`);
652  }
653
654  public async releaseRecording() {
655    Log.start(`${TAG} releaseRecording`);
656    if (!this.mAVRecorder) {
657      Log.info(`${TAG} AVRecorder has not been created.`);
658      return;
659    }
660    if (this.mIsStartRecording) {
661      await this.stopRecording();
662    }
663    await this.mAVRecorder.release().then(() => {
664      Log.info(`${TAG} AVRecorder.release() success.`);
665      this.mAVRecorder = undefined;
666    });
667    Log.end(`${TAG} releaseRecording`);
668  }
669
670  public async releaseCamera() {
671    Log.start(`${TAG} releaseCamera`);
672    await this.releaseRecording();
673    await this.releaseVideoOutput();
674    await this.releasePhotoOutput();
675    await this.releaseSession();
676    Log.end(`${TAG} releaseCamera`);
677  }
678
679  public async setZoomRatio(zoomRatio: number) {
680    Log.info(`${TAG} setZoomRatio invoke E ${zoomRatio}`);
681    if (!this.mCaptureSession) {
682      Log.info(`${TAG} setZoomRatio mCaptureSession is release`);
683      return;
684    }
685    try {
686      this.mCaptureSession.setZoomRatio(zoomRatio);
687    } catch (error) {
688      Log.error(`${TAG} setZoomRatio failed: ${JSON.stringify(error)}`);
689    }
690    Log.info(`${TAG} setZoomRatio invoke X.`);
691  }
692
693  public async getZoomRatio(): Promise<number> {
694    Log.info(`${TAG} getZoomRatio invoke E.`);
695    if (!this.mCaptureSession) {
696      Log.info(`${TAG} getZoomRatio mCaptureSession is release`);
697      return 1;
698    }
699    Log.info(`${TAG} getZoomRatio invoke X.`);
700    return this.mCaptureSession.getZoomRatio();
701  }
702
703  public async setVideoConfig(videoConfig: any) {
704    Log.info(`${TAG} setVideoConfig invoke E.`);
705    if (videoConfig) {
706      this.mVideoConfig = videoConfig;
707    } else {
708      Log.info(`${TAG} setVideoConfig videoConfig is null.`);
709    }
710    Log.info(`${TAG} setVideoConfig invoke X.`);
711  }
712
713  public async setCaptureSetting(captureSetting: any) {
714    Log.info(`${TAG} setCaptureSetting invoke E.`);
715    if (captureSetting) {
716      this.mCaptureSetting = captureSetting;
717    } else {
718      Log.info(`${TAG} setCaptureSetting captureSetting is null.`);
719    }
720    Log.info(`${TAG} setCaptureSetting invoke X.`);
721  }
722
723  public getThumbnail(functionCallBack: FunctionCallBack): image.PixelMap {
724    Log.start(`${TAG} getThumbnail`);
725    this.mThumbnailGetter.getThumbnailInfo(40, 40).then((thumbnail) => {
726      functionCallBack.thumbnail(thumbnail);
727      Log.end(`${TAG} getThumbnail`);
728    });
729    return this.mThumbnail;
730  }
731
732  public getCameraName(): string {
733    return this.curCameraName;
734  }
735
736  public setCameraId(name: string): void {
737    this.curCameraName = name;
738  }
739
740  public getPhotoUri() {
741    return this.mSaveCameraAsset.getPhotoUri();
742  }
743
744  public getRecentFileUri(): string {
745    return this.mThumbnailGetter.getRecentFileUri();
746  }
747
748  private async getCameraLists() {
749    const cameras = this.mCameraManager.getSupportedCameras();
750    this.camerasCache = cameras;
751    return cameras;
752  }
753}