• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2022 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
16import camera from '@ohos.multimedia.camera'
17import deviceInfo from '@ohos.deviceInfo'
18import fileio from '@ohos.file.fs'
19import image from '@ohos.multimedia.image'
20import media from '@ohos.multimedia.media'
21import userFileManager from '@ohos.filemanagement.userFileManager'
22import Logger from '../model/Logger'
23import MediaUtils, { FileType } from '../model/MediaUtils'
24
25const CameraMode = {
26  MODE_PHOTO: 0, // 拍照模式
27  MODE_VIDEO: 1 // 录像模式
28}
29
30const CameraSize = {
31  WIDTH: 1920,
32  HEIGHT: 1080
33}
34
35export default class CameraService {
36  private tag: string = 'CameraService'
37  private context: any = undefined
38  private mediaUtil: MediaUtils = undefined
39  private cameraManager: camera.CameraManager = undefined
40  private cameras: Array<camera.CameraDevice> = undefined
41  private cameraId: string = ''
42  private cameraInput: camera.CameraInput = undefined
43  private previewOutput: camera.PreviewOutput = undefined
44  private photoOutPut: camera.PhotoOutput = undefined
45  private captureSession: camera.CaptureSession = undefined
46  private mReceiver: image.ImageReceiver = undefined
47  private photoUri: string = ''
48  private fileAsset: userFileManager.FileAsset = undefined
49  private fd: number = -1
50  private curMode = CameraMode.MODE_PHOTO
51  private videoRecorder: media.VideoRecorder = undefined
52  private videoOutput: camera.VideoOutput = undefined
53  private handleTakePicture: (photoUri: string) => void = undefined
54  private cameraOutputCapability: camera.CameraOutputCapability = undefined
55  private videoConfig: any = {
56    audioSourceType: 1,
57    videoSourceType: 0,
58    profile: {
59      audioBitrate: 48000,
60      audioChannels: 2,
61      audioCodec: 'audio/mp4v-es',
62      audioSampleRate: 48000,
63      durationTime: 1000,
64      fileFormat: 'mp4',
65      videoBitrate: 48000,
66      videoCodec: 'video/mp4v-es',
67      videoFrameWidth: 640,
68      videoFrameHeight: 480,
69      videoFrameRate: 30
70    },
71    url: '',
72    orientationHint: 0,
73    location: {
74      latitude: 30, longitude: 130
75    },
76    maxSize: 10000,
77    maxDuration: 10000
78  }
79
80  constructor(context: any) {
81    this.context = context
82    this.mediaUtil = MediaUtils.getInstance(context)
83    this.mReceiver = image.createImageReceiver(CameraSize.WIDTH, CameraSize.HEIGHT, 4, 8)
84    Logger.info(this.tag, 'createImageReceiver')
85    this.mReceiver.on('imageArrival', () => {
86      Logger.info(this.tag, 'imageArrival')
87      this.mReceiver.readNextImage((err, image) => {
88        Logger.info(this.tag, 'readNextImage')
89        if (err || image === undefined) {
90          Logger.error(this.tag, 'failed to get valid image')
91          return
92        }
93        image.getComponent(4, (errMsg, img) => {
94          Logger.info(this.tag, 'getComponent')
95          if (errMsg || img === undefined) {
96            Logger.info(this.tag, 'failed to get valid buffer')
97            return
98          }
99          let buffer = new ArrayBuffer(4096)
100          if (img.byteBuffer) {
101            buffer = img.byteBuffer
102          } else {
103            Logger.error(this.tag, 'img.byteBuffer is undefined')
104          }
105          this.savePicture(buffer, image)
106        })
107      })
108    })
109  }
110
111  async savePicture(buffer: ArrayBuffer, img: image.Image) {
112    Logger.info(this.tag, 'savePicture')
113    this.fileAsset = await this.mediaUtil.createAndGetUri(FileType.IMAGE)
114    this.photoUri = this.fileAsset.uri
115    Logger.info(this.tag, `this.photoUri = ${this.photoUri}`)
116    this.fd = await this.mediaUtil.getFdPath(this.fileAsset)
117    Logger.info(this.tag, `this.fd = ${this.fd}`)
118    await fileio.write(this.fd, buffer)
119    await this.fileAsset.close(this.fd)
120    await img.release()
121    Logger.info(this.tag, 'save image done')
122    if (this.handleTakePicture) {
123      this.handleTakePicture(this.photoUri)
124    }
125  }
126
127  async initCamera(surfaceId: string) {
128    Logger.info(this.tag, 'initCamera')
129    await this.releaseCamera()
130    Logger.info(this.tag, `deviceInfo.deviceType = ${deviceInfo.deviceType}`)
131    if (deviceInfo.deviceType === 'default') {
132      this.videoConfig.videoSourceType = 1
133    } else {
134      this.videoConfig.videoSourceType = 0
135    }
136    this.cameraManager = camera.getCameraManager(this.context)
137    Logger.info(this.tag, 'getCameraManager')
138    this.cameras = this.cameraManager.getSupportedCameras()
139    Logger.info(this.tag, `get cameras ${this.cameras.length}`)
140    if (this.cameras.length === 0) {
141      Logger.info(this.tag, 'cannot get cameras')
142      return
143    }
144
145    let cameraDevice = this.cameras[0]
146    this.cameraInput = this.cameraManager.createCameraInput(cameraDevice)
147    this.cameraInput.open()
148    Logger.info(this.tag, 'createCameraInput')
149    this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(cameraDevice)
150    let previewProfile = this.cameraOutputCapability.previewProfiles[0]
151    this.previewOutput = this.cameraManager.createPreviewOutput(previewProfile, surfaceId)
152    Logger.info(this.tag, 'createPreviewOutput')
153    let mSurfaceId = await this.mReceiver.getReceivingSurfaceId()
154    let profile = this.cameraOutputCapability.photoProfiles[0]
155    this.photoOutPut = this.cameraManager.createPhotoOutput(profile, mSurfaceId)
156    this.captureSession = this.cameraManager.createCaptureSession()
157    Logger.info(this.tag, 'createCaptureSession')
158    this.captureSession.beginConfig()
159    Logger.info(this.tag, 'beginConfig')
160    this.captureSession.addInput(this.cameraInput)
161    this.captureSession.addOutput(this.previewOutput)
162    this.captureSession.addOutput(this.photoOutPut)
163    await this.captureSession.commitConfig()
164    await this.captureSession.start()
165    Logger.info(this.tag, 'captureSession start')
166  }
167
168  setTakePictureCallback(callback) {
169    this.handleTakePicture = callback
170  }
171
172  async takePicture() {
173    Logger.info(this.tag, 'takePicture')
174    if (this.curMode === CameraMode.MODE_VIDEO) {
175      this.curMode = CameraMode.MODE_PHOTO
176    }
177    let photoSettings = {
178      rotation: camera.ImageRotation.ROTATION_0,
179      quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
180      location: { // 位置信息,经纬度
181        latitude: 12.9698,
182        longitude: 77.7500,
183        altitude: 1000
184      },
185      mirror: false
186    }
187    await this.photoOutPut.capture(photoSettings)
188    Logger.info(this.tag, 'takePicture done')
189  }
190
191  async startVideo() {
192    Logger.info(this.tag, 'startVideo begin')
193    await this.captureSession.stop()
194    this.captureSession.beginConfig()
195    if (this.curMode === CameraMode.MODE_PHOTO) {
196      this.curMode = CameraMode.MODE_VIDEO
197      if (this.photoOutPut) {
198        this.captureSession.removeOutput(this.photoOutPut)
199        this.photoOutPut.release()
200      }
201    } else {
202      if (this.videoOutput) {
203        this.captureSession.removeOutput(this.videoOutput)
204      }
205    }
206    if (this.videoOutput) {
207      this.captureSession.removeOutput(this.videoOutput)
208      await this.videoOutput.release()
209    }
210    this.fileAsset = await this.mediaUtil.createAndGetUri(FileType.VIDEO)
211    this.fd = await this.mediaUtil.getFdPath(this.fileAsset)
212    this.videoRecorder = await media.createVideoRecorder()
213    this.videoConfig.url = `fd://${this.fd}`
214    await this.videoRecorder.prepare(this.videoConfig)
215    let videoId = await this.videoRecorder.getInputSurface()
216    let profile = this.cameraOutputCapability.videoProfiles[0];
217    this.videoOutput = this.cameraManager.createVideoOutput(profile, videoId)
218    this.captureSession.addOutput(this.videoOutput)
219    await this.captureSession.commitConfig()
220    await this.captureSession.start()
221    await this.videoOutput.start()
222    await this.videoRecorder.start()
223    Logger.info(this.tag, 'startVideo end')
224  }
225
226  async stopVideo() {
227    Logger.info(this.tag, 'stopVideo called')
228    await this.videoRecorder.stop()
229    await this.videoOutput.stop()
230    await this.videoRecorder.release()
231    await this.fileAsset.close(this.fd)
232  }
233
234  async releaseCamera() {
235    Logger.info(this.tag, 'releaseCamera')
236    if (this.cameraInput) {
237      await this.cameraInput.close()
238    }
239    if (this.previewOutput) {
240      await this.previewOutput.release()
241    }
242    if (this.photoOutPut) {
243      await this.photoOutPut.release()
244    }
245    if (this.videoOutput) {
246      await this.videoOutput.release()
247    }
248    if (this.captureSession) {
249      await this.captureSession.release()
250    }
251  }
252}