8

OpenHarmony 分布式相机(下)-开源基础软件社区-51CTO.COM

 1 year ago
source link: https://ost.51cto.com/posts/21257
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

作者:徐金生

前面两篇,已经介绍了分布式相机应用开发的整个流程,有兴趣的可以回顾下:

这篇我们主要讲讲分布式相机开发过程中遇到的一些问题和思考,由于本地人目前主要是北向入手,所以只从应用开发的角度总结目前遇到的问题,如有一些低级错误,还希望各位老师不吝赐教。

分布式相机问题一览

对于开发过程中所遇到的一些坑,前面两篇多少有简单的提到一些,这里做一次规整,也算是一次回顾。

1、首次授权成功无法显示相机预览

解析: 我们正常会在MainAbility.ts的onCreate()函数加载的时候执行申请授权,在index.ets页面中,当 XComponent 组件 onLoad() 回调后执行初始化相机操作,代码如下:

MainAbility.ts


const TAG: string = '[DistributedCamera]'
let permissionList: Array<string> = [
    "ohos.permission.MEDIA_LOCATION",
    "ohos.permission.READ_MEDIA",
    "ohos.permission.WRITE_MEDIA",
    "ohos.permission.CAMERA",
    "ohos.permission.MICROPHONE",
    "ohos.permission.DISTRIBUTED_DATASYNC"
]


export default class MainAbility extends Ability {
    async onCreate(want, launchParam) {
        console.info(`${TAG} onCreate`)
        globalThis.cameraAbilityContext = this.context
        await globalThis.cameraAbilityContext.requestPermissionsFromUser(permissionList)
    }
  }

index.ets

// ...
// 截取部分主要代码

Column() {
          XComponent({
            id: 'componentId',
            type: 'surface',
            controller: this.XComponentController
          }).onLoad(async () => {
            console.info(`${TAG} XComponent onLoad is called`)
            this.XComponentController.setXComponentSurfaceSize({
              surfaceWidth: Resolution.DEFAULT_WIDTH,
              surfaceHeight: Resolution.DEFAULT_HEIGHT
            })
            this.surfaceId = this.XComponentController.getXComponentSurfaceId()
            console.info(`${TAG} surfaceId: ${this.surfaceId}`)
            await this.initCamera()
          }).height('100%')
            .width('100%')
        }
        .width('100%')
        .height('75%')
        .margin({
          bottom: 20
        })

// ...

应用启动后,调用了requestPermissionsFromUser()请求权限后,但未手动授权时,查看相关日志:

OpenHarmony 分布式相机(下)-开源基础软件社区

日志告诉我们,page的生命周期已启动到onShow,并且页面布局也完成了加载,XComponent 组件回调 onLoad() ,但是由于还未授权,导致无法初始化相机,此时即便授权成功,也不会再进行初始化,导致相机无法启动,无预览视图。

知道原因后,我们可以有多种方式解决,重点就是在授权完成后,需要再次触发初始化相机,让相机启动才可以正常预览。

我的处理方式:

1、在index.ets页面中处理授权
2、定义是否已授权的标识,用于判断是否可以初始化相机
3、定义是否已经初始化相机标识,防止对此初始化
4、在page页面初始化函数aboutToAppear()中请求权限,并在权限申请结果中添加初始化相机操作
5、XComponent 组件回调 onLoad() 初始化相机操作不变

index.ets


  private isInitCamera: boolean = false // 是否已初始化相机
  private isPermissions: boolean = false // 是否完成授权

  async aboutToAppear() {
    console.info(`${TAG} aboutToAppear`)
    globalThis.cameraAbilityContext.requestPermissionsFromUser(permissionList).then(async (data) => {
      console.info(`${TAG} data permissions: ${JSON.stringify(data.permissions)}`)
      console.info(`${TAG} data authResult: ${JSON.stringify(data.authResults)}`)
      // 判断授权是否完成
      let resultCount: number = 0
      for (let result of data.authResults) {
        if (result === 0) {
          resultCount += 1
        }
      }
      if (resultCount === permissionList.length) {
        this.isPermissions = true
      }
      await this.initCamera()
      // 获取缩略图
      this.mCameraService.getThumbnail(this.functionBackImpl)
    })
  }

2、相机应用未关闭,系统息屏后重新点亮,重新返回相机应用,无预览输出流返回

