Camera: Focus 影响因素与状态管理及下发(二)

        Auto-Focus(AF)  Tag下发主要是研究点击UI界面,选定特定的聚焦区域,如何从应用层下发关键Tag驱使底层对Focus State进行改变,主要是针对ACTIVE的变化状态的研究。

1.点击手机屏幕触发聚焦效果

        结合之前俩篇文章,点击屏幕触发的是onSingleTapUp事件,而且肯定也会涉及到request的下发,但是与前篇文章不同之处在于下发的Tag不仅仅是AF Mode、AF Regions、AF Trigger了。

@Override
    public boolean onSingleTapUp(float x, float y) {
        if (mNeedShowFocusUi) {
            mFocusViewController.showActiveFocusAt((int) x, (int) y);
        }

        mModeHandler.post(new Runnable() {
            @Override
            public void run() {
                //API2 face detection need to config face detect mode
                if (mSettingChangeRequester != null) {
                    //此时下发的Auto-Focus是还没有更新的状态
                    mSettingChangeRequester.sendSettingChangeRequest();
                }

                //更新下发的AF Region Tag对应的value为lens需要聚焦的区域
                mFocusListener.updateFocusArea(mFocusArea, mMeteringArea);

                //更新下发的AF Mode Tag对应的value为AF_MODE_AUTO
                mFocusListener.updateFocusMode("auto");

                //这边对各种其他的TAG进行处理以及设置
                mFocusListener.autoFocus();
            }
        });
        LogHelper.d(mTag, "[onSingleTapUp]-");
        return false;
    }
//AF Regions的更新
@Override
    public void updateFocusArea(List<Camera.Area> focusArea, List<Camera.Area> meteringArea) {
        if (focusArea != null) {
            mResetAFRoi = checkRectValue(focusArea, mAfRegion);
            mAFRegions = new MeteringRectangle[]{new MeteringRectangle(focusArea.get(0).rect,
                    CAMERA2_REGION_WEIGHT)};
        }
        if (meteringArea != null) {
            mResetAERoi = checkRectValue(meteringArea, mAeRegion);
            mAERegions = new MeteringRectangle[]{new MeteringRectangle(meteringArea.get(0).rect,
                    CAMERA2_REGION_WEIGHT)};
        }
    }

//AF Mode更新
@Override
    public void updateFocusMode(String currentValue) {
        if (getSettingEntryValues().contains(currentValue)) {
            mExpectedFocusMode = convertStringToEnum(currentValue);
            sendSettingChangeRequest();
        }
    }

         之前忘记讲了一点AF_MODE对应的6种状态,分别为:AF_MODE_OFF(0)、AF_MODE_AUTO(1)、AF_MODE_MACRO(2)、AF_MODE_CONTINUOUS_VIDEO(3)、AF_MODE_CONTINUOUS_PICTURE(4)、AF_MODE_EDOF(5)。

        接下来check最关键AF ACTIVE通过改变拍照请求capture request,进而改变Lens的聚焦区域,进而驱使底层做出对AF state的改变的过程。

    private void sendAutoFocusTriggerCaptureRequest(boolean needCancelAutoFocus) {
        //AF Trigger value设置为CONTROL_AF_TRIGGER_START状态
        builder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_START);        

        if (needCancelAutoFocus && mKeyFlashCalibrationRequest != null) {
            builder.set(mKeyFlashCalibrationRequest, FLASH_CALIBRATION_ON);
        }
       
        
        Camera2CaptureSessionProxy sessionProxy = mDevice2Requester.getCurrentCaptureSession();
        if (sessionProxy == null) {
            return;
        }
        if(mNeedWaitTafDone && !needCancelAutoFocus){
            //根据mNeedWaitTafDone 状态进行判断,如果capture request已经下发,则发送CONTROL_AF_TRIGGER_CANCEL的value
            sendAutoFocusCancelCaptureRequest();
            mNeedWaitTafDone = false;
        }
        try {
            if (SLOW_MOTION.equals(mFocus.getCurrentMode()) && mFocus.isHighSpeedRequest()) {
                List<CaptureRequest> captureRequests = null;
                captureRequests = sessionProxy.createHighSpeedRequestList(builder.build());
                //这边下发的是Slowmotion HighSpeedSession capture 拍照的request
                sessionProxy.captureBurst(captureRequests, mPreviewCallback, mModeHandler);
            } else {
                //这边下发的是正常的session capture请求
                sessionProxy.capture(builder.build(), mPreviewCallback, mModeHandler);
            }
            mStartTime = System.currentTimeMillis();

            mNeedWaitTafDone = true;

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

        //这边会再发一次预览Preview的request请求,这边的AF mode、AF regions、AF trigger都会发生变化
        sendSettingChangeRequest();
    }

         上图为应用层下发Auto-Focus下不同的拍照请求后,底层拿到的capture request的相关数据。需要注意的是发送拍照的capture request时的AF Trigger value与下发预览的request以及sendAutoFocusCancelCaptureRequest时的值是不一样的。

