Android Camera2 每次拍照前觸發(fā)閃光燈打閃的實現(xiàn)

如下內(nèi)容方便有Camera2基礎(chǔ)人查看晴埂,如不了解Camera2的人不建議查看澳泵。

拍照流程
先執(zhí)行CaptureRequest.CONTROL_AF_TRIGGER_START鎖定AF授翻,然后根據(jù)回調(diào)不斷判斷AF狀態(tài)刚梭,偽代碼實現(xiàn)如下

Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
    //--執(zhí)行拍照`
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
    //--判斷AE狀態(tài)
}

判斷AF狀態(tài)是lock或者unlock之后還需要在進一步判斷AE狀態(tài)是否收斂重慢,然后在執(zhí)行拍照。AF狀態(tài)lock或unlock后判斷AE狀態(tài)判斷偽代碼如下

if (afState == null) {
    `//--執(zhí)行拍照`
} else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
    if (aeState == null ||
        aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
        //--執(zhí)行拍照
    } else {
        //--AE未收斂师溅,主動執(zhí)行AE_trigger_start
    }
}

如果AE未收斂則主動觸發(fā)一次AE操作執(zhí)行CONTROL_AE_PRECAPTURE_TRIGGER_START茅信,然后根據(jù)Capture回調(diào)判斷AE狀態(tài),偽代碼如下:

Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null ||
    aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
    aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
    //--鎖定AE
}

AE收斂完成墓臭,為了確保場景亮度變化自動觸發(fā)AE蘸鲸,這里需要鎖定AE,偽代碼如下

final CaptureRequest.Builder captureBuilder;
try {
    captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
    captureBuilder.addTarget(mPreviewSurface);
    setAutoFlash(captureBuilder);
    //--鎖定AE
    captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
    try {
        mCaptureSession.setRepeatingRequest(captureBuilder.build(), mCaptureCallback, mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
        Log.d("ArMn", "--------STATE_WATTING_LOCK_AE--------Excepture" );
    }
} catch (CameraAccessException e) {
    e.printStackTrace();
        }

//---監(jiān)聽AE LOCK狀態(tài)
if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
    //--------執(zhí)行拍照
}

在AF和AE都滿足拍照條件后起便,執(zhí)行拍照棚贾。如上是拍照中AF和AE狀態(tài)處理流程,也是確保圖片質(zhì)量的關(guān)鍵點榆综。

現(xiàn)在我們討論下如何在每次拍照前觸發(fā)一次閃光燈
在每次拍照前觸發(fā)閃光燈需要遵循多個條件

  • 條件一
    AE_MODE需要設置成CONTROL_AE_MODE_ON_ALWAYS_FLASH
  • 條件二
    FLASH_MODE需要設置成FLASH_MODE_SINGLE

完整代碼實現(xiàn)如下:

按下拍照按鈕

private void takePicture() {
    lockFocus();
}

鎖AF(如果在鎖定AF之前設置了CONTROL_AE_REGIONS,則AF LOCK會觸發(fā)打閃)

private void lockFocus() {
    try {
        // This is how to tell the camera to lock focus.
        mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_START);
        // Tell #mCaptureCallback to wait for the lock.
        mState = STATE_WAITING_LOCK;
        mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

判斷AF狀態(tài)

case STATE_WAITING_LOCK: {
    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
    Log.d("ArMn", "--------- STATE_WAITING_LOCK-------afState: " + afState);
    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;
            Log.d("ArMn", "--------captureStillPicture--------");
            captureStillPicture();
        } else {
            Log.d("ArMn", "--------runPrecaptureSequence--------");
              runPrecaptureSequence();
        }
    }
    break;
}

執(zhí)行AE打閃(如果AF沒有觸發(fā)打閃铸史,則此處會觸發(fā)打閃)

