当前位置:   article > 正文

OpenHarmony相机开发_openharmony camera

openharmony camera

1、OpenHarmony相机开发简介

         OpenHarmony相机模块支持相机业务的开发,开发者可以通过已开放的接口实现相机硬件的访问、操作和新功能开发,最常见的操作如:预览、拍照和录像等。开发者也可以通过合适的接口或者接口组合实现闪光灯控制、曝光时间控制、手动对焦和自动对焦控制、变焦控制以及更多的功能。

开发者在调用Camera能力时,需要了解Camera的一些基本概念:

  • 相机静态能力:用于描述相机的固有能力的一系列参数,比如朝向、支持的分辨率等信息。
  • 物理相机:物理相机就是独立的实体摄像头设备。物理相机ID是用于标志每个物理摄像头的唯一字串。
  • 异步操作:为保证UI线程不被阻塞,部分Camera接口采用异步调用方式。异步方式API均提供了callback函数和Promise函数。

2、OpenHarmony相机开发流程及接口说明

        接口说明

        详细API含义请参考:相机管理API文档

 

参考代码如下: 

  1. const PERMISSIONS: Array<string> = [
  2. 'ohos.permission.CAMERA',
  3. 'ohos.permission.MICROPHONE',
  4. 'ohos.permission.MEDIA_LOCATION',
  5. 'ohos.permission.READ_MEDIA',
  6. 'ohos.permission.WRITE_MEDIA'
  7. ]
  8. function applyPermission() {
  9. console.info('[permission] get permission');
  10. globalThis.abilityContext.requestPermissionFromUser(PERMISSIONS)
  11. }

(1)、 创建相机实例:

        在实现一个相机应用之前必须先创建一个独立的相机设备,然后才能继续相机的其他操作。如果此步骤操作失败,相机可能被占用或无法使用。如果被占用,必须等到相机释放后才能重新获取CameraManager对象。通过getSupportedCameras() 方法,获取当前使用的设备支持的相机列表。相机列表中存储了当前设备拥有的所有相机ID,如果列表不为空,则列表中的每个ID都支持独立创建相机对象;否则,说明正在使用的设备无可用的相机,不能继续后续的操作。相机设备具备预览、拍照、录像、Metadata等输出流,需要通过getSupportedOutputCapability()接口获取各个输出流的具体能力,通过该接口,可以获取当前设备支持的所有输出流能力,分别在CameraOutputCapability中的各个profile字段中,相机设备创建的建议步骤如下:

  1. import camera from '@ohos.multimedia.camera'
  2. import image from '@ohos.multimedia.image'
  3. import media from '@ohos.multimedia.media'
  4. // 创建CameraManager对象
  5. context: any = getContext(this)
  6. let cameraManager = camera.getCameraManager(this.context)
  7. if (!cameraManager) {
  8. console.error("camera.getCameraManager error")
  9. return;
  10. }
  11. // 监听相机状态变化
  12. cameraManager.on('cameraStatus', (cameraStatusInfo) => {
  13. console.log(`camera : ${cameraStatusInfo.camera.cameraId}`);
  14. console.log(`status: ${cameraStatusInfo.status}`);
  15. })
  16. // 获取相机列表
  17. let cameraArray = cameraManager.getSupportedCameras();
  18. if (cameraArray.length <= 0) {
  19. console.error("cameraManager.getSupportedCameras error")
  20. return;
  21. }
  22. for (let index = 0; index < cameraArray.length; index++) {
  23. console.log('cameraId : ' + cameraArray[index].cameraId); // 获取相机ID
  24. console.log('cameraPosition : ' + cameraArray[index].cameraPosition); // 获取相机位置
  25. console.log('cameraType : ' + cameraArray[index].cameraType); // 获取相机类型
  26. console.log('connectionType : ' + cameraArray[index].connectionType); // 获取相机连接类型
  27. }
  28. // 创建相机输入流
  29. let cameraInput
  30. try {
  31. cameraInput = cameraManager.createCameraInput(cameraArray[0]);
  32. } catch () {
  33. console.error('Failed to createCameraInput errorCode = ' + error.code);
  34. }
  35. // 监听cameraInput错误信息
  36. let cameraDevice = cameraArray[0];
  37. cameraInput.on('error', cameraDevice, (error) => {
  38. console.log(`Camera input error code: ${error.code}`);
  39. })
  40. // 打开相机
  41. await cameraInput.open();
  42. // 获取相机设备支持的输出流能力
  43. let cameraOutputCap = cameraManager.getSupportedOutputCapability(cameraArray[0]);
  44. if (!cameraOutputCap) {
  45. console.error("cameraManager.getSupportedOutputCapability error")
  46. return;
  47. }
  48. console.info("outputCapability: " + JSON.stringify(cameraOutputCap));
  49. let previewProfilesArray = cameraOutputCap.previewProfiles;
  50. if (!previewProfilesArray) {
  51. console.error("createOutput previewProfilesArray == null || undefined")
  52. }
  53. let photoProfilesArray = cameraOutputCap.photoProfiles;
  54. if (!photoProfilesArray) {
  55. console.error("createOutput photoProfilesArray == null || undefined")
  56. }
  57. let videoProfilesArray = cameraOutputCap.videoProfiles;
  58. if (!videoProfilesArray) {
  59. console.error("createOutput videoProfilesArray == null || undefined")
  60. }
  61. let metadataObjectTypesArray = cameraOutputCap.supportedMetadataObjectTypes;
  62. if (!metadataObjectTypesArray) {
  63. console.error("createOutput metadataObjectTypesArray == null || undefined")
  64. }
  65. // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件,预览流为XComponent组件提供的surface
  66. let previewOutput
  67. try {
  68. previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId)
  69. } catch (error) {
  70. console.error("Failed to create the PreviewOutput instance.")
  71. }
  72. // 监听预览输出错误信息
  73. previewOutput.on('error', (error) => {
  74. console.log(`Preview output error code: ${error.code}`);
  75. })
  76. // 创建ImageReceiver对象,并设置照片参数:分辨率大小是根据前面 photoProfilesArray 获取的当前设备所支持的拍照分辨率大小去设置
  77. let imageReceiver = await image.createImageReceiver(1920, 1080, 4, 8)
  78. // 获取照片显示SurfaceId
  79. let photoSurfaceId = await imageReceiver.getReceivingSurfaceId()
  80. // 创建拍照输出流
  81. let photoOutput
  82. try {
  83. photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0], photoSurfaceId)
  84. } catch (error) {
  85. console.error('Failed to createPhotoOutput errorCode = ' + error.code);
  86. }
  87. // 创建视频录制的参数
  88. let videoConfig = {
  89. audioSourceType: 1,
  90. videoSourceType: 1,
  91. profile: {
  92. audioBitrate: 48000,
  93. audioChannels: 2,
  94. audioCodec: 'audio/mp4v-es',
  95. audioSampleRate: 48000,
  96. durationTime: 1000,
  97. fileFormat: 'mp4',
  98. videoBitrate: 48000,
  99. videoCodec: 'video/mp4v-es',
  100. videoFrameWidth: 640,
  101. videoFrameHeight: 480,
  102. videoFrameRate: 30
  103. },
  104. url: 'file:///data/media/01.mp4',
  105. orientationHint: 0,
  106. maxSize: 100,
  107. maxDuration: 500,
  108. rotation: 0
  109. }
  110. // 创建录像输出流
  111. let videoRecorder
  112. media.createVideoRecorder().then((recorder) => {
  113. console.log('createVideoRecorder called')
  114. videoRecorder = recorder
  115. })
  116. // 设置视频录制的参数
  117. videoRecorder.prepare(videoConfig)
  118. //获取录像SurfaceId
  119. let videoSurfaceId
  120. videoRecorder.getInputSurface().then((id) => {
  121. console.log('getInputSurface called')
  122. videoSurfaceId = id
  123. })
  124. // 创建VideoOutput对象
  125. let videoOutput
  126. try {
  127. videoOutput = cameraManager.createVideoOutput(videoProfilesArray[0], videoSurfaceId)
  128. } catch (error) {
  129. console.error('Failed to create the videoOutput instance. errorCode = ' + error.code);
  130. }
  131. // 监听视频输出错误信息
  132. videoOutput.on('error', (error) => {
  133. console.log(`Preview output error code: ${error.code}`);
  134. })

         预览流、拍照流和录像流的输入均需要提前创建surface,其中预览流为XComponent组件提供的surface,拍照流为ImageReceiver提供的surface,录像流为VideoRecorder的surface。