//这边的预览请求是由上面的sendSettingChangeRequest()触发的,其中AF mode、AF regions已经发生更新
private void addBaselineCaptureKeysToRequest(CaptureRequest.Builder builder) {
        builder.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions);
        builder.set(CaptureRequest.CONTROL_AE_REGIONS, mAERegions);
        builder.set(CaptureRequest.CONTROL_AF_MODE, mCurrentFocusMode);
        
        //AF Trigger value为CONTROL_AF_TRIGGER_IDLE
        builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
    }


   private void sendAutoFocusCancelCaptureRequest() {
        CaptureRequest.Builder builder = mDevice2Requester.createAndConfigRequest(
                Camera2Proxy.TEMPLATE_PREVIEW);
        if (builder == null) {
            LogHelper.w(TAG, "[sendAutoFocusTriggerCaptureRequest] builder is null");
            return;
        }
        //此时的AF_TRIGGER为CONTROL_AF_TRIGGER_CANCEL
        builder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                CaptureRequest.CONTROL_AF_TRIGGER_CANCEL);

        Camera2CaptureSessionProxy sessionProxy = mDevice2Requester.getCurrentCaptureSession();
        if (sessionProxy == null) {
            LogHelper.w(TAG, "[sendAutoFocusCancelCaptureRequest] sessionProxy is null");
            return;
        }
        try {
            if (SLOW_MOTION.equals(mFocus.getCurrentMode()) && mFocus.isHighSpeedRequest()) {
                List<CaptureRequest> captureRequests = null;
                captureRequests = sessionProxy.createHighSpeedRequestList(builder.build());
                sessionProxy.captureBurst(captureRequests, mPreviewCallback, mModeHandler);
            } else {
                sessionProxy.capture(builder.build(), mPreviewCallback, mModeHandler);
            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        sendSettingChangeRequest();
    }

2.长按屏幕触发Auto-Focus Mode

        应用层下发拍照request进而移动lens,聚焦指定区域再改变Focus State的流程是一样的,唯一不同的地方在于当上来的预览帧的Focus State状态变为ACTIVE_FOCUSED时候,长按屏幕触发的AF会具有锁定功能,锁定AE/AF的相关值不再改变。

        接收到Focus State状态改变之后的处理方式上一篇有讲。

@Override
    public boolean onLongPress(float x, float y) {
        boolean isNeeedCancelAutoFocus = needCancelAutoFocus();
        mModeHandler.post(new Runnable() {
            @Override
            public void run() {
                mNeedDoAfLock = false;
                if (mFocusViewController == null) {
                    return;
                }

                //通过mIsAutoFocusTriggered 这个TAG来控制AE/AF的锁定
                mIsAutoFocusTriggered = true;
                // do not do AE/AF lock in panorama mode and pip mode.
                if (mCurrentMode.equals("com.mediatek.camera.feature.mode.panorama.PanoramaMode")) {
                    return;
                }
                if (mCurrentMode.contains("com.mediatek.camera.feature.mode.pip")) {
                    return;
                }
                mLockPoint.set((int) x, (int) y);
                if (isNeeedCancelAutoFocus) {
                    mFocusListener.cancelAutoFocus();
                }
                triggerAfLock();
            }
        });
        return false;
    }


    private void triggerAfLock() {
        //其他的下发TAG的更新跟单击屏幕触发是一样的
        mFocusListener.updateFocusArea(mFocusArea, mMeteringArea);

        mFocusListener.updateFocusMode("auto");

        mFocusListener.autoFocus();
        mLockState = LockState.STATE_LOCKING;
        
        //这个flag用于在接收到Focus State状态改变为ACTIVE_FOCUSED之后判断是否需要锁定
        mNeedDoAfLock = true;
    }

小结:

        Auto-Focus应用层的控制、管理及下发已经get了;置于HAL接收到capture request咋么去驱使driver使相机Lens聚焦到指定区域,然后Lens锁定,改变相关状态为ACTIVE_FOCUSED这些内容以后的以后可以再去专门check。

       结合Flash、AE、AF、ContinusShot这些模块关系是错综复杂的,一个模块的改变势必会对其他模块进行一些改变,这些在文章中有简单的提了一下,其实这些内容以后也可以整理一下,更清晰条理的把这些模块的互斥呈现出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值