private void runPrecaptureSequence() {
    try {
        final CaptureRequest.Builder captureBuilder =
                mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        captureBuilder.addTarget(mImageReader.getSurface());
        setAutoFlash(captureBuilder);
        captureBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
        // This is how to tell the camera to trigger.
        // Tell #mCaptureCallback to wait for the precapture sequence to be set.
        mState = STATE_WAITING_PRECAPTURE;
        mCaptureSession.capture(captureBuilder.build(), mCaptureCallback,
                mBackgroundHandler);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }

判斷AE打閃狀態(tài)

case STATE_WAITING_PRECAPTURE: {
    // CONTROL_AE_STATE can be null on some devices
    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
    Log.d("ArMn", "--------STATE_WAITING_PRECAPTURE--------aeState: " + aeState);
    if (aeState == null ||
            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
        mState = STATE_WATTING_LOCK_AE;
    }
    break;

鎖定AE狀態(tài)

    private void lockAe() {
        mState = STATE_WAITING_NON_PRECAPTURE;
        final CaptureRequest.Builder captureBuilder;
        try {
            captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            captureBuilder.addTarget(mPreviewSurface);
            setAutoFlash(captureBuilder);
            captureBuilder.set(CaptureRequest.CONTROL_AE_LOCK, Boolean.TRUE);
            try {
                mCaptureSession.setRepeatingRequest(captureBuilder.build(), mCaptureCallback, mBackgroundHandler);
            } catch (CameraAccessException e) {
                e.printStackTrace();
                Log.d("ArMn", "--------STATE_WATTING_LOCK_AE--------Excepture" );
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

判斷AE鎖定狀態(tài)

case STATE_WAITING_NON_PRECAPTURE: {
    // CONTROL_AE_STATE can be null on some devices
    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
    Log.d("ArMn", "--------captureStillPicture-- STATE_WAITING_NON_PRECAPTURE ------state: " + aeState);
    if (aeState == null || aeState == CaptureResult.CONTROL_AE_STATE_LOCKED) {
        mState = STATE_PICTURE_TAKEN;
        captureStillPicture();
    }
    break;
}

執(zhí)行拍照

private void captureStillPicture() {
    try {
        final Activity activity = getActivity();
        if (null == activity || null == mCameraDevice) {
            return;
        }
        // This is the CaptureRequest.Builder that we use to take a picture.
        final CaptureRequest.Builder captureBuilder =
                mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(mImageReader.getSurface());
        // Use the same AE and AF modes as the preview.
        captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        setAutoFlash(captureBuilder);
        mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
    } catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

注意: 不要在鎖定AE的時候下發(fā)CONTROL_AE_PRECAPTURE_TRIGGER鼻疮,不然會導致閃光燈常亮。 建議每觸發(fā)一次capture都重新創(chuàng)建一次CapureRequest對象琳轿。 如果在觸發(fā)CONTROL_AE_PRECAPTURE_TRIGGER成功之后不鎖定AE判沟,閃光燈會很快關(guān)閉。如果執(zhí)行了鎖定AE會在AE狀態(tài)lock后關(guān)閉

Flash常用的如下設置(摘抄高通Camera源碼)

    private void applyFlash(CaptureRequest.Builder request, String value) {

        switch (value) {
            case "on":
                if (mLongshotActive) {
                    request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                    request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
                } else {
                    request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_ALWAYS_FLASH);
                    request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
                }
                break;
            case "auto":
                if (mLongshotActive) {
                    // When long shot is active, turn off the flash in auto mode
                    request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                    request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                } else {
                    request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
                    request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_SINGLE);
                }
                break;
            case "off":
                request.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
                request.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
                break;
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末崭篡,一起剝皮案震驚了整個濱河市挪哄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琉闪,老刑警劉巖迹炼,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異颠毙,居然都是意外死亡斯入,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門蛀蜜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來刻两,“玉大人,你說我怎么就攤上這事滴某“跄。” “怎么了滋迈?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長户誓。 經(jīng)常有香客問我杀怠,道長,這世上最難降的妖魔是什么厅克? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任赔退,我火速辦了婚禮,結(jié)果婚禮上证舟,老公的妹妹穿的比我還像新娘硕旗。我一直安慰自己,他們只是感情好女责,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布漆枚。 她就那樣靜靜地躺著,像睡著了一般抵知。 火紅的嫁衣襯著肌膚如雪墙基。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天刷喜,我揣著相機與錄音残制,去河邊找鬼。 笑死掖疮,一個胖子當著我的面吹牛初茶,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播浊闪,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼恼布,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搁宾?” 一聲冷哼從身側(cè)響起折汞,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盖腿,沒想到半個月后爽待,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡奸忽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年堕伪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栗菜。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡欠雌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出疙筹,到底是詐尸還是另有隱情富俄,我是刑警寧澤禁炒,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站霍比,受9級特大地震影響幕袱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悠瞬,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一们豌、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧浅妆,春花似錦望迎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至康辑,卻和暖如春摄欲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疮薇。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工胸墙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惦辛。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓劳秋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親胖齐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345