camera.md 14.6 KB
Newer Older
T
tongxu-liu1 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# 相机开发指导

## 场景介绍

相机模块支持相机相关基础功能的开发,主要包括预览、拍照、录像等。本文将对相机各种基础功能的开发进行介绍说明。

## 开发步骤

### 接口说明

详细API含义请参考:[相机管理API文档](../reference/apis/js-apis-camera.md)

### 全流程场景

包含流程:创建实例、参数设置、会话管理、拍照、录像、释放资源等。

T
tongxu-liu1 已提交
17
Xcomponent创建方法可参考:[XComponent创建方法](#xcomponent创建方法)
T
tongxu-liu1 已提交
18

T
tongxu-liu1 已提交
19 20
拍照保存接口可参考:[图片处理API文档](../reference/apis/js-apis-image.md)

T
tongxu-liu1 已提交
21 22 23
#### 创建实例

```js
T
tongxu-liu1 已提交
24 25 26
import camera from '@ohos.multimedia.camera'
import image from '@ohos.multimedia.image'
import media from '@ohos.multimedia.media'
T
tongxu-liu1 已提交
27 28
import featureAbility from '@ohos.ability.featureAbility'

29
// 创建CameraManager对象
T
tongxu-liu1 已提交
30 31 32 33 34 35 36 37 38 39
let cameraManager
await camera.getCameraManager(globalThis.Context, (err, manager) => {
    if (err) {
        console.error('Failed to get the CameraManager instance ${err.message}');
        return;
    }
    console.log('Callback returned with the CameraManager instance');
    cameraManager = manager
})

40
// 注册回调函数监听相机状态变化,获取状态变化的相机信息
T
tongxu-liu1 已提交
41 42 43 44 45
cameraManager.on('cameraStatus', (cameraStatusInfo) => {
    console.log('camera : ' + cameraStatusInfo.camera.cameraId);
    console.log('status: ' + cameraStatusInfo.status);
})

46
// 获取相机列表
T
tongxu-liu1 已提交
47 48 49 50 51 52 53 54 55 56
let cameraArray
await cameraManager.getCameras((err, cameras) => {
    if (err) {
        console.error('Failed to get the cameras. ${err.message}');
        return;
    }
    console.log('Callback returned with an array of supported cameras: ' + cameras.length);
    cameraArray = cameras
})

57
for(let cameraIndex = 0; cameraIndex < cameraArray.length; cameraIndex++) {
58 59 60 61
    console.log('cameraId : ' + cameraArray[cameraIndex].cameraId)                          // 获取相机ID
    console.log('cameraPosition : ' + cameraArray[cameraIndex].cameraPosition)              // 获取相机位置
    console.log('cameraType : ' + cameraArray[cameraIndex].cameraType)                      // 获取相机类型
    console.log('connectionType : ' + cameraArray[cameraIndex].connectionType)              // 获取相机连接类型
Mr-YX's avatar
Mr-YX 已提交
62 63
}

64
// 创建相机输入流
Mr-YX's avatar
Mr-YX 已提交
65 66
let cameraInput
await cameraManager.createCameraInput(cameraArray[0].cameraId).then((input) => {
T
tongxu-liu1 已提交
67 68 69 70
    console.log('Promise returned with the CameraInput instance');
    cameraInput = input
})

71
// 创建预览输出流
T
tongxu-liu1 已提交
72 73 74 75 76 77 78 79 80 81
let previewOutput
camera.createPreviewOutput((globalThis.surfaceId), (err, output) => {
    if (err) {
        console.error('Failed to create the PreviewOutput instance. ${err.message}');
        return;
    }
    console.log('Callback returned with previewOutput instance');
    previewOutput = output
});

82
// 创建ImageReceiver对象,并设置照片参数
T
tongxu-liu1 已提交
83
let imageReceiver = await image.createImageReceiver(1920, 1080, 4, 8)
84
// 获取照片显示SurfaceId
T
tongxu-liu1 已提交
85
let photoSurfaceId = await imageReceiver.getReceivingSurfaceId()
86
// 创建拍照输出流
T
tongxu-liu1 已提交
87 88 89 90 91 92 93 94 95 96
let photoOutput
camera.createPhotoOutput((photoSurfaceId), (err, output) => {
    if (err) {
        console.error('Failed to create the PhotoOutput instance. ${err.message}');
        return;
    }
    console.log('Callback returned with the PhotoOutput instance.');
    photoOutput = output
});

97
// 创建视频录制的参数
T
tongxu-liu1 已提交
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
let videoProfile = {
    audioBitrate : 48000,
    audioChannels : 2,
    audioCodec : 'audio/mp4a-latm',
    audioSampleRate : 48000,
    fileFormat : 'mp4',
    videoBitrate : 48000,
    videoCodec : 'video/mp4v-es',
    videoFrameWidth : 640,
    videoFrameHeight : 480,
    videoFrameRate : 30
}
let videoConfig = {
    audioSourceType : 1,
    videoSourceType : 0,
    profile : videoProfile,
    url : 'file:///data/media/01.mp4',
    orientationHint : 0,
    location : { latitude : 30, longitude : 130 },
}

119
// 创建录像输出流
T
tongxu-liu1 已提交
120 121 122 123 124
let videoRecorder
await media.createVideoRecorder().then((recorder) => {
    console.log('createVideoRecorder called')
    videoRecorder = recorder
})
125
// 设置视频录制的参数
T
tongxu-liu1 已提交
126 127 128 129 130 131 132 133 134
await videoRecorder.prepare(videoConfig)
//获取录像SurfaceId
await videoRecorder.getInputSurface().then((id) => {
    console.log('getInputSurface called')
    videoSurfaceId = id
})
```
videoRecorder详细创建方法可参考:[视频录制开发指导](./video-recorder.md)
```js
135
// 创建VideoOutput对象
T
tongxu-liu1 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
let videoOutput
camera.createVideoOutput((surfaceId), (err, output) => {
    if (err) {
        console.error('Failed to create the VideoOutput instance. ${err.message}');
        return;
    }
    console.log('Callback returned with the VideoOutput instance');
    videoOutput = output
});

```

#### 参数设置

```js
151
// 判断设备是否支持闪光灯
T
tongxu-liu1 已提交
152 153 154 155 156 157
let flashStatus
await cameraInput.hasFlash().then((status) => {
    console.log('Promise returned with the flash light support status:' + status);
    flashStatus = status
})
if(flashStatus) {
158
    // 判断是否支持自动闪光灯模式
T
tongxu-liu1 已提交
159 160 161 162 163 164 165 166 167 168
    let flashModeStatus
    cameraInput.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO, (err, status) => {
        if (err) {
            console.error('Failed to check whether the flash mode is supported. ${err.message}');
            return;
        }
        console.log('Callback returned with the flash mode support status: ' + status);
        flashModeStatus = status
    })
    if(flashModeStatus) {
169
        // 设置自动闪光灯模式
T
tongxu-liu1 已提交
170 171 172 173 174 175 176 177 178 179
        cameraInput.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO, (err) => {
            if (err) {
                console.error('Failed to set the flash mode  ${err.message}');
                return;
            }
            console.log('Callback returned with the successful execution of setFlashMode.');
        })
    }
}

180
// 判断是否支持连续自动变焦模式
T
tongxu-liu1 已提交
181 182 183 184 185 186 187 188 189 190
let focusModeStatus
cameraInput.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err, status) => {
    if (err) {
        console.error('Failed to check whether the focus mode is supported. ${err.message}');
        return;
    }
    console.log('Callback returned with the focus mode support status: ' + status);
    focusModeStatus = status
})
if(focusModeStatus) {
191
    // 设置连续自动变焦模式
T
tongxu-liu1 已提交
192 193 194 195 196 197 198 199 200
    cameraInput.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO, (err) => {
        if (err) {
            console.error('Failed to set the focus mode  ${err.message}');
            return;
        }
        console.log('Callback returned with the successful execution of setFocusMode.');
    })
}

201
// 获取相机支持的可变焦距比范围
T
tongxu-liu1 已提交
202 203 204 205 206 207 208 209 210 211
let zoomRatioRange
cameraInput.getZoomRatioRange((err, range) => {
    if (err) {
        console.error('Failed to get the zoom ratio range. ${err.message}');
        return;
    }
    console.log('Callback returned with zoom ratio range: ' + range.length);
    zoomRatioRange = range
})

212
// 设置可变焦距比
T
tongxu-liu1 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226
cameraInput.setZoomRatio(zoomRatioRange[0], (err) => {
    if (err) {
        console.error('Failed to set the zoom ratio value ${err.message}');
        return;
    }
    console.log('Callback returned with the successful execution of setZoomRatio.');
})
```

#### 会话管理

##### 创建会话

```js
227
// 创建Context对象
T
tongxu-liu1 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240
let context = featureAbility.getContext()

//创建会话
let captureSession
await camera.createCaptureSession((context), (err, session) => {
    if (err) {
        console.error('Failed to create the CaptureSession instance. ${err.message}');
        return;
    }
    console.log('Callback returned with the CaptureSession instance.' + session);
    captureSession = session
});

241
// 开始配置会话
T
tongxu-liu1 已提交
242 243 244 245 246 247 248 249
await captureSession.beginConfig((err) => {
    if (err) {
        console.error('Failed to start the configuration. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the begin config success.');
});

250
// 向会话中添加相机输入流
T
tongxu-liu1 已提交
251 252 253 254 255 256 257 258
await captureSession.addInput(cameraInput, (err) => {
    if (err) {
        console.error('Failed to add the CameraInput instance. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the CameraInput instance is added.');
});

259
// 向会话中添加预览输入流
T
tongxu-liu1 已提交
260 261 262 263 264 265 266 267
await captureSession.addOutput(previewOutput, (err) => {
    if (err) {
        console.error('Failed to add the PreviewOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the PreviewOutput instance is added.');
});

268
// 向会话中添加拍照输出流
T
tongxu-liu1 已提交
269 270 271 272 273 274 275 276
await captureSession.addOutput(photoOutput, (err) => {
    if (err) {
        console.error('Failed to add the PhotoOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the PhotoOutput instance is added.');
});

277
// 提交会话配置
T
tongxu-liu1 已提交
278 279 280 281 282 283 284 285
await captureSession.commitConfig((err) => {
    if (err) {
        console.error('Failed to commit the configuration. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the commit config success.');
});

286
// 启动会话
T
tongxu-liu1 已提交
287 288 289 290 291 292 293 294
await captureSession.start().then(() => {
    console.log('Promise returned to indicate the session start success.');
})
```

##### 切换会话

```js
295
// 停止当前会话
T
tongxu-liu1 已提交
296 297 298 299 300 301 302 303
await captureSession.stop((err) => {
    if (err) {
        console.error('Failed to stop the session ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the session stop success.');
});

304
// 开始配置会话
T
tongxu-liu1 已提交
305 306 307 308 309 310 311 312
await captureSession.beginConfig((err) => {
    if (err) {
        console.error('Failed to start the configuration. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the begin config success.');
});

313
// 从会话中移除拍照输出流
T
tongxu-liu1 已提交
314 315 316 317 318 319 320 321
await captureSession.removeOutput(photoOutput, (err) => {
    if (err) {
        console.error('Failed to remove the PhotoOutput instance. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the PhotoOutput instance is removed.');
});

322
// 向会话中添加录像输出流
T
tongxu-liu1 已提交
323 324 325 326 327 328 329 330
await captureSession.addOutput(videoOutput, (err) => {
    if (err) {
        console.error('Failed to add the VideoOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the VideoOutput instance is added.');
});

331
// 提交会话配置
T
tongxu-liu1 已提交
332 333 334 335 336 337 338 339
await captureSession.commitConfig((err) => {
    if (err) {
        console.error('Failed to commit the configuration. ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the commit config success.');
});

340
// 启动会话
T
tongxu-liu1 已提交
341 342 343 344 345 346 347 348 349
await captureSession.start().then(() => {
    console.log('Promise returned to indicate the session start success.');
})
```

#### 拍照

```js
let settings = {
350 351
    quality: camera.QualityLevel.QUALITY_LEVEL_HIGH,                                     // 设置图片质量高
    rotation: camera.ImageRotation.ROTATION_0                                            // 设置图片旋转角度0
T
tongxu-liu1 已提交
352
}
353
// 使用当前拍照设置进行拍照
T
tongxu-liu1 已提交
354 355 356 357 358 359 360 361 362 363 364 365
photoOutput.capture(settings, (err) => {
    if (err) {
        console.error('Failed to capture the photo ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the photo capture request success.');
});
```

#### 录像

```js
366
// 启动录像输出流
T
tongxu-liu1 已提交
367 368 369 370 371 372 373 374
videoOutput.start((err) => {
    if (err) {
        console.error('Failed to start the video output ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the video output start success.');
});

375
// 开始录像
T
tongxu-liu1 已提交
376 377 378 379
await videoRecorder.start().then(() => {
    console.info('videoRecorder start success');
}

380
// 停止录像
T
tongxu-liu1 已提交
381 382 383 384
await videoRecorder.stop().then(() => {
    console.info('stop success');
}

385
// 停止录像输出流
T
tongxu-liu1 已提交
386 387 388 389 390 391 392 393 394 395 396 397
await videoOutput.stop((err) => {
    if (err) {
        console.error('Failed to stop the video output ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the video output stop success.');
});
```

#### 释放资源

```js
398
// 停止当前会话
T
tongxu-liu1 已提交
399 400 401 402 403 404 405
await captureSession.stop((err) => {
    if (err) {
        console.error('Failed to stop the session ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate the session stop success.');
});
406
// 释放相机输入流
T
tongxu-liu1 已提交
407 408 409 410 411 412 413
await cameraInput.release((err) => {
    if (err) {
        console.error('Failed to release the CameraInput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the CameraInput instance is released successfully.');
});
414
// 释放预览输出流
T
tongxu-liu1 已提交
415 416 417 418 419 420 421
await previewOutput.release((err) => {
    if (err) {
        console.error('Failed to release the PreviewOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the PreviewOutput instance is released successfully.');
});
422
// 释放拍照输出流
T
tongxu-liu1 已提交
423 424 425 426 427 428 429
await photoOutput.release((err) => {
    if (err) {
        console.error('Failed to release the PhotoOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the PhotoOutput instance is released successfully.');
});
430
// 释放录像输出流
T
tongxu-liu1 已提交
431 432 433 434 435 436 437
await videoOutput.release((err) => {
    if (err) {
        console.error('Failed to release the VideoOutput instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the VideoOutput instance is released successfully.');
});
438
// 释放会话
T
tongxu-liu1 已提交
439 440 441 442 443 444 445
await captureSession.release((err) => {
    if (err) {
        console.error('Failed to release the CaptureSession instance ${err.message}');
        return;
    }
    console.log('Callback invoked to indicate that the CaptureSession instance is released successfully.');
});
T
tongxu-liu1 已提交
446 447 448 449 450 451
```

#### XComponent创建方法
预览画面显示需要获取SurfaceId

```js
452
mXComponentController: XComponentController = new XComponentController                   // 创建XComponentController
T
tongxu-liu1 已提交
453 454 455

build() {
    Flex() {
456
        XComponent({                                                                     // 创建XComponent
T
tongxu-liu1 已提交
457 458 459 460 461
            id: '',
            type: 'surface',
            libraryname: '',
            controller: this.mXComponentController
        })
462 463
        .onload(() => {                                                                  // 设置onload回调
            // 设置Surface宽高(1920*1080)
T
tongxu-liu1 已提交
464
            this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080})
465
            // 获取Surface ID
T
tongxu-liu1 已提交
466 467
            globalThis.surfaceId = mXComponentController.getXComponentSurfaceId()
        })
468 469
        .width('1920px')                                                                 // 设置XComponent宽度
        .height('1080px')                                                                // 设置XComponent高度
T
tongxu-liu1 已提交
470 471
    }
}
T
tongxu-liu1 已提交
472
```