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这些模块关系是错综复杂的,一个模块的改变势必会对其他模块进行一些改变,这些在文章中有简单的提了一下,其实这些内容以后也可以整理一下,更清晰条理的把这些模块的互斥呈现出来。