0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

鴻蒙分布式相機(jī)“踩坑”分享

OpenHarmony技術(shù)社區(qū) ? 來(lái)源:OST開(kāi)源開(kāi)發(fā)者 ? 2023-03-08 14:19 ? 次閱讀

接上一篇 OpenHarmony 分布式相機(jī)(上),今天我們來(lái)說(shuō)下如何實(shí)現(xiàn)分布式相機(jī)。

實(shí)現(xiàn)分布式相機(jī)其實(shí)很簡(jiǎn)單,正如官方介紹的一樣,當(dāng)被控端相機(jī)被連接成功后,可以像使用本地設(shè)備一樣使用遠(yuǎn)程相機(jī)。

我們先看下效果:

066055e4-b9cf-11ed-bfe3-dac502259ad0.jpg

上一篇已經(jīng)完整的介紹了如何開(kāi)發(fā)一個(gè)本地相機(jī),對(duì)于分布式相機(jī)我們需要完成以下幾個(gè)步驟。

前置條件:

兩臺(tái)帶攝像頭的設(shè)備

建議使用相同版本的 OH 系統(tǒng),本案例使用 OpenHarmony 3.2 beta5

連接在同一個(gè)網(wǎng)絡(luò)

開(kāi)發(fā)步驟:

引入設(shè)備管理(@ohos.distributedHardware.deviceManager)

通過(guò) deviceManager 發(fā)現(xiàn)周邊設(shè)備

通過(guò) pin 碼完成設(shè)備認(rèn)證

獲取和展示可信設(shè)備

在可信設(shè)備直接選擇切換不同設(shè)備的攝像頭

在主控端查看被控端的攝像頭圖像

以上描述的功能在應(yīng)用開(kāi)發(fā)時(shí)可以使用一張草圖來(lái)表示,草圖中切換設(shè)備->彈窗顯示設(shè)備列表的過(guò)程,草圖如下:

0679e5a4-b9cf-11ed-bfe3-dac502259ad0.png

代碼

①RemoteDeviceModel.ts

說(shuō)明:遠(yuǎn)程設(shè)備業(yè)務(wù)處理類(lèi),包括獲取可信設(shè)備列表、獲取周邊設(shè)備列表、監(jiān)聽(tīng)設(shè)備狀態(tài)(上線、下線、狀態(tài)變化)、監(jiān)聽(tīng)設(shè)備連接失敗、設(shè)備授信認(rèn)證、卸載設(shè)備狀態(tài)監(jiān)聽(tīng)等。

代碼如下:

importdeviceManagerfrom'@ohos.distributedHardware.deviceManager'
importLoggerfrom'./util/Logger'
constTAG:string='RemoteDeviceModel'
letsubscribeId:number=-1
exportclassRemoteDeviceModel{
privatedeviceList:Array=[]
privatediscoverList:Array=[]
privatecallback:()=>void
privateauthCallback:()=>void
privatedeviceManager:deviceManager.DeviceManager
constructor(){
}
publicregisterDeviceListCallback(bundleName:string,callback){
if(typeof(this.deviceManager)!=='undefined'){
this.registerDeviceListCallbackImplement(callback)
return
}
Logger.info(TAG,`deviceManager.createDeviceManagerbegin`)
try{
deviceManager.createDeviceManager(bundleName,(error,value)=>{
if(error){
Logger.info(TAG,`createDeviceManagerfailed.`)
return
}
this.deviceManager=value
this.registerDeviceListCallbackImplement(callback)
Logger.info(TAG,`createDeviceManagercallbackreturned,error=${error},value=${value}`)
})
}catch(err){
Logger.error(TAG,`createDeviceManagerfailed,codeis${err.code},messageis${err.message}`)
}
Logger.info(TAG,`deviceManager.createDeviceManagerend`)
}
privatedeviceStateChangeActionOffline(device){
if(this.deviceList.length<=?0)?{
????????????this.callback()
????????????return
????????}
????????for?(let?j?=?0;?j?{
if(data===null){
return
}
Logger.info(TAG,`deviceStateChangedata=${JSON.stringify(data)}`)
switch(data.action){
casedeviceManager.DeviceStateChangeAction.READY:
this.discoverList=[]
this.deviceList.push(data.device)
try{
letlist=this.deviceManager.getTrustedDeviceListSync()
if(typeof(list)!=='undefined'&&typeof(list.length)!=='undefined'){
this.deviceList=list
}
this.callback()
}catch(err){
Logger.error(TAG,`getTrustedDeviceListSyncfailed,codeis${err.code},messageis${err.message}`)
}
break
casedeviceManager.DeviceStateChangeAction.OFFLINE:
casedeviceManager.DeviceStateChangeAction.CHANGE:
this.deviceStateChangeActionOffline(data.device)
break
default:
break
}
})
this.deviceManager.on('deviceFound',(data)=>{
if(data===null){
return
}
Logger.info(TAG,`deviceFounddata=${JSON.stringify(data)}`)
this.deviceFound(data)
})
this.deviceManager.on('discoverFail',(data)=>{
Logger.info(TAG,`discoverFaildata=${JSON.stringify(data)}`)
})
this.deviceManager.on('serviceDie',()=>{
Logger.info(TAG,`serviceDie`)
})
this.startDeviceDiscovery()
}
privatedeviceFound(data){
for(vari=0;i=0){
Logger.info(TAG,`startedDeviceDiscovery`)
return
}
subscribeId=Math.floor(65536*Math.random())
letinfo={
subscribeId:subscribeId,
mode:deviceManager.DiscoverMode.DISCOVER_MODE_ACTIVE,
medium:deviceManager.ExchangeMedium.COAP,
freq:deviceManager.ExchangeFreq.HIGH,
isSameAccount:false,
isWakeRemote:true,
capability:deviceManager.SubscribeCap.SUBSCRIBE_CAPABILITY_DDMP
}
Logger.info(TAG,`startDeviceDiscovery${subscribeId}`)
try{
// todo 多次啟動(dòng)發(fā)現(xiàn)周邊設(shè)備有什么影響嗎?
this.deviceManager.startDeviceDiscovery(info)
}catch(err){
Logger.error(TAG,`startDeviceDiscoveryfailed,codeis${err.code},messageis${err.message}`)
}
}
publicunregisterDeviceListCallback(){
Logger.info(TAG,`stopDeviceDiscovery$subscribeId}`)
this.deviceList=[]
this.discoverList=[]
try{
this.deviceManager.stopDeviceDiscovery(subscribeId)
}catch(err){
Logger.error(TAG,`stopDeviceDiscoveryfailed,codeis${err.code},messageis${err.message}`)
}
this.deviceManager.off('deviceStateChange')
this.deviceManager.off('deviceFound')
this.deviceManager.off('discoverFail')
this.deviceManager.off('serviceDie')
}
publicauthenticateDevice(device,extraInfo,callBack){
Logger.info(TAG,`authenticateDevice${JSON.stringify(device)}`)
for(leti=0;i{
if(err){
Logger.error(TAG,`authenticateDeviceerror:${JSON.stringify(err)}`)
this.authCallback=null
return
}
Logger.info(TAG,`authenticateDevicesucceed:${JSON.stringify(data)}`)
this.authCallback=callBack
})
}catch(err){
Logger.error(TAG,`authenticateDevicefailed,codeis${err.code},messageis${err.message}`)
}
}
}
/**
*已認(rèn)證設(shè)備列表
*/
publicgetDeviceList():Array{
returnthis.deviceList
}
/**
*發(fā)現(xiàn)設(shè)備列表
*/
publicgetDiscoverList():Array{
returnthis.discoverList
}
}

getDeviceList() :獲取已認(rèn)證的設(shè)備列表;getDiscoverList:發(fā)現(xiàn)周邊設(shè)備的列表。

②DeviceDialog.ets

說(shuō)明:通過(guò) RemoteDeviceModel.getDiscoverList() 和通過(guò) RemoteDeviceModel.getDeviceList() 獲取到所有周邊設(shè)備列表,用戶(hù)通過(guò)點(diǎn)擊"切換設(shè)備"按鈕彈窗顯示所有設(shè)備列表信息。