解析: 从现象看,预览画面卡在息屏前的状态,需要退出应用后,重启应用才能正常预览。从日志上看没有查看到具体的原因,只是camera_host的数据量日志消失。
猜想:相机在系统息屏后强制关闭,需要重新加载相机才能正常预览,实现方式如下:
1、在page的onPageShow()回调函数中重新初始化相机
2、在page的onPageHide()函数中释放相机资源,减少系统资源不必要的消耗。

index.ets


  async onPageShow() {
    console.info(`${TAG} onPageShow`)
    await this.initCamera()
  }
  onPageHide() {
    console.info(`${TAG} onPageHide`)
    this.isSwitchDeviceing = false
    this.isInitCamera = false
    this.mCameraService.releaseCamera()
  }

结论: 实践验证此方法有效解决息屏后点亮返回相机无法预览的问题。

3、加载远程相机,在会话管理中添加拍照输出流,无法拍照,预览黑屏

解析: 两台设备pin码认证通过,连接成功,在主控端选择一台被控端设备时,加载相机,流程与加载本地相机相同,流程如下:

createCameraInput()
createPreviewOutput()
createPhotoOutput()
createSession()

* createSession.beginConfig()
* createSession.addInput(CameraInput)
* createSession.addOutput(PreviewOutput)
* createSession.addOutput(PhotoOutput)
* createSession.commitConfig()
* createSession.start()

经过排查,发现日志中返回异常not found in supported streams,详情可以查看关联 issues

原因: 在创建PhotoOutput时需要传递支持的拍照配置信息Profile,这里的Profile可以通过CmeraManager.getSupportedOutputCapability()返回的相机输出能力CameraOutputCapability对象获取,但远程相机设备拍照输出能力列表返回空,但通过查看本地相机拍照输出能力可知DAYU200设备支持的Profile信息:


photoProfile {"format":2000,"size":{"width":1280,"height":960}}

通过此将photoProfile作为远程相机设备构建拍照输出流的入参场景拍照输出流,并把此添加到拍照会话管理中,但是界面出现不支持此相机配置,最终关闭了相机,导致黑屏。

解决方案: 根据此问题,目前只能根据场景判断是否需要添加拍照输出流到会话管理,对于本地相机则可以添加拍照输出流,执行拍照业务,远程相机则不添加拍照输出流,这也就不能执行拍照业务,希望社区有解决方案。

4、切换不同设备上的相机,相机预览输出流出现异常,无法显示远程相机的画面

解析: 此问题存在的原因可能有多种,这里我说下我遇到的情况,
1、分布式连接被断开,但是因为底层机制,设备之间下线需要在一段时间内才能上报(预计5分钟),所以在应用层看到可以连接的远端设备,其实已经下线了,这时当然不能切换到远程相机。

2、与问题3中描述的相同,因为添加了一个无法支持的拍照配置信息导致相机被关闭。

解决方案
1、等待线下通知,再重新连接设备,或者等待设备自动完成重连,简单粗暴就是重启设备。
2、待社区反馈

5、相机业务在主线程执行,需要将业务移动到子线程,防止UI线程堵塞

解析: 如题描述,目前可能存在堵塞UI线程的可能,需要将一些耗时的操作移动到子线程,比如预览、拍照保存图片等

目前正在修改优化,关于ets的异步线程worker可以查看之前写的一篇关于:OpenHarmony stage worker 多线程

6、远程相机预览数据传输存在500ms的延迟

解析: 在wifi环境下,被控端相机将预览数据通过软总线传输到主控端显示,有500ms左右的延迟,此问题待排查,具体是那个环境出现的延迟。

7、no permission for function call

解析: 用户动态授予:允许不同设备间的数据(ohos.permission.DISTRIBUTED_DATASYNC) 交换权限后,DeviceManager.startDeviceDiscovery()启动发现周边设备总会出现异常,日志中提示:

discoverFail data= {"subscribeId":26386,"reason":-20007,"errInfo":"no permission for function call."}

原因: 非系统应用无法使用DeviceManager,详细可查看:issues

解决方案:
系统应用和普通应用是通过签名来区分,那只要通过修改签名UnsgnedReleasedProfileTemplate.json文件中的app-feature值为ohos_system_app,即为系统应用。

继续探索…

如果您能看到最后,还希望您能动动手指点个赞,一个人能走多远关键在于与谁同行,我用跨越山海的一路相伴,希望得到您的点赞。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK