OpenHarmony 分布式相机(下)

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

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

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

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

分布式相机问题一览

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

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,即为系统应用。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 51CTO 开源基础软件社区
相关推荐

2023-02-20 15:29:14

分布式相机鸿蒙

2023-02-20 15:38:38

2022-04-24 16:00:03

Ability鸿蒙

2022-04-08 11:08:17

分布式数据接口同步机制

2022-06-20 15:32:55

Stage模型分布式开发

2021-11-10 16:10:18

鸿蒙HarmonyOS应用

2019-10-10 09:16:34

Zookeeper架构分布式

2017-09-01 05:35:58

分布式计算存储

2019-06-19 15:40:06

分布式锁RedisJava

2023-05-29 14:07:00

Zuul网关系统

2023-12-26 08:59:52

分布式场景事务机制

2022-06-15 16:16:21

分布式数据库鸿蒙

2022-02-17 18:08:04

OpenHarmon应用开发鸿蒙

2021-12-14 10:16:00

鸿蒙HarmonyOS应用

2017-10-27 08:40:44

分布式存储剪枝系统

2023-10-26 18:10:43

分布式并行技术系统

2013-12-20 09:43:13

分布式

2018-07-17 08:14:22

分布式分布式锁方位

2024-03-01 09:53:34

2022-06-27 08:21:05

Seata分布式事务微服务
点赞
收藏

51CTO技术栈公众号