importdeviceManagerfrom'@ohos.distributedHardware.deviceManager';
constTAG='DeviceDialog'
//分布式設(shè)備選擇彈窗
@CustomDialog
exportstructDeviceDialog{
privatecontroller?:CustomDialogController//彈窗控制器
@LinkdeviceList:Array//設(shè)備列表
@LinkselectIndex:number//選中的標(biāo)簽
build(){
Column(){
List(){
ForEach(this.deviceList,(item:deviceManager.DeviceInfo,index)=>{
ListItem(){
Row(){
Text(item.deviceName)
.fontSize(22)
.width(350)
.fontColor(Color.Black)
Image(index===this.selectIndex?$r('app.media.checked'):$r('app.media.uncheck'))
.width(35)
.objectFit(ImageFit.Contain)
}
.height(55)
.onClick(()=>{
console.info(`${TAG}selectdevice${item.deviceId}`)
if(index===this.selectIndex){
console.info(`${TAG}devicenotchange`)
}else{
this.selectIndex=index
}
this.controller.close()
})
}
},item=>item.deviceName)
}
.width('100%')
.height(150)
Button(){
Text($r('app.string.cancel'))
.width('100%')
.height(45)
.fontSize(18)
.fontColor(Color.White)
.textAlign(TextAlign.Center)
}.onClick(()=>{
this.controller.close()
})
.backgroundColor('#ed3c13')
}
.width('100%')
.padding(20)
.backgroundColor(Color.White)
.border({
color:Color.White,
radius:20
})
}
}
③打開(kāi)設(shè)備列表彈窗

說(shuō)明:在 index.ets 頁(yè)面中,點(diǎn)擊“切換設(shè)備”按鈕即可以開(kāi)啟設(shè)備列表彈窗,通過(guò) @Watch(‘selectedIndexChange’) 監(jiān)聽(tīng)用戶(hù)選擇的設(shè)備標(biāo)簽,在 devices 中獲取到具體的 DeviceInfo 對(duì)象。

代碼如下:

@State@Watch('selectedIndexChange')selectIndex:number=0
//設(shè)備列表
@Statedevices:Array=[]
//設(shè)備選擇彈窗
privatedialogController:CustomDialogController=newCustomDialogController({
builder:DeviceDialog({
deviceList:$devices,
selectIndex:$selectIndex,
}),
autoCancel:true,
alignment:DialogAlignment.Center
})


