blob: b543a769ac10e2c9891085359fb4a568bf38240c [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 "IntelAEStateMachine"
#include "IntelAEStateMachine.h"
#include "Errors.h"
#include "HALv3Utils.h"
#include "Utils.h"
namespace camera3 {
IntelAEStateMachine::IntelAEStateMachine(int cameraId)
: mCameraId(cameraId),
mLastControlMode(0),
mLastSceneMode(0),
mCurrentAeMode(NULL) {
LOG1("%s mCameraId %d", __func__, mCameraId);
mCurrentAeMode = &mAutoMode;
CLEAR(mLastAeControls);
mLastAeControls.aeMode = ANDROID_CONTROL_AE_MODE_ON;
}
IntelAEStateMachine::~IntelAEStateMachine() {
LOG1("%s mCameraId %d", __func__, mCameraId);
}
/**
* Process states in input stage before the AE is run.
* It is initializing the current state if input
* parameters have an influence.
*
* \param[IN] controlMode: control.controlMode
* \param[IN] sceneMode: control.sceneMode
* \param[IN] aeControls: set of control.<ae>
*/
int IntelAEStateMachine::processState(uint8_t controlMode, uint8_t sceneMode,
const AeControls& aeControls) {
if (controlMode == ANDROID_CONTROL_MODE_OFF) {
LOG2("%s: Set AE offMode: controlMode = %d, aeMode = %d", __func__, controlMode,
aeControls.aeMode);
mCurrentAeMode = &mOffMode;
} else {
if (aeControls.aeMode == ANDROID_CONTROL_AE_MODE_OFF) {
mCurrentAeMode = &mOffMode;
LOG2("%s: Set AE offMode: controlMode = %d, aeMode = %d", __func__, controlMode,
aeControls.aeMode);
} else {
LOG2("%s: Set AE AutoMode: controlMode = %d, aeMode = %d", __func__, controlMode,
aeControls.aeMode);
mCurrentAeMode = &mAutoMode;
}
}
mLastAeControls = aeControls;
mLastSceneMode = sceneMode;
mLastControlMode = controlMode;
return mCurrentAeMode->processState(controlMode, sceneMode, aeControls);
}
/**
* Process results and define output state after the AE is run
*
* \param[IN] aeConverged: from the ae result
* \param[IN] results: cameraMetadata to write dynamic tags.
*/
int IntelAEStateMachine::processResult(bool aeConverged, android::CameraMetadata* result) {
CheckError(!mCurrentAeMode, icamera::UNKNOWN_ERROR, "Invalid AE mode");
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
return mCurrentAeMode->processResult(aeConverged, result);
}
/******************************************************************************
* AE MODE - BASE
******************************************************************************/
IntelAEModeBase::IntelAEModeBase()
: mLastControlMode(0),
mLastSceneMode(0),
mEvChanged(false),
mLastAeConvergedFlag(false),
mAeRunCount(0),
mAeConvergedCount(0),
mCurrentAeState(ANDROID_CONTROL_AE_STATE_INACTIVE) {
LOG1("%s", __func__);
CLEAR(mLastAeControls);
}
void IntelAEModeBase::updateResult(android::CameraMetadata* results) {
CheckError(!results, VOID_VALUE, "%s, result is nullptr", __func__);
LOG2("%s: current AE state is: %d", __func__, mCurrentAeState);
//# METADATA_Dynamic control.aeMode done
results->update(ANDROID_CONTROL_AE_MODE, &mLastAeControls.aeMode, 1);
//# METADATA_Dynamic control.aeLock done
results->update(ANDROID_CONTROL_AE_LOCK, &mLastAeControls.aeLock, 1);
//# METADATA_Dynamic control.aePrecaptureTrigger done
results->update(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &mLastAeControls.aePreCaptureTrigger, 1);
//# METADATA_Dynamic control.aeState done
results->update(ANDROID_CONTROL_AE_STATE, &mCurrentAeState, 1);
}
void IntelAEModeBase::resetState() {
LOG2("%s", __func__);
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
mLastAeConvergedFlag = false;
mAeRunCount = 0;
mAeConvergedCount = 0;
}
/******************************************************************************
* AE MODE - OFF
******************************************************************************/
IntelAEModeOff::IntelAEModeOff() : IntelAEModeBase() {
LOG1("%s", __func__);
}
int IntelAEModeOff::processState(uint8_t controlMode, uint8_t sceneMode,
const AeControls& aeControls) {
LOG2("%s", __func__);
mLastAeControls = aeControls;
mLastSceneMode = sceneMode;
mLastControlMode = controlMode;
if (controlMode == ANDROID_CONTROL_MODE_OFF ||
aeControls.aeMode == ANDROID_CONTROL_AE_MODE_OFF) {
resetState();
} else {
LOGE("AE State machine should not be OFF! - Fix bug");
return icamera::UNKNOWN_ERROR;
}
return icamera::OK;
}
int IntelAEModeOff::processResult(bool aeConverged, android::CameraMetadata* result) {
UNUSED(aeConverged);
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
LOG2("%s", __func__);
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
updateResult(result);
return icamera::OK;
}
/******************************************************************************
* AE MODE - AUTO
******************************************************************************/
IntelAEModeAuto::IntelAEModeAuto() : IntelAEModeBase() {
LOG1("%s", __func__);
}
int IntelAEModeAuto::processState(uint8_t controlMode, uint8_t sceneMode,
const AeControls& aeControls) {
if (controlMode != mLastControlMode) {
LOG1("%s: control mode has changed %d -> %d, reset AE State", __func__, controlMode,
mLastControlMode);
resetState();
}
if (aeControls.aeLock == ANDROID_CONTROL_AE_LOCK_ON) {
// If ev compensation changes, we have to let the AE run until
// convergence. Thus we need to figure out changes in compensation and
// only change the state immediately to locked,
// IF the EV did not change.
mEvChanged = (mLastAeControls.evCompensation != aeControls.evCompensation) ? true : false;
if (!mEvChanged) mCurrentAeState = ANDROID_CONTROL_AE_STATE_LOCKED;
} else if (aeControls.aeMode != mLastAeControls.aeMode ||
(controlMode == ANDROID_CONTROL_MODE_USE_SCENE_MODE &&
sceneMode != mLastSceneMode)) {
resetState();
} else {
switch (mCurrentAeState) {
case ANDROID_CONTROL_AE_STATE_LOCKED:
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
break;
case ANDROID_CONTROL_AE_STATE_SEARCHING:
case ANDROID_CONTROL_AE_STATE_INACTIVE:
case ANDROID_CONTROL_AE_STATE_CONVERGED:
case ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED:
case ANDROID_CONTROL_AE_STATE_PRECAPTURE:
if (aeControls.aePreCaptureTrigger == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_START)
mCurrentAeState = ANDROID_CONTROL_AE_STATE_PRECAPTURE;
if (aeControls.aePreCaptureTrigger == ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL)
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
break;
default:
LOGE("Invalid AE state!, State set to INACTIVE");
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
break;
}
}
mLastAeControls = aeControls;
mLastSceneMode = sceneMode;
mLastControlMode = controlMode;
return icamera::OK;
}
int IntelAEModeAuto::processResult(bool aeConverged, android::CameraMetadata* result) {
CheckError(!result, icamera::UNKNOWN_ERROR, "%s, result is nullptr", __func__);
switch (mCurrentAeState) {
case ANDROID_CONTROL_AE_STATE_LOCKED:
// do nothing
break;
case ANDROID_CONTROL_AE_STATE_INACTIVE:
case ANDROID_CONTROL_AE_STATE_SEARCHING:
case ANDROID_CONTROL_AE_STATE_CONVERGED:
case ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED:
if (aeConverged) {
mEvChanged = false; // converged -> reset
if (mLastAeControls.aeLock) {
mCurrentAeState = ANDROID_CONTROL_AE_STATE_LOCKED;
} else {
mCurrentAeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
}
} else {
mCurrentAeState = ANDROID_CONTROL_AE_STATE_SEARCHING;
}
break;
case ANDROID_CONTROL_AE_STATE_PRECAPTURE:
if (aeConverged) {
mEvChanged = false; // converged -> reset
if (mLastAeControls.aeLock) {
mCurrentAeState = ANDROID_CONTROL_AE_STATE_LOCKED;
} else {
mCurrentAeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
}
} // here the else is staying at the same state.
break;
default:
LOGE("Invalid AE state!, State set to INACTIVE");
mCurrentAeState = ANDROID_CONTROL_AE_STATE_INACTIVE;
break;
}
if (aeConverged) {
if (mLastAeConvergedFlag == true) {
mAeConvergedCount++;
LOG2("%s: AE converged for %d frames", __func__, mAeConvergedCount);
} else {
mAeConvergedCount = 1;
LOG1("%s: AE converging -> converged, after running AE for %d times", __func__,
mAeRunCount);
}
} else {
if (mLastAeConvergedFlag == true) {
LOG1("%s: AE Converged -> converging", __func__);
mAeRunCount = 1;
mAeConvergedCount = 0;
} else {
mAeRunCount++;
LOG2("%s: AE converging for %d frames", __func__, mAeRunCount);
}
}
mLastAeConvergedFlag = aeConverged;
updateResult(result);
return icamera::OK;
}
} // namespace camera3