XComponent

  1. mXComponentController: XComponentController = new XComponentController // 创建XComponentController
  2. build() {
  3. Flex() {
  4. XComponent({ // 创建XComponent
  5. id: '',
  6. type: 'surface',
  7. libraryname: '',
  8. controller: this.mXComponentController
  9. })
  10. .onload(() => { // 设置onload回调
  11. // 设置Surface宽高(1920*1080),预览尺寸设置参考前面 previewProfilesArray 获取的当前设备所支持的预览分辨率大小去设置
  12. this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:1920,surfaceHeight:1080})
  13. // 获取Surface ID
  14. globalThis.surfaceId = mXComponentController.getXComponentSurfaceId()
  15. })
  16. .width('1920px') // 设置XComponent宽度
  17. .height('1080px') // 设置XComponent高度
  18. }
  19. }

ImageReceiver

  1. function getImageReceiverSurfaceId() {
  2. let receiver = image.createImageReceiver(640, 480, 4, 8)
  3. console.log(TAG + 'before ImageReceiver check')
  4. if (receiver !== undefined) {
  5. console.log('ImageReceiver is ok')
  6. surfaceId1 = receiver.getReceivingSurfaceId()
  7. console.log('ImageReceived id: ' + JSON.stringify(surfaceId1))
  8. } else {
  9. console.log('ImageReceiver is not ok')
  10. }
  11. }

VideoRecorder 

  1. function getVideoRecorderSurface() {
  2. await getFd('CameraManager.mp4');
  3. mVideoConfig.url = mFdPath;
  4. media.createVideoRecorder((err, recorder) => {
  5. console.info('Entering create video receiver')
  6. mVideoRecorder = recorder
  7. console.info('videoRecorder is :' + JSON.stringify(mVideoRecorder))
  8. console.info('videoRecorder.prepare called.')
  9. mVideoRecorder.prepare(mVideoConfig, (err) => {
  10. console.info('videoRecorder.prepare success.')
  11. mVideoRecorder.getInputSurface((err, id) => {
  12. console.info('getInputSurface called')
  13. mVideoSurface = id
  14. console.info('getInputSurface surfaceId: ' + JSON.stringify(mVideoSurface))
  15. })
  16. })
  17. })
  18. }

 (2)、创建相机实例

  1. //创建会话
  2. let captureSession
  3. try {
  4. captureSession = cameraManager.createCaptureSession()
  5. } catch (error) {
  6. console.error('Failed to create the CaptureSession instance. errorCode = ' + error.code);
  7. }
  8. // 监听session错误信息
  9. captureSession.on('error', (error) => {
  10. console.log(`Capture session error code: ${error.code}`);
  11. })
  12. // 开始配置会话
  13. try {
  14. captureSession.beginConfig()
  15. } catch (error) {
  16. console.error('Failed to beginConfig. errorCode = ' + error.code);
  17. }
  18. // 向会话中添加相机输入流
  19. try {
  20. captureSession.addInput(cameraInput)
  21. } catch (error) {
  22. console.error('Failed to addInput. errorCode = ' + error.code);
  23. }
  24. // 向会话中添加预览输入流
  25. try {
  26. captureSession.addOutput(previewOutput)
  27. } catch (error) {
  28. console.error('Failed to addOutput(previewOutput). errorCode = ' + error.code);
  29. }
  30. // 向会话中添加拍照输出流
  31. try {
  32. captureSession.addOutput(photoOutput)
  33. } catch (error) {
  34. console.error('Failed to addOutput(photoOutput). errorCode = ' + error.code);
  35. }
  36. // 提交会话配置
  37. await captureSession.commitConfig()
  38. // 启动会话
  39. await captureSession.start().then(() => {
  40. console.log('Promise returned to indicate the session start success.');
  41. })

