天天看點

Android中Camera的聚焦流程---應用層

在Camera中,autofocus是個很重要的知識點,一般有移動對焦,點選聚焦和長按聚焦,這裡我們以展銳平台相機的點選聚焦為例,分析下聚焦在app層的流程。

1、聚焦觸發

點選螢幕事件的觸發

PhotoModule.java的onSingleTapUp中

public void onSingleTapUp(View view, int x, int y) {
 	......
 	//調用FocusManager的singletap
 	mFocusManager.onSingleTapUp(x, y);
 }
           

FocusOverlayManager.java的onSingleTapUp中

public void onSingleTapUp(int x, int y) {
         
        lastSingleTap.set(x,y);
        //如果目前已經是定焦的,取消定焦,重新對焦
        if(isAFLock) {
            sendCancleMsg(false);
            mListener.setAELock(false);
            isAFLock = false;
        }

        //沒有初始化或者拍照前的聚焦的狀态,直接傳回
        if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) { 
            return;
        }
        //讓使用者可以取消掉之前未消失的觸摸聚焦
        if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
                mState == STATE_SUCCESS || mState == STATE_FAIL)) { 
            cancelAutoFocus();
        }
        if (mPreviewRect.width() == 0 || mPreviewRect.height() == 0) {
            return;
        }
     
        // Initialize variables.
        if (mAutoChasingSupported && mAutoChasingEnable){
            boolean isChasing = isAutoChasing();
            if (isChasing) {
                initializeAutoChasingRegion(0,0);
                Log.d(TAG,"set chasing Region x = 0 , y = 0");
                mListener.setAutoChasingParameters();
            }
        }

        //初始化聚焦的區域
        // Initialize mFocusArea.
        if (mFocusAreaSupported) {
            initializeFocusAreas(x, y);
            mFocusRing.setFocusLocation(x, y);
        }
        // Initialize mMeteringArea.
        if (mMeteringAreaSupported) {
            initializeMeteringAreas(x, y);
        }

        // Log manual tap to focus.
        mTouchCoordinate = new TouchCoordinate(x, y, mPreviewRect.width(), mPreviewRect.height());
        mTouchTime = System.currentTimeMillis();

        //停止人臉識别,因為要進行識别聚焦和測量area
        mListener.stopFaceDetection();

        //設定聚焦區域&測量區域
        mListener.setFocusParameters();

        
        if (mFocusAreaSupported) {
            autoFocus();//開始對焦
        } else {  // Just show the indicator in all other cases.
            // Reset the metering area in 4 seconds.
            mHandler.removeMessages(RESET_TOUCH_FOCUS);
            mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
        }
    }
           

接着看FocusOverlayManager這裡的autoFocus()方法

private void autoFocus(int focusingState) {
        //監聽autofocus,這裡autofocus的實作是PhotoModule中
        mListener.autoFocus();
        //目前focus的狀态設定成正在focus
        mState = focusingState;
        //更新正在對焦的對焦框ui
        updateFocusUI();
        mHandler.removeMessages(RESET_TOUCH_FOCUS);
        initializeCameraSound();
    }
           

在PhotoMudule.java中的autoFocus()中

@Override
    public void autoFocus() {
        if (mCameraDevice == null) {
            return;
        }
        mNeedCancelAutoFocus = true;
        mFocusStartTime = System.currentTimeMillis();
        //設定Camera的回調聚焦
        mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
        //設定相機的狀态為FOCUSING
        setCameraState(FOCUSING);
    }
           

2、聚焦完成回調

接着看上層對于聚焦的回調處理,在PhotoModule中有内部類AutoFocusCallback

private final class AutoFocusCallback implements CameraAFCallback {
        @Override
        public void onAutoFocus(boolean focused, CameraProxy camera) {
            //如果是暫停狀态,不聚焦
            if (mPaused) {
                return;
            }
            //算出目前到聚焦開始的時間差
            mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
            //設定Camera狀态為IDLE
            setCameraState(IDLE);
            //調用FocusManager中的onAutoFocus
            mFocusManager.onAutoFocus(focused, false);
        }
    }
           

