blob: c409afeb33784ca413fa7fc3c8861f6e4fd07850 [file] [log] [blame]
/*
* Copyright (C) 2015-2020 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "IntelAFStateMachine"
#include "IntelAFStateMachine.h"
#include "Errors.h"
#include "HALv3Utils.h"
#include "Utils.h"
namespace camera3 {
/**
* AF timeouts. Together these will make:
* timeout if: [MIN_AF_TIMEOUT - MAX_AF_FRAME_COUNT_TIMEOUT - MAX_AF_TIMEOUT]
* which translates to 2-4 seconds with the current values. Actual timeout value
* will depend on the FPS. E.g. >30FPS = 2s, 20FPS = 3s, <15FPS = 4s.
*/
/**
* MAX_AF_TIMEOUT
* Maximum time we allow the AF to iterate without a result.
* This timeout is the last resort, for very low FPS operation.
* Units are in microseconds.
* 4 seconds is a compromise between CTS & ITS. ITS allows for 10 seconds for
* 3A convergence. CTS1 allows only 5, but it doesn't require convergence, just
* a conclusion. We reserve one second for latencies to be safe. This makes the
* timeout 5 (cts1) - 1 (latency safety) = 4 seconds = 4000000us.
*/
static const long int MAX_AF_TIMEOUT = 4000000; // 4 seconds
/**
* MIN_AF_TIMEOUT
* For very high FPS use cases, we want to anyway allow some time for moving the
* lens.
*/
static const long int MIN_AF_TIMEOUT = 2000000; // 2 seconds
/**
* MAX_AF_FRAME_COUNT_TIMEOUT
* Maximum time we allow the AF to iterate without a result.
* Based on frames, as the AF algorithm itself needs frames for its operation,
* not just time, and the FPS varies.
* This is the timeout for normal operation, and translates to 2 seconds
* if FPS is 30.
*/
static const int MAX_AF_FRAME_COUNT_TIMEOUT = 60; // 2 seconds if 30fps
IntelAFStateMachine::IntelAFStateMachine(int cameraId) : mCameraId(cameraId) {
LOG1("%s mCameraId %d", __func__, mCameraId);
mCurrentAfMode = &mAutoMode;
mLastAfControls = {ANDROID_CONTROL_AF_MODE_AUTO, ANDROID_CONTROL_AF_TRIGGER_IDLE};
}
IntelAFStateMachine::~IntelAFStateMachine() {
LOG1("%s mCameraId %d", __func__, mCameraId);
}
int IntelAFStateMachine::processTriggers(uint8_t afTrigger, uint8_t afMode) {
if (afMode != mLastAfControls.afMode) {
LOG1("Change of AF mode from %d to %d", mLastAfControls.afMode, afMode);
switch (afMode) {
case ANDROID_CONTROL_AF_MODE_AUTO:
case ANDROID_CONTROL_AF_MODE_MACRO:
mCurrentAfMode = &mAutoMode;
break;
case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
mCurrentAfMode = &mContinuousPictureMode;
break;
case ANDROID_CONTROL_AF_MODE_OFF:
mCurrentAfMode = &mOffMode;
break;
default:
LOGE("INVALID AF mode requested defaulting to AUTO");
mCurrentAfMode = &mAutoMode;
break;
}
mCurrentAfMode->resetState();
}
mLastAfControls.afTrigger = afTrigger;
mLastAfControls.afMode = afMode;
LOG2("%s: afMode %d", __func__, mLastAfControls.afMode);
return mCurrentAfMode->processTriggers(afTrigger, afMode);
}
int IntelAFStateMachine::processResult(int afState, bool lensMoving,
android::CameraMetadata* result) {
CheckError(!mCurrentAfMode, icamera::UNKNOWN_ERROR, "Invalid AF mode");
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
return mCurrentAfMode->processResult(afState, lensMoving, result);
}
/**
* updateDefaults
*
* Used in case of error in the algorithm or fixed focus sensor
* In case of fixed focus sensor we always report locked
*/
int IntelAFStateMachine::updateDefaults(android::CameraMetadata* result, bool fixedFocus) const {
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
mCurrentAfMode->updateResult(result);
uint8_t defaultState = ANDROID_CONTROL_AF_STATE_INACTIVE;
if (fixedFocus) defaultState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
result->update(ANDROID_CONTROL_AF_STATE, &defaultState, 1);
return icamera::OK;
}
/******************************************************************************
* AF MODE - BASE
******************************************************************************/
IntelAfModeBase::IntelAfModeBase()
: mCurrentAfState(ANDROID_CONTROL_AF_STATE_INACTIVE),
mLensState(ANDROID_LENS_STATE_STATIONARY),
mLastActiveTriggerTime(0),
mFramesSinceTrigger(0) {
LOG1("%s", __func__);
mLastAfControls = {ANDROID_CONTROL_AF_MODE_AUTO, ANDROID_CONTROL_AF_TRIGGER_IDLE};
}
/**
* processTriggers
*
* This method is called BEFORE auto focus algorithm has RUN
* Input parameters are pre-filled by the Intel3APlus::fillAfInputParams()
* by parsing the request settings.
* Other parameters from the capture request settings not filled in the input
* params structure is passed as argument
*/
int IntelAfModeBase::processTriggers(uint8_t afTrigger, uint8_t afMode) {
LOG2("%s", __func__);
if (afTrigger == ANDROID_CONTROL_AF_TRIGGER_START) {
resetTrigger(icamera::CameraUtils::systemTime() / 1000);
LOG1("AF TRIGGER START");
} else if (afTrigger == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
LOG1("AF TRIGGER CANCEL");
resetTrigger(0);
}
mLastAfControls.afTrigger = afTrigger;
mLastAfControls.afMode = afMode;
return icamera::OK;
}
void IntelAfModeBase::updateResult(android::CameraMetadata* results) {
CheckError(!results, VOID_VALUE, "%s, result is nullptr", __func__);
LOG2("%s", __func__);
LOG2("%s afMode = %d state = %d", __func__, mLastAfControls.afMode, mCurrentAfState);
results->update(ANDROID_CONTROL_AF_MODE, &mLastAfControls.afMode, 1);
//# METADATA_Dynamic control.afTrigger done
results->update(ANDROID_CONTROL_AF_TRIGGER, &mLastAfControls.afTrigger, 1);
//# METADATA_Dynamic control.afState done
results->update(ANDROID_CONTROL_AF_STATE, &mCurrentAfState, 1);
/**
* LENS STATE update
*/
//# METADATA_Dynamic lens.state Done
results->update(ANDROID_LENS_STATE, &mLensState, 1);
}
void IntelAfModeBase::resetTrigger(usecs_t triggerTime) {
mLastActiveTriggerTime = triggerTime;
mFramesSinceTrigger = 0;
}
void IntelAfModeBase::resetState() {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
}
void IntelAfModeBase::checkIfFocusTimeout() {
// give up if AF was iterating for too long
if (mLastActiveTriggerTime != 0) {
mFramesSinceTrigger++;
usecs_t now = icamera::CameraUtils::systemTime() / 1000;
usecs_t timeSinceTriggered = now - mLastActiveTriggerTime;
if (mCurrentAfState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED) {
/**
* Timeout IF either time has passed beyond MAX_AF_TIMEOUT
* OR
* Enough frames have been processed and time has passed beyond
* MIN_AF_TIMEOUT
*/
if (timeSinceTriggered > MAX_AF_TIMEOUT ||
(mFramesSinceTrigger > MAX_AF_FRAME_COUNT_TIMEOUT &&
timeSinceTriggered > MIN_AF_TIMEOUT)) {
resetTrigger(0);
mCurrentAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
}
}
}
}
/******************************************************************************
* AF MODE - OFF
******************************************************************************/
IntelAFModeOff::IntelAFModeOff() : IntelAfModeBase() {
LOG1("%s", __func__);
}
int IntelAFModeOff::processTriggers(uint8_t afTrigger, uint8_t afMode) {
LOG2("%s", __func__);
mLastAfControls.afTrigger = afTrigger;
mLastAfControls.afMode = afMode;
return icamera::OK;
}
int IntelAFModeOff::processResult(int afState, bool lensMoving, android::CameraMetadata* result) {
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
/**
* IN MANUAL and EDOF AF state never changes
*/
LOG2("%s", __func__);
mCurrentAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
mLensState = lensMoving ? ANDROID_LENS_STATE_MOVING : ANDROID_LENS_STATE_STATIONARY;
updateResult(result);
return icamera::OK;
}
/******************************************************************************
* AF MODE - AUTO
******************************************************************************/
IntelAFModeAuto::IntelAFModeAuto() : IntelAfModeBase() {
LOG1("%s", __func__);
}
int IntelAFModeAuto::processTriggers(uint8_t afTrigger, uint8_t afMode) {
LOG2("%s", __func__);
IntelAfModeBase::processTriggers(afTrigger, afMode);
// Override AF state if we just got an AF TRIGGER Start
// This is only valid for the AUTO/MACRO state machine
if (mLastAfControls.afTrigger == ANDROID_CONTROL_AF_TRIGGER_START) {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN;
LOG2("@%s AF state ACTIVE_SCAN (trigger start)", __PRETTY_FUNCTION__);
} else if (mLastAfControls.afTrigger == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_INACTIVE;
LOG2("@%s AF state INACTIVE (trigger cancel)", __PRETTY_FUNCTION__);
}
return icamera::OK;
}
int IntelAFModeAuto::processResult(int afState, bool lensMoving, android::CameraMetadata* result) {
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
LOG2("%s", __func__);
mLensState = lensMoving ? ANDROID_LENS_STATE_MOVING : ANDROID_LENS_STATE_STATIONARY;
if (mLastActiveTriggerTime != 0) {
switch (afState) {
case icamera::AF_STATE_LOCAL_SEARCH:
case icamera::AF_STATE_EXTENDED_SEARCH:
LOG2("@%s AF state SCANNING", __PRETTY_FUNCTION__);
break;
case icamera::AF_STATE_SUCCESS:
mCurrentAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
resetTrigger(0);
LOG2("@%s AF state FOCUSED_LOCKED", __PRETTY_FUNCTION__);
break;
case icamera::AF_STATE_FAIL:
mCurrentAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
resetTrigger(0);
LOG2("@%s AF state NOT_FOCUSED_LOCKED", __PRETTY_FUNCTION__);
break;
default:
case icamera::AF_STATE_IDLE:
LOG2("@%s AF state INACTIVE", __PRETTY_FUNCTION__);
break;
}
}
checkIfFocusTimeout();
updateResult(result);
return icamera::OK;
}
/******************************************************************************
* AF MODE - CONTINUOUS PICTURE
******************************************************************************/
IntelAFModeContinuousPicture::IntelAFModeContinuousPicture() : IntelAfModeBase() {
LOG1("%s", __func__);
}
int IntelAFModeContinuousPicture::processTriggers(uint8_t afTrigger, uint8_t afMode) {
LOG2("%s", __func__);
IntelAfModeBase::processTriggers(afTrigger, afMode);
// Override AF state if we just got an AF TRIGGER CANCEL
if (mLastAfControls.afTrigger == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
/* Scan is supposed to be restarted, which we try by triggering a new
* scan. (see IntelAFStateMachine::processTriggers)
* This however, doesn't do anything at all, because AIQ does not
* want to play ball, at least yet.
*
* We can skip state transitions when allowed by the state
* machine documentation, so skip INACTIVE, also skip PASSIVE_SCAN if
* possible and go directly to either PASSIVE_FOCUSED or UNFOCUSED
*
* TODO: Remove this switch-statement, once triggering a scan starts to
* work. We could go directly to PASSIVE_SCAN always then, because a
* scan is really happening. Now it is not.
*/
switch (mCurrentAfState) {
case ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN:
case ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED;
break;
case ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED:
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
break;
default:
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
break;
}
}
/* Override AF state if we just got an AF TRIGGER START, this will stop
* the scan as intended in the state machine documentation (see
* IntelAFStateMachine::processTriggers)
*/
if (mLastAfControls.afTrigger == ANDROID_CONTROL_AF_TRIGGER_START) {
if (mCurrentAfState == ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)
mCurrentAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
else if (mCurrentAfState == ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED ||
mCurrentAfState == ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN)
mCurrentAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
}
return icamera::OK;
}
int IntelAFModeContinuousPicture::processResult(int afState, bool lensMoving,
android::CameraMetadata* result) {
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
LOG2("%s", __func__);
mLensState = lensMoving ? ANDROID_LENS_STATE_MOVING : ANDROID_LENS_STATE_STATIONARY;
// state transition from locked state are only allowed via triggers, which
// are handled in the currentAFMode processTriggers() and below in this
// function.
if (mCurrentAfState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
mCurrentAfState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
switch (afState) {
case icamera::AF_STATE_LOCAL_SEARCH:
case icamera::AF_STATE_EXTENDED_SEARCH:
LOG2("@%s AF state SCANNING", __PRETTY_FUNCTION__);
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN;
break;
case icamera::AF_STATE_SUCCESS:
if (mLastActiveTriggerTime == 0) {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED;
LOG2("@%s AF state PASSIVE_FOCUSED", __PRETTY_FUNCTION__);
} else {
resetTrigger(0);
mCurrentAfState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
LOG2("@%s AF state FOCUSED_LOCKED", __PRETTY_FUNCTION__);
}
break;
case icamera::AF_STATE_FAIL:
if (mLastActiveTriggerTime == 0) {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED;
LOG2("@%s AF state PASSIVE_UNFOCUSED", __PRETTY_FUNCTION__);
} else {
resetTrigger(0);
mCurrentAfState = ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED;
LOG2("@%s AF state NOT_FOCUSED_LOCKED", __PRETTY_FUNCTION__);
}
break;
default:
case icamera::AF_STATE_IDLE:
if (mCurrentAfState == ANDROID_CONTROL_AF_STATE_INACTIVE) {
mCurrentAfState = ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED;
LOG2("@%s AF state PASSIVE_UNFOCUSED (idle)", __PRETTY_FUNCTION__);
}
break;
}
}
checkIfFocusTimeout();
updateResult(result);
return icamera::OK;
}
} // namespace camera3