OpenHarmony3.2 beta4上照相机的使用之1--开启照相机预览画面 原创 精华

开源夏德旺
发布于 2022-12-13 22:56
浏览
12收藏

随着OpenHarmony的版本更新,在3.2上已经提供了非常丰富的API来调用照相机。此处讲解的是原生的使用相机的流程,并发像Android普通应用开发一样通过一个intent直接调用系统相机应用进行拍照,根据原生的调用相机的API可以让大家自己定义功能更加丰富的相机应用。

这里为何我特意强调是OpenHarmony3.2 beta4,因为我发现即使同为3.2版本,beta4上的Camera相关的api和beta2版本差距都非常大,于是选取了当前最新的版本进行讲解。

既然使用相机,那么第一步是先想办法把相机点亮,即能通过摄像头看到预览画面,后面才是拍照、录像、分布式拍照等功能实现。

关于sdk的问题

目前在OpenHarmony3.2上调用相机,需要使用ohos-full-sdk,而非大家下载DevEco Studio所带的sdk,那个sdk被称作为public sdk。关于sdk的替换办法可以参考官方文档“ full-SDK替换指南”,我这里不过多赘述。

此处核心要注意的一点是,目前我3.2 beta4上用的sdk对应的版本号为3.2.9.4

OpenHarmony3.2 beta4上照相机的使用之1--开启照相机预览画面-鸿蒙开发者社区

而目前官方文档上写的能下载到的sdk最高版本只有3.2.5.6。

OpenHarmony3.2 beta4上照相机的使用之1--开启照相机预览画面-鸿蒙开发者社区

因此,需要我们手动下载系统源码,自己完成sdk的编译才行,我这里是基于3.2 beta4的系统源码自行编译出来的full-sdk。

启用相机打开预览画面核心流程与代码实现

(1)动态权限申请

需要获取ohos.permission.CAMERA权限

(2)相机相关API操作流程
OpenHarmony3.2 beta4上照相机的使用之1--开启照相机预览画面-鸿蒙开发者社区

上面是相机完整功能使用的时序图,这里我们先只按照时序图中的流程只实现预览部分。

(3)配合XComponent组件完成相机预览流的输出

XComponent组件中通过XComponentController的getXComponentSurfaceId方法可以获取到sufaceId,然后通过相机管理对象cameraManager.createPreviewOutput这个关键方法可以绑定该surface,从而实现预览画面的输出。

启用相机打开预览画面代码实现

import camera from '@ohos.multimedia.camera'

const PERMISSIONS: Array<string> = [
  'ohos.permission.CAMERA']
let previewWidth;
let previewHeight;
@Entry
@Component
struct Index {
  private mXComponentController: XComponentController = new XComponentController()
  private surfaceId: string = '-1'

  async initCamera(surfaceId: string){
    //动态获取隐私权限
    let context = getContext(this) as any
    await context.requestPermissionsFromUser(PERMISSIONS)
    console.log('grantPermission,requestPermissionsFromUser');
    // 创建CameraManager对象
    let cameraManager = await camera.getCameraManager(context)
    if (!cameraManager) {
      console.error('Failed to get the CameraManager instance');
    }
    // 获取相机列表
    let cameraArray = await cameraManager.getSupportedCameras()
    if (!cameraArray) {
      console.error('Failed to get the cameras');
    }
    for (let index = 0; index < cameraArray.length; index++) {
      console.log('cameraId : ' + cameraArray[index].cameraId)                          // 获取相机ID
      console.log('cameraPosition : ' + cameraArray[index].cameraPosition)              // 获取相机位置
      console.log('cameraType : ' + cameraArray[index].cameraType)                      // 获取相机类型
      console.log('connectionType : ' + cameraArray[index].connectionType)              // 获取相机连接类型
    }

    // 创建相机输入流
    let cameraInput = await cameraManager.createCameraInput(cameraArray[0])

    //  打开相机
    await cameraInput.open().then(() => {
      console.log('opencamera succ.');
    }).catch(function(err){
      console.log("opencamera failed with error:"+ err);
    });

    // 获取相机设备支持的输出流能力
    let cameraOutputCap = await cameraManager.getSupportedOutputCapability(cameraArray[0]);
    if (!cameraOutputCap) {
      console.error("outputCapability outputCapability == null || undefined")
    } else {
      console.log("outputCapability: " + JSON.stringify(cameraOutputCap));
    }

    //获取相机支持的输出能力--支持的预览配置信息
    let previewProfilesArray = cameraOutputCap.previewProfiles;
    if (!previewProfilesArray) {
      console.error("createOutput previewProfilesArray == null || undefined")
    }else{
      console.log("previewProfiles:"+JSON.stringify(previewProfilesArray[0]))
      previewWidth = previewProfilesArray[0].size.width;
      previewHeight = previewProfilesArray[0].size.height;
    }

    // 创建预览输出流,其中参数 surfaceId 参考下面 XComponent 组件,预览流为XComponent组件提供的surface
    let previewOutput = await cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId)
    if (!previewOutput) {
      console.error("Failed to create the PreviewOutput instance.")
    }else{
      console.log("create the PreviewOutput instance succ.")
    }