接着去看聚焦完成的具體處理

在FocusManager的onAutoFocus中

public void onAutoFocus(boolean focused, boolean shutterButtonPressed) {
        //正在進行聚焦,拍照動作必須再聚焦完之後
        if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
            // 無論聚焦成功還是失敗,都會拍照。如果要進行拍照發聲,就無需AF發聲了
            if (focused) {
                //聚焦成功
                mState = STATE_SUCCESS;
            } else {
                //聚焦失敗
                mState = STATE_FAIL;
            }

            //更新聚焦完成的ui以及各種狀态的設定
            updateFocusUI();
            //拍照,mState的狀态變為STATE_IDLE
            capture();

            //如果是聚焦中的狀态
        } else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
            //此狀态的發生分為兩種,half-pressing按壓聚焦或者觸摸聚焦被觸發,這個時候不要發生拍照動作
            if (focused) {
                mState = STATE_SUCCESS;
            } else {
                mState = STATE_FAIL;
            }
            //如果是觸摸聚焦,需要延遲一下取消掉聚焦
            if (mFocusArea != null) {
                mFocusLocked = true;
                if(!isAFLock) {
                    mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
                }
            }
            //更新聚焦完成的ui
            if(!isAFLock) {
                updateFocusUI();
                autoChase();
            } else {
                mFocusRing.setAELockColor(true);
            }
            if (shutterButtonPressed) {
                // Lock AE & AWB so users can half-press shutter and recompose.
                lockAeAwbIfNeeded();
            }
        } else if (mState == STATE_IDLE) {
            // User has released the focus key before focus completes.
            // Do nothing.
        }
    }
           

3、取消聚焦

在FocusManager()中的cancleAutofocus()

private void cancelAutoFocus() {
        //清除聚焦區域
        clearAfArea();
        mMeteringArea = null;
        //監聽cancelAutoFocus,在PhotoModule中實作
        mListener.cancelAutoFocus();
        //重置聚焦,聚焦框恢複到螢幕中間
        resetTouchFocus();
        //改變聚焦狀态
        mState = STATE_IDLE;
        mFocusLocked = false;
        //移除msg
        mHandler.removeMessages(RESET_TOUCH_FOCUS);
    }
           

在PhotoModule的cancelAutoFocus()中

public void cancelAutoFocus() {
        if (mCameraDevice == null) {
            return;
        }
        //取消底層聚焦
        mCameraDevice.cancelAutoFocus();
        //設定相機狀态
        setCameraState(IDLE);
        if (mFace != null && mFace
                && isCameraIdle() && !isHdr() ) {
            //開始人臉檢測
            startFaceDetection();
        }
        setCameraParameters(UPDATE_PARAM_PREFERENCE);
    }
           

以上就是app層聚焦的大緻流程

4、更新聚焦框ui

前面有好幾處有更新ui的操作,我們來看一下具體做了些什麼,其實就是對于聚焦框的改變與展示。

在FucusManager的updateFocusUI中:

public void updateFocusUI() {
        //沒有初始化完成
        if (!mInitialized) {
            // Show only focus indicator or face indicator.
            return;
        }
        //聚焦開始,mFocusRing為聚焦框,可自定義
        if (mState == STATE_IDLE) {
            if (mFocusArea != null) {
                mFocusRing.startActiveFocus();
            }
            //正在聚焦
        } else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
            if (mFocusArea == null) {
                mFocusRing.centerFocusLocation();
            }
            mFocusRing.startActiveFocus();
        } else {
            //聚焦成功
            if (mState == STATE_SUCCESS) {
                //拍照
                if (mTouchListener != null) {
                    mTouchListener.touchCapture();
                }
                //聚焦完成顯示的對焦框
                mFocusRing.startActiveFocusedFocus();
                //聚焦成功的聲音
                if (mFocusArea != null) {
                    if (mAppController.isPlaySoundEnable()) {
                        mCameraSound.play(MediaActionSound.FOCUS_COMPLETE);
                    }
                } else {
                    mFocusRing.centerFocusLocation();
                }
                //聚焦失敗
            } else if (mState == STATE_FAIL) {
                if (mTouchListener != null) {
                    mTouchListener.touchCapture();
                }
                mFocusRing.startActiveFocusedFocus();
            }
        }
    }
           

