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