1. 程式人生 > >關於Android Camera2 API 的自動對焦的坑

關於Android Camera2 API 的自動對焦的坑

https://www.jianshu.com/p/280e5301b7b9

一、使用。關於Camera2的API使用,參考Google官方的例子:
Camera2Basic
Camera2Raw
Camera2Video
這是一手資料,配合官方的資料理解Camera2 API的底層原理:
3A 模式和狀態轉換

二、關於Camera2 API 的一些坑。
本人應公司要求,預研Camera2 相關API以及封裝。在參考Camera2Basic 編寫相機應用時,本人發現了Camera2 API 的關於自動對焦的一個非常嚴重的BUG。在此記錄下來,希望後來者在使用Camera2 API時,慎重選擇。
Camera2Basic 中出現問題的程式碼如下:

private CameraCaptureSession.CaptureCallback mCaptureCallback
            = new CameraCaptureSession.CaptureCallback() {

        private void process(CaptureResult result) { switch (mState) { case STATE_PREVIEW: { // We have nothing to do when the camera preview is working normally. break; } case STATE_WAITING_LOCK: { Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); if (afState == null) { captureStillPicture(); } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } else { runPrecaptureSequence(); } } break; } case STATE_WAITING_PRECAPTURE: { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) { mState = STATE_WAITING_NON_PRECAPTURE; } break; } case STATE_WAITING_NON_PRECAPTURE: { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } break; } } } @Override public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) { process(partialResult); } @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { process(result); } }; 

出現問題的程式碼如下:

case STATE_WAITING_LOCK: {
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    if (afState == null) {
                        captureStillPicture();
                    } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } else { runPrecaptureSequence(); } } break; } 

呼叫拍照方法後,會進入STATE_WAITING_LOCK狀態,此時獲取Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);的對焦狀態afState 在某些機器上面,連續拍了幾張圖片之後,afState 會一直處於CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN狀態,表示一個持續聚焦的演算法正在做掃描。鏡頭正在移動中。然而實際上你並沒有移動鏡頭。這裡會導致後續的對焦完成ImageReader取出對焦完成的影象資料無法進行。也就是無法再拍照了。這是我測試得到的log:


  對焦狀態

afState 的狀態為1,即CONTROL_AF_STATE_PASSIVE_SCAN。無法再繼續走到後續的CONTROL_AF_STATE_FOCUSED_LOCKED 和 CONTROL_AF_STATE_NOT_FOCUSED_LOCKED 狀態,導致無法取出影象資料,進而完成拍照功能。

測試裝置:紅米5 Plus

而且這個狀態出錯的情況一旦出現,就只能關掉相機重新開啟才能恢復正常。由於手上的裝置有限,無法做更多的測試。但至少這個情況在MIUI系統上非常大概率出現,基於MIUI國內的市場份額,對於這種情況,只有兩種解決方案,要麼放棄Camera2在拍照時的自動對焦,要麼放棄使用Camera2 API。暫時沒有找到滿意的解決方法。

關於放棄拍照時自動對焦方案是:

// 等待對焦被鎖定
                case STATE_WAITING_LOCK: {
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                    if (afState == null) {
                        Log.d(TAG, "STATE_WAITING_LOCK: mState = STATE_WAITING_LOCK;"); captureStillPicture(); } else if ( CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN == afState || CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState || CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) { // CONTROL_AE_STATE can be null on some devices Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); if (aeState == null || (CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN != afState && aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED)) { mState = STATE_PICTURE_TAKEN; captureStillPicture(); } else { runPrecaptureSequence(); } } Log.d(TAG, "process: afState = " + afState); break; } 

加入CONTROL_AF_STATE_PASSIVE_SCAN 狀態的判斷,對於出現一直出現CONTROL_AF_STATE_PASSIVE_SCAN的情況時,直接走下一層的AE曝光處理runPrecaptureSequence()流程,此時可能會因為無法對焦,畫面層次感丟失的情況。
如果有人有更好的解決方案。希望能夠分享一下。個人感覺目前Camera2 API的坑相當的多,至少在使用的時候,注意一些深坑。



作者:cain_huang
連結:https://www.jianshu.com/p/280e5301b7b9
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。