showDialog(){
console.info(`${TAG}RegisterDeviceListCallbackbegin`)
distributed.registerDeviceListCallback(BUNDLE_NAME,()=>{
console.info(`${TAG}RegisterDeviceListCallbackcallbackentered`)
this.devices=[]
//添加本地設(shè)備
this.devices.push({
deviceId:Constant.LOCAL_DEVICE_ID,
deviceName:Constant.LOCAL_DEVICE_NAME,
deviceType:0,
networkId:'',
range:1//發(fā)現(xiàn)設(shè)備的距離
})
letdiscoverList=distributed.getDiscoverList()
letdeviceList=distributed.getDeviceList()
letdiscoveredDeviceSize=discoverList.length
letdeviceSize=deviceList.length
console.info(`${TAG}discoveredDeviceSize:${discoveredDeviceSize}deviceSize:${deviceSize}`)
letdeviceTemp=discoveredDeviceSize>0?discoverList:deviceList
for(letindex=0;index=distributed.getDiscoverList()
if(discoverList.length<=?0)?{
??????this.mCurDeviceID?=?this.devices[this.selectIndex].deviceId
??????await?this.switchDevice()
??????this.devices?=?[]
??????return
????}
????let?selectDeviceName?=?this.devices[this.selectIndex].deviceName
????let?extraInfo?=?{
??????'targetPkgName':?BUNDLE_NAME,
??????'appName':?APP_NAME,
??????'appDescription':?APP_NAME,
??????'business':?'0'
????}
????distributed.authenticateDevice(this.devices[this.selectIndex],?extraInfo,?async?()?=>{
//獲取到相關(guān)的設(shè)備ID,啟動(dòng)遠(yuǎn)程應(yīng)用
for(varindex=0;index

④重新加載相機(jī)

說(shuō)明:根據(jù)用戶(hù)選擇的設(shè)備標(biāo)簽獲取到當(dāng)前用戶(hù)需要切換的相機(jī)設(shè)備對(duì)象,重新加載相機(jī),重新加載需要釋放原有的相機(jī)資源,然后重新構(gòu)建 createCameraInput、createPreviewOutput、createSession。 可能你注意到這里好像沒(méi)有執(zhí)行 createPhotoOutput,這是因?yàn)樵趯?shí)踐過(guò)程中發(fā)現(xiàn),添加了一個(gè)當(dāng)前設(shè)備所支持的拍照配置到會(huì)話管理(CaptureSession.addOutput())時(shí),系統(tǒng)會(huì)返回當(dāng)前拍照配置流不支持,并關(guān)閉相機(jī),導(dǎo)致相機(jī)預(yù)覽黑屏,所以這里沒(méi)有添加。

issues:遠(yuǎn)程相機(jī)拍照失敗 not found in supported streams。

https://gitee.com/openharmony/distributedhardware_distributed_camera/issues/I6E5ZX
mCameraService:這個(gè)是相機(jī)管理類(lèi),代碼可以查看上一篇:OpenHarmony 分布式相機(jī)(上)中查看。

代碼如下:

/**
*切換攝像頭
*同一臺(tái)設(shè)備上切換不同攝像頭
*/
asyncswitchCamera(){
console.info(`${TAG}switchCamera`)
letcameraList=this.mCameraService.getDeviceCameras(this.mCurDeviceID)
if(cameraList&&cameraList.length>1){
letcameraCount:number=cameraList.length
console.info(`${TAG}cameralist${cameraCount}}`)
if(this.mCurCameraIndex

⑤加載過(guò)度動(dòng)畫(huà)

說(shuō)明:在相機(jī)切換中會(huì)需要釋放原相機(jī)的資源,在重啟新相機(jī),在通過(guò)軟總線通道同步遠(yuǎn)程相機(jī)的預(yù)覽數(shù)據(jù)。 這里需要一些時(shí)間,根據(jù)目前測(cè)試,在網(wǎng)絡(luò)穩(wěn)定狀態(tài)下,切換時(shí)間 3~5s,網(wǎng)絡(luò)不穩(wěn)定狀態(tài)下,切換最長(zhǎng)需要 13s,當(dāng)然有時(shí)候會(huì)出現(xiàn)無(wú)法切換成功,這種情況可能是遠(yuǎn)程設(shè)備已經(jīng)下線,無(wú)法再獲取到數(shù)據(jù)。

代碼如下:

@StateisSwitchDeviceing:boolean=false//是否正在切換相機(jī)

if(this.isSwitchDeviceing){
Column(){
Image($r('app.media.load_switch_camera'))
.width(400)
.height(306)
.objectFit(ImageFit.Fill)
Text($r('app.string.switch_camera'))
.width('100%')
.height(50)
.fontSize(16)
.fontColor(Color.White)
.align(Alignment.Center)
}
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.onClick(()=>{
})
}
至此,分布式相機(jī)的整體流程就已實(shí)現(xiàn)完成。下面我們介紹下分布式相機(jī)開(kāi)發(fā)中所遇到的問(wèn)題。

分布式相機(jī)問(wèn)題一覽

對(duì)于開(kāi)發(fā)過(guò)程中所遇到的一些坑,前面多少有簡(jiǎn)單的提到一些,這里做一次規(guī)整,也算是一次回顧。

①首次授權(quán)成功無(wú)法顯示相機(jī)預(yù)覽

解析:我們正常會(huì)在 MainAbility.ts 的 onCreate() 函數(shù)加載的時(shí)候執(zhí)行申請(qǐng)授權(quán),在 index.ets 頁(yè)面中,當(dāng) XComponent 組件 onLoad() 回調(diào)后執(zhí)行初始化相機(jī)操作,代碼如下:

MainAbility.ts:

constTAG:string='[DistributedCamera]'
letpermissionList:Array=[
"ohos.permission.MEDIA_LOCATION",
"ohos.permission.READ_MEDIA",
"ohos.permission.WRITE_MEDIA",
"ohos.permission.CAMERA",
"ohos.permission.MICROPHONE",
"ohos.permission.DISTRIBUTED_DATASYNC"
]


exportdefaultclassMainAbilityextendsAbility{
asynconCreate(want,launchParam){
console.info(`${TAG}onCreate`)
globalThis.cameraAbilityContext=this.context
awaitglobalThis.cameraAbilityContext.requestPermissionsFromUser(permissionList)
}
}
index.ets:
//...
//截取部分主要代碼

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

//...

應(yīng)用啟動(dòng)后,調(diào)用了 requestPermissionsFromUser() 請(qǐng)求權(quán)限后,但未手動(dòng)授權(quán)時(shí),查看相關(guān)日志:

0694b794-b9cf-11ed-bfe3-dac502259ad0.png

日志告訴我們,page 的生命周期已啟動(dòng)到 onShow,并且頁(yè)面布局也完成了加載,XComponent 組件回調(diào) onLoad()。 但是由于還未授權(quán),導(dǎo)致無(wú)法初始化相機(jī),此時(shí)即便授權(quán)成功,也不會(huì)再進(jìn)行初始化,導(dǎo)致相機(jī)無(wú)法啟動(dòng),無(wú)預(yù)覽視圖。 知道原因后,我們可以有多種方式解決,重點(diǎn)就是在授權(quán)完成后,需要再次觸發(fā)初始化相機(jī),讓相機(jī)啟動(dòng)才可以正常預(yù)覽。

我的處理方式:

在 index.ets 頁(yè)面中處理授權(quán)

定義是否已授權(quán)的標(biāo)識(shí),用于判斷是否可以初始化相機(jī)

定義是否已經(jīng)初始化相機(jī)標(biāo)識(shí),防止對(duì)此初始化

在 page 頁(yè)面初始化函數(shù) aboutToAppear() 中請(qǐng)求權(quán)限,并在權(quán)限申請(qǐng)結(jié)果中添加初始化相機(jī)操作

XComponent 組件回調(diào) onLoad() 初始化相機(jī)操作不變

index.ets:

privateisInitCamera:boolean=false//是否已初始化相機(jī)
privateisPermissions:boolean=false//是否完成授權(quán)

asyncaboutToAppear(){
console.info(`${TAG}aboutToAppear`)
globalThis.cameraAbilityContext.requestPermissionsFromUser(permissionList).then(async(data)=>{
console.info(`${TAG}datapermissions:${JSON.stringify(data.permissions)}`)
console.info(`${TAG}dataauthResult:${JSON.stringify(data.authResults)}`)
//判斷授權(quán)是否完成
letresultCount:number=0
for(letresultofdata.authResults){
if(result===0){
resultCount+=1
}
}
if(resultCount===permissionList.length){
this.isPermissions=true
}
awaitthis.initCamera()
//獲取縮略圖
this.mCameraService.getThumbnail(this.functionBackImpl)
})
}

相機(jī)應(yīng)用未關(guān)閉,系統(tǒng)息屏后重新點(diǎn)亮,重新返回相機(jī)應(yīng)用,無(wú)預(yù)覽輸出流返回

解析:從現(xiàn)象看,預(yù)覽畫(huà)面卡在息屏前的狀態(tài),需要退出應(yīng)用后,重啟應(yīng)用才能正常預(yù)覽。從日志上看沒(méi)有查看到具體的原因,只是 camera_host 的數(shù)據(jù)量日志消失。

猜想:相機(jī)在系統(tǒng)息屏后強(qiáng)制關(guān)閉,需要重新加載相機(jī)才能正常預(yù)覽,實(shí)現(xiàn)方式如下:

在 page 的 onPageShow() 回調(diào)函數(shù)中重新初始化相機(jī)。

在 page 的 onPageHide() 函數(shù)中釋放相機(jī)資源,減少系統(tǒng)資源不必要的消耗。

index.ets:

asynconPageShow(){
console.info(`${TAG}onPageShow`)
awaitthis.initCamera()
}
onPageHide(){
console.info(`${TAG}onPageHide`)
this.isSwitchDeviceing=false
this.isInitCamera=false
this.mCameraService.releaseCamera()
}
結(jié)論:實(shí)踐驗(yàn)證此方法有效解決息屏后點(diǎn)亮返回相機(jī)無(wú)法預(yù)覽的問(wèn)題。

③加載遠(yuǎn)程相機(jī),在會(huì)話管理中添加拍照輸出流,無(wú)法拍照,預(yù)覽黑屏

解析:兩臺(tái)設(shè)備 pin 碼認(rèn)證通過(guò),連接成功,在主控端選擇一臺(tái)被控端設(shè)備時(shí),加載相機(jī),流程與加載本地相機(jī)相同。

流程如下:

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

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

經(jīng)過(guò)排查,發(fā)現(xiàn)日志中返回異常 not found in supported streams,詳情可以查看關(guān)聯(lián)issues。

https://gitee.com/openharmony/distributedhardware_distributed_camera/issues/I6E5ZX
原因:在創(chuàng)建 PhotoOutput 時(shí)需要傳遞支持的拍照配置信息 Profile,這里的 Profile 可以通過(guò)CmeraManager.getSupportedOutputCapability()返回的相機(jī)輸出能力 CameraOutputCapability 對(duì)象獲取,但遠(yuǎn)程相機(jī)設(shè)備拍照輸出能力列表返回空。

但通過(guò)查看本地相機(jī)拍照輸出能力可知 DAYU200 設(shè)備支持的 Profile 信息:

photoProfile{"format":2000,"size":{"width":1280,"height":960}}
通過(guò)此將 photoProfile 作為遠(yuǎn)程相機(jī)設(shè)備構(gòu)建拍照輸出流的入?yún)?chǎng)景拍照輸出流,并把此添加到拍照會(huì)話管理中,但是界面出現(xiàn)不支持此相機(jī)配置,最終關(guān)閉了相機(jī),導(dǎo)致黑屏。 解決方案:根據(jù)此問(wèn)題,目前只能根據(jù)場(chǎng)景判斷是否需要添加拍照輸出流到會(huì)話管理,對(duì)于本地相機(jī)則可以添加拍照輸出流,執(zhí)行拍照業(yè)務(wù),遠(yuǎn)程相機(jī)則不添加拍照輸出流,這也就不能執(zhí)行拍照業(yè)務(wù),希望社區(qū)有解決方案。

④切換不同設(shè)備上的相機(jī),相機(jī)預(yù)覽輸出流出現(xiàn)異常,無(wú)法顯示遠(yuǎn)程相機(jī)的畫(huà)面

解析:此問(wèn)題存在的原因可能有多種,這里我說(shuō)下我遇到的情況。 (1)分布式連接被斷開(kāi),但是因?yàn)榈讓訖C(jī)制,設(shè)備之間下線需要在一段時(shí)間內(nèi)才能上報(bào)(預(yù)計(jì) 5 分鐘),所以在應(yīng)用層看到可以連接的遠(yuǎn)端設(shè)備,其實(shí)已經(jīng)下線了,這時(shí)當(dāng)然不能切換到遠(yuǎn)程相機(jī)。 (2)與問(wèn)題 3 中描述的相同,因?yàn)樘砑恿艘粋€(gè)無(wú)法支持的拍照配置信息導(dǎo)致相機(jī)被關(guān)閉。

解決方案:

等待線下通知,再重新連接設(shè)備,或者等待設(shè)備自動(dòng)完成重連,簡(jiǎn)單粗暴就是重啟設(shè)備。

待社區(qū)反饋。

⑤相機(jī)業(yè)務(wù)在主線程執(zhí)行,需要將業(yè)務(wù)移動(dòng)到子線程,防止 UI 線程堵塞

解析:如題描述,目前可能存在堵塞 UI 線程的可能,需要將一些耗時(shí)的操作移動(dòng)到子線程,比如預(yù)覽、拍照保存圖片等。 目前正在修改優(yōu)化,關(guān)于 ets 的異步線程 worker 可以查看之前寫(xiě)的一篇關(guān)于:OpenHarmony stage worker 多線程。

⑥遠(yuǎn)程相機(jī)預(yù)覽數(shù)據(jù)傳輸存在 500ms 的延遲

解析:在 wifi 環(huán)境下,被控端相機(jī)將預(yù)覽數(shù)據(jù)通過(guò)軟總線傳輸?shù)街骺囟孙@示,有 500ms 左右的延遲,此問(wèn)題待排查,具體是那個(gè)環(huán)境出現(xiàn)的延遲。

⑦no permission for function call

解析:用戶(hù)動(dòng)態(tài)授予:允許不同設(shè)備間的數(shù)據(jù)(ohos.permission.DISTRIBUTED_DATASYNC) 交換權(quán)限后,DeviceManager.startDeviceDiscovery() 啟動(dòng)發(fā)現(xiàn)周邊設(shè)備總會(huì)出現(xiàn)異常。

日志中提示:

discoverFaildata={"subscribeId":26386,"reason":-20007,"errInfo":"nopermissionforfunctioncall."}

原因:非系統(tǒng)應(yīng)用無(wú)法使用 DeviceManager,詳細(xì)可查看:issues。

https://gitee.com/openharmony/distributedhardware_device_manager/issues/I6BYK4
解決方案:系統(tǒng)應(yīng)用和普通應(yīng)用是通過(guò)簽名來(lái)區(qū)分,那只要通過(guò)修改簽名 UnsgnedReleasedProfileTemplate.json 文件中的 app-feature 值為 ohos_system_app,即為系統(tǒng)應(yīng)用。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 攝像頭
    +關(guān)注

    關(guān)注

    60

    文章

    4841

    瀏覽量

    95690
  • 相機(jī)
    +關(guān)注

    關(guān)注

    4

    文章

    1351

    瀏覽量

    53601
  • 設(shè)備
    +關(guān)注

    關(guān)注

    2

    文章

    4509

    瀏覽量

    70637
  • 鴻蒙
    +關(guān)注

    關(guān)注

    57

    文章

    2351

    瀏覽量

    42849
  • OpenHarmony
    +關(guān)注

    關(guān)注

    25

    文章

    3722

    瀏覽量

    16313

原文標(biāo)題:鴻蒙分布式相機(jī)“踩坑”分享

文章出處:【微信號(hào):gh_834c4b3d87fe,微信公眾號(hào):OpenHarmony技術(shù)社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    HarmonyOS鴻蒙操作系統(tǒng)之什么是“基于微內(nèi)核的全場(chǎng)景分布式操作系統(tǒng)”?

    HarmonyOS鴻蒙操作系統(tǒng)之什么是“基于微內(nèi)核的全場(chǎng)景分布式操作系統(tǒng)”?即使作為理工科的人咋一眼看上去似乎也不太懂這是什么,就像區(qū)塊鏈這個(gè)概念剛出來(lái)一樣,普通人都是一臉懵B(當(dāng)然現(xiàn)在我對(duì)這個(gè)也是
    發(fā)表于 09-23 17:06

    鴻蒙分布式任務(wù)調(diào)度

    鴻蒙分布式任務(wù)調(diào)度,實(shí)現(xiàn)跨設(shè)備FA拉起
    發(fā)表于 06-12 17:28

    鴻蒙分布式任務(wù)調(diào)度——數(shù)據(jù)傳遞

    鴻蒙分布式任務(wù)調(diào)度之?dāng)?shù)據(jù)傳遞
    發(fā)表于 06-12 17:29

    HarmonyOS教程一分布式語(yǔ)音照相機(jī)

    文件系統(tǒng)和AI語(yǔ)音識(shí)別功能開(kāi)發(fā)了一款分布式語(yǔ)音照相機(jī),這款相機(jī)能將拍攝的照片實(shí)時(shí)共享到同一分布式網(wǎng)絡(luò)下的不同設(shè)備中,這樣大家都可以看到拍攝的照片,就不需要一窩蜂的跑到一臺(tái)手機(jī)前,不滿意
    發(fā)表于 09-10 09:53

    Linux學(xué)習(xí)過(guò)程過(guò)的與如何解決

    Linux記錄記錄Linux學(xué)習(xí)過(guò)程過(guò)的與如何解決1解決方法:F10進(jìn)入BIOS使能
    發(fā)表于 11-04 08:44

    分布式系統(tǒng)硬件資源池原理和接入實(shí)踐

    提供更好的服務(wù)體驗(yàn)。 圖 3 鴻蒙硬件資源池支持各類(lèi)消費(fèi)者場(chǎng)景 2.2 開(kāi)發(fā)者場(chǎng)景 對(duì)于開(kāi)發(fā)者來(lái)說(shuō),由于分布式硬件資源池將跨設(shè)備硬件調(diào)用的復(fù)雜度都封裝在了系統(tǒng)底層,跨設(shè)備硬件復(fù)用本地硬件的 API
    發(fā)表于 12-06 10:02

    什么是鴻蒙分布式游戲?為什么要做分布式游戲?

    鴻蒙”(Harmony)無(wú)疑是近期以來(lái)最為熱點(diǎn)的話題之一,而在技術(shù)層面上,“分布式”又是鴻蒙最核心的關(guān)鍵點(diǎn)之一,無(wú)論應(yīng)用還是游戲都與之息息相關(guān)。
    的頭像 發(fā)表于 01-30 09:49 ?4629次閱讀

    華為鴻蒙系統(tǒng)之分布式游戲詳解

    鴻蒙”(Harmony)無(wú)疑是近期以來(lái)最為熱點(diǎn)的話題之一,而在技術(shù)層面上,“分布式”又是鴻蒙最核心的關(guān)鍵點(diǎn)之一,無(wú)論應(yīng)用還是游戲都與之息息相關(guān)。
    的頭像 發(fā)表于 01-30 10:42 ?7193次閱讀

    鴻蒙分布式怎么理解

    ”,帶來(lái)設(shè)備內(nèi)和設(shè)備間高吞吐、低時(shí)延、高可靠的流暢連接體驗(yàn)。 ? 1. 介紹 鴻蒙分布式軟總線致力于實(shí)現(xiàn)近場(chǎng)設(shè)備間統(tǒng)一的分布式通信能力,提供不區(qū)分鏈路的設(shè)備發(fā)現(xiàn)和傳輸接口,具備快速發(fā)現(xiàn)并連接設(shè)備,高效分發(fā)任務(wù)和傳輸數(shù)據(jù)。作為多終
    的頭像 發(fā)表于 07-08 14:47 ?4506次閱讀

    鴻蒙系統(tǒng)底層架構(gòu) 鴻蒙系統(tǒng)分布式架構(gòu)

    鴻蒙系統(tǒng)是一款面向未來(lái)、面向全場(chǎng)景的分布式操作系統(tǒng),鴻蒙系統(tǒng)開(kāi)創(chuàng)性地提出了基于同一套系統(tǒng)能力、適配多種終端形態(tài)的分布式理念,在這個(gè)理念加持下,可支持多種終端設(shè)備。
    的頭像 發(fā)表于 07-08 14:35 ?1.3w次閱讀

    分享一個(gè)有趣的鴻蒙分布式小游戲

    ?? 今天給大家分享一個(gè)有趣的鴻蒙分布式小游戲:你畫(huà)我猜。 ??? ? 開(kāi)發(fā)心得(如有錯(cuò)誤還請(qǐng)大佬及時(shí)指正): ? 分布式流轉(zhuǎn): 一個(gè) APP 應(yīng)用在設(shè)備之間互相拉起遷移,只在一個(gè)終端上運(yùn)行
    的頭像 發(fā)表于 11-01 14:29 ?2558次閱讀
    分享一個(gè)有趣的<b class='flag-5'>鴻蒙</b><b class='flag-5'>分布式</b>小游戲

    嵌入Linux記錄

    Linux記錄記錄Linux學(xué)習(xí)過(guò)程過(guò)的與如何解決1解決方法:F10進(jìn)入BIOS使能
    發(fā)表于 11-01 17:21 ?10次下載
    嵌入<b class='flag-5'>式</b>Linux<b class='flag-5'>踩</b><b class='flag-5'>坑</b>記錄

    鴻蒙版JS如何實(shí)現(xiàn)分布式仿抖音應(yīng)用

    ?? 之前大家看過(guò)了 Java 版的《 HarmonyOS 分布式之仿抖音應(yīng)用 》,現(xiàn)在講講 JS 如何實(shí)現(xiàn)分布式仿抖音應(yīng)用,通過(guò) JS 方式開(kāi)發(fā)視頻播放,分布式設(shè)備遷移,評(píng)論,通過(guò) Java
    的頭像 發(fā)表于 11-15 09:44 ?2370次閱讀

    OpenHarmony技術(shù)論壇:分布式相機(jī)分布式圖庫(kù)功能

    《OpenHarmony Tech Day·技術(shù)日》 技術(shù)論壇 新增分布式相機(jī)分布式圖庫(kù)功能 相比OpenHarmony 3.0版本,OpenHarmony 3.1版本的相機(jī)框架新增
    的頭像 發(fā)表于 04-25 15:06 ?1830次閱讀
    OpenHarmony技術(shù)論壇:<b class='flag-5'>分布式</b><b class='flag-5'>相機(jī)</b>和<b class='flag-5'>分布式</b>圖庫(kù)功能

    鴻蒙OS 分布式任務(wù)調(diào)度

    鴻蒙OS 分布式任務(wù)調(diào)度概述 在 HarmonyO S中,分布式任務(wù)調(diào)度平臺(tái)對(duì)搭載 HarmonyOS 的多設(shè)備構(gòu)筑的“超級(jí)虛擬終端”提供統(tǒng)一的組件管理能力,為應(yīng)用定義統(tǒng)一的能力基線、接口
    的頭像 發(fā)表于 01-29 16:50 ?497次閱讀