
??想了解更多關于開源的內容,請訪問:??
??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()請求權限后,但未手動授權時,查看相關日志:

日志告訴我們,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??