系列文章
- [Android P] CameraAPI1 轉 HAL3 預覽流程(一) — 背景概述
- [Android P] CameraAPI1 轉 HAL3 預覽流程(二) — startPreview
- [Android P] CameraAPI1 轉 HAL3 預覽流程(三) — setPreviewCallbackFlag
- [Android P] CameraAPI1 轉 HAL3 預覽流程(四) — Preview Data
正文
HAL3 強制升級已經有一年左右了,和 HAL3 搭配的 Camera API2 目前已經改用的三方相機應用還並不算多,所以爲了更好地 debug 三方相機相關的卡頓問題,我近期花時間專門研究了 Android Framework 層提供的 API1 轉 API2 連接 HAL3 的邏輯(以啓動預覽、預覽數據流爲例),以便對轉換過程有一個總體認識,並且對經常遇到的兩個由於 API 邏輯轉換導致的卡頓問題進行更細緻的分析。
先說說目前幾個項目經常碰到的兩種卡頓現象:
- 啓動預覽後出現短暫預覽卡頓現象,然後恢復正常;
- 預覽過程中偶現卡頓(但應用自身、GPU 都沒有很長耗時的情況);
第一種卡頓的原理,以及示意圖如下:
- APP 啓動預覽採用的是
startPreview
+setPreviewCallbackWithBuffer
的方式; - 後發調用
setPreviewCallbackWithBuffer
相當於增加一路 stream,會觸發 HAL3 邏輯下的 re-config 機制,相當於再啓動一次預覽; startPreview
調用成功後會先有一些預覽數據出來;setPreviewCallbackWithBuffer
最終調用到的setPreviewCallbackFlag
觸發 re-config,取消了前面出來的預覽幀,導致無數據而卡頓一小段時間;- 後續的預覽過程不會受到影響。
第二種卡頓的原理,以及示意圖如下:
- APP 使用 preview callback 這路數據去做預覽(因爲應用本身想要對數據進行一些客製化操作);
- 每一次數據幀上傳後,JNI 部分
copyAndPost
調用時若 CallbackBuffer 被取空了,則會把 callbackEnabled 這個標記設置爲 false(APP 接着調用addCallbackBuffer
的時候纔會設置回 true); - 此時 streamList size 爲 1;
- 如果剛好在這時 RequestThread 執行到
prepareHalRequests
,就會只准備 preview stream 的 buffer,而 callback 的 buffer 就沒有準備; - 這一次 Request 對應的 Result 裏沒有 callback 這一路的數據(會有 preview 的數據,但 APP 並不是用這一路數據做預覽,或者取 preview 的時機取決於 callback 數據處理完的時間點),最終出現預覽卡頓現象。
這兩種卡頓實際上都與 Framework 層中 API1 轉 API2 的邏輯有關,如果三方應用都按照 Google 標準轉用 API2 的話,就不會有這兩種問題。
當然,現在對於整個 Android 生態來說 API2 還是新東西,升級適配需要一些過渡。而且有些應用設計得比較簡單,只需要考慮打開預覽、拿預覽數據做處理就完了,改換 API2 要花費不少精力重新設計,其實用 API1 對他們來說也是合情合理的。
可以預見的是,在今後相當一段時間內,我們每個項目都要對一些 API1 的三方相機進行 debug,所以還是有必要對 API1 轉 HAL3 的流程進行一些細緻的瞭解的。
而這兩類問題的解法(在保持 API1 的情況下)通常是:
- 對於第一種卡頓問題,需要 APP 把
setPreviewCallbackWithBuffer
放在startPreview
前面(實際上 Google 也沒有規定這兩個方法誰要在前),這樣一次就 config 了兩路 stream,就不會觸發 re-config 的情況了; - 對於第二種卡頓問題,可以讓 APP 多調用一次
addCallbackBuffer
,這樣保證 APP 自己帶下來的 Buffer 足夠,在copyAndPost
時就不會觸發到setPreviewCallbackFlags(0x00)
; - 對於第二種卡頓問題,還可以想辦法把 callbackEnabled 控制爲 true,這樣也可以實現
prepareHalRequests
時不會缺 Callback 這一路的 request。
爲了更清晰地瞭解這些解決方案的原理,我花了點時間探索了一下 API1 轉 HAL3 在 Framework 層中的整體運作機制,接下來幾篇文章將要分別詳細介紹這幾個內容:
startPreview
流程;setPreviewCallbackFlag
流程;- 持續預覽時 Request 和 Result 對應的流程。