    //创建会话
    let captureSession = await cameraManager.createCaptureSession()
    if (!captureSession) {
      console.error('Failed to create the CaptureSession instance.');
      return;
    }
    console.log('Callback returned with the CaptureSession instance.' + captureSession);

    // 开始配置会话
    await captureSession.beginConfig().then(()=>{
      console.log('captureSession beginConfig succ');
    }).catch(function(err){
      console.log("captureSession beginConfig failed with error:"+ err);
    });
 
    // 向会话中添加相机输入流
    await captureSession.addInput(cameraInput).then(() => {
      console.log('captureSession addInput instance is added.');
    }).catch(function(err){
      console.log("captureSession addInput failed with error:"+ err);
    });

    // 向会话中添加预览输入流
    await captureSession.addOutput(previewOutput).then(() => {
      console.log('captureSession addOutput previewOutput instance is added.');
    }).catch(function(err){
      console.log("captureSession addOutput previewOutput failed with error:"+ err);
    });

    // 提交会话配置
    await captureSession.commitConfig().then(() => {
      console.log('captureSession commitConfig success.');
    }).catch(function(err){
      console.log("captureSession commitConfig failed with error:"+ err);
    });
    // 启动会话
    await captureSession.start().then(() => {
      console.log('captureSession start success.');
    }).catch(function(err){
      console.log("captureSession start failed with error:"+ err);
    });
  }

  build() {
    Flex() {
      XComponent({                                                                     // 创建XComponent
        id: '',
        type: 'surface',
        libraryname: '',
        controller: this.mXComponentController
      })
        .onLoad(() => {                                                                  // 设置onload回调
          // 设置Surface宽高(1920*1080),预览尺寸设置参考前面 previewProfilesArray 获取的当前设备所支持的预览分辨率大小去设置
          this.mXComponentController.setXComponentSurfaceSize({surfaceWidth:previewWidth,surfaceHeight:previewHeight})
          // 获取Surface ID
          this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
          this.initCamera(this.surfaceId)
        })
        .width('100%')                                                                 // 设置XComponent宽度
        .height('100%')                                                                // 设置XComponent高度
    }
  }

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
16
收藏 12
回复
举报
16
8
12
8条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

版本问题,sdk问题这篇真是细节满满

回复
2022-12-14 10:00:38
SummerRic
SummerRic

xue xi ld

回复
2022-12-14 16:27:05
笨笨的婧婧
笨笨的婧婧

请问相机相关API操作流程有更清晰点的大图学习下吗

回复
2022-12-14 18:21:42
物联风景
物联风景

不错不错,非常好

回复
2022-12-14 20:36:34
香菜太难吃了
香菜太难吃了

不同版本api不同会不会影响后续应用的更新

回复
2022-12-15 18:16:08
皮皮虾233
皮皮虾233

希望后续版本兼容能好起来吧

回复
2022-12-16 18:46:45
0aaron
0aaron

不同版本的api不同对开发者来说有点不友好

回复
2022-12-19 10:53:32
owCode
owCode

mark:由于"ohos.permission.CAMERA"权限的授权类型为user-agent,应用在申请user_grant类型的权限默认未授权,这就需要我们不仅在module.json5中的"requestPermissions"字段[申请该权限​],还需要通过拉起弹框由用户确认是否授予该权限。


已于2023-2-10 15:47:33修改
1
回复
2023-2-10 15:16:28


回复
    相关推荐