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}