5、相機狀态和聚焦狀态

聚焦過程中,相機狀态的改變和聚焦狀态的改變

相機狀态:

在PhotoModule中設定相機狀态:

protected void setCameraState(int state) {
        mCameraState = state;
        switch (state) {
        case PREVIEW_STOPPED:
        case SNAPSHOT_IN_PROGRESS:
        case SWITCHING_CAMERA:
            // TODO: Tell app UI to disable swipe
            break;
        case PhotoController.IDLE:
            // TODO: Tell app UI to enable swipe
            break;
        }
    }
           

聚焦狀态:

STATE_IDLE:空閑狀态

capture():空閑狀态可以執行拍照
onAutoFocus(boolean focused):使用者再聚焦完成前放掉了聚焦按鈕,是以不做任何事。
onPreviewStarted(),onPreviewStopped():狀态都變為空閑
cancelAutoFocus():取消聚焦,狀态變為空閑
updateFocusUI():如果空閑&有聚焦區域,顯示聚焦框
           

STATE_FOCUSING:正在對焦

onShutterUp():如果是focusmode為自動聚焦,狀态為正在聚焦,則取消掉聚焦
capture():如果是正在聚焦狀态,将狀态改為聚焦完拍照狀态
onAutoFocus(boolean focused, boolean shutterButtonPressed):判斷focused,為true變為聚焦成功狀态,為false變為聚焦失敗狀态
onSingleTapUp(int x, int y):如果正在聚焦&之前有手動聚焦了,則取消掉之前的聚焦
autoFocus():狀态變為聚焦狀态
updateFocusUI():顯示聚焦框
           

STATE_FOCUSING_SNAP_ON_FINISH:聚焦完拍照

onShutterUp():狀态不是聚焦完拍照,可以設定FocusParameters
onAutoFocus(boolean focused, boolean shutterButtonPressed):判斷focused,為true變為聚焦成功狀态,為false變為聚焦失敗狀态,更新聚焦框UI
onSingleTapUp(int x, int y):直接不繼續操作下去
updateFocusUI():顯示聚焦框
           

STATE_SUCCESS:聚焦成功

onShutterDown():如果是自動聚焦mode,并且不為聚焦成功狀态,執行聚焦
onShutterUp(): 如果是自動聚焦mode,并且為聚焦成功狀态,執行取消聚焦
capture():拍照
onSingleTapUp(int x, int y):讓使用者可以取消掉之前未消失的觸摸聚焦
updateFocusUI():聚焦框顯示成功
           

STATE_FAIL:聚焦失敗

onShutterDown():如果是自動聚焦mode,并且不為聚焦失敗狀态,執行聚焦
onShutterUp(): 如果是自動聚焦mode,并且為聚焦失敗狀态,執行取消聚焦
capture():拍照
onSingleTapUp(int x, int y):讓使用者可以取消掉之前未消失的觸摸聚焦
updateFocusUI():聚焦框顯示失敗
           

關于底層的實作,主要是聚焦指令的下發(開始聚焦和結束聚焦),以及聚焦完成的回調

//開始聚焦
mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);//mCameraDevice為CameraProxy的引用,mAutoFocusCallback為聚焦完成的回調

//取消聚焦
mCameraDevice.cancelAutoFocus();
           

CameraProxy為CameraAgent的内部類

具體實作又在AndroidCamera2AgentImpl中,有興趣的朋友可以自行檢視源碼