(3)、切换回话

  1. // 停止当前会话
  2. await captureSession.stop()
  3. // 开始配置会话
  4. try {
  5. captureSession.beginConfig()
  6. } catch (error) {
  7. console.error('Failed to beginConfig. errorCode = ' + error.code);
  8. }
  9. // 从会话中移除拍照输出流
  10. try {
  11. captureSession.removeOutput(photoOutput)
  12. } catch (error) {
  13. console.error('Failed to removeOutput(photoOutput). errorCode = ' + error.code);
  14. }
  15. // 向会话中添加录像输出流
  16. try {
  17. captureSession.addOutput(videoOutput)
  18. } catch (error) {
  19. console.error('Failed to addOutput(videoOutput). errorCode = ' + error.code);
  20. }
  21. // 提交会话配置
  22. await captureSession.commitConfig()
  23. // 启动会话
  24. await captureSession.start().then(() => {
  25. console.log('Promise returned to indicate the session start success.');
  26. })

 (4)、参数设置

  1. // 判断设备是否支持闪光灯
  2. let flashStatus
  3. try {
  4. flashStatus = captureSession.hasFlash()
  5. } catch (error) {
  6. console.error('Failed to hasFlash. errorCode = ' + error.code);
  7. }
  8. console.log('Promise returned with the flash light support status:' + flashStatus);
  9. if (flashStatus) {
  10. // 判断是否支持自动闪光灯模式
  11. let flashModeStatus
  12. try {
  13. let status = captureSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO)
  14. flashModeStatus = status
  15. } catch (error) {
  16. console.error('Failed to check whether the flash mode is supported. errorCode = ' + error.code);
  17. }
  18. if(flashModeStatus) {
  19. // 设置自动闪光灯模式
  20. try {
  21. captureSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO)
  22. } catch (error) {
  23. console.error('Failed to set the flash mode. errorCode = ' + error.code);
  24. }
  25. }
  26. }
  27. // 判断是否支持连续自动变焦模式
  28. let focusModeStatus
  29. try {
  30. let status = captureSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO)
  31. focusModeStatus = status
  32. } catch (error) {
  33. console.error('Failed to check whether the focus mode is supported. errorCode = ' + error.code);
  34. }
  35. if (focusModeStatus) {
  36. // 设置连续自动变焦模式
  37. try {
  38. captureSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO)
  39. } catch (error) {
  40. console.error('Failed to set the focus mode. errorCode = ' + error.code);
  41. }
  42. }
  43. // 获取相机支持的可变焦距比范围
  44. let zoomRatioRange
  45. try {
  46. zoomRatioRange = captureSession.getZoomRatioRange()
  47. } catch (error) {
  48. console.error('Failed to get the zoom ratio range. errorCode = ' + error.code);
  49. }
  50. // 设置可变焦距比
  51. try {
  52. captureSession.setZoomRatio(zoomRatioRange[0])
  53. } catch (error) {
  54. console.error('Failed to set the zoom ratio value. errorCode = ' + error.code);
  55. }

(5)、拍照

  1. let settings = {
  2. quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // 设置图片质量高
  3. rotation: camera.ImageRotation.ROTATION_0 // 设置图片旋转角度0
  4. }
  5. // 使用当前拍照设置进行拍照
  6. photoOutput.capture(settings, async (err) => {
  7. if (err) {
  8. console.error('Failed to capture the photo ${err.message}');
  9. return;
  10. }
  11. console.log('Callback invoked to indicate the photo capture request success.');
  12. });

 (6)、录像

  1. // 启动录像输出流
  2. videoOutput.start(async (err) => {
  3. if (err) {
  4. console.error('Failed to start the video output ${err.message}');
  5. return;
  6. }
  7. console.log('Callback invoked to indicate the video output start success.');
  8. });
  9. // 开始录像
  10. videoRecorder.start().then(() => {
  11. console.info('videoRecorder start success');
  12. }
  13. // 停止录像
  14. videoRecorder.stop().then(() => {
  15. console.info('stop success');
  16. }
  17. // 停止录像输出流
  18. videoOutput.stop((err) => {
  19. if (err) {
  20. console.error('Failed to stop the video output ${err.message}');
  21. return;
  22. }
  23. console.log('Callback invoked to indicate the video output stop success.');
  24. });

(7)、资源释放

  1. // 停止当前会话
  2. captureSession.stop()
  3. // 释放相机输入流
  4. cameraInput.close()
  5. // 释放预览输出流
  6. previewOutput.release()
  7. // 释放拍照输出流
  8. photoOutput.release()
  9. // 释放录像输出流
  10. videoOutput.release()
  11. // 释放会话
  12. captureSession.release()
  13. // 会话置空
  14. captureSession = null

3、应用使用相机的流程图

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/329337
推荐阅读
相关标签
  

闽ICP备14008679号