[libcamera-devel] [PATCH v2 6/7] android: Plumb all AE-related controls
Paul Elder
paul.elder at ideasonboard.com
Fri Oct 1 12:33:24 CEST 2021
With the AE-related controls reorganized in libcamera, with separate
value and lever controls for exposure and gain, plumb these through the
HAL layer (in order of appearence in the patch):
- static metadata: available AE modes, AE lock available
- manual template: add AE off (the other templates already have AE on)
- request metadata: HAL -> libcamera controls conversion
- result metadata: libcamera -> HAL controls conversion
- result metadata: AE state
We add class variables to CameraDevice to save the last set android AE
controls, as that is how android controls function (no need to resubmit
controls if they are unchanged).
We also save libcamera's AE state in the request descriptor, as
otherwise there is insufficient information from libcamera's result
metadata alone to tell if the state is locked or manual (as they are an
internal state in libcamera).
Bug: https://bugs.libcamera.org/show_bug.cgi?id=42
Bug: https://bugs.libcamera.org/show_bug.cgi?id=43
Bug: https://bugs.libcamera.org/show_bug.cgi?id=47
Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
---
New in v2
---
src/android/camera_capabilities.cpp | 63 ++++++++++++++++---
src/android/camera_device.cpp | 98 +++++++++++++++++++++++++++--
src/android/camera_device.h | 16 +++++
3 files changed, 165 insertions(+), 12 deletions(-)
diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index f7a6cda9..3fed3f83 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -830,12 +830,62 @@ int CameraCapabilities::initializeStaticMetadata()
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
aeAvailableAntiBandingModes);
- std::vector<uint8_t> aeAvailableModes = {
- ANDROID_CONTROL_AE_MODE_ON,
- };
+ std::vector<uint8_t> aeAvailableModes;
+ /* This will cause problems if one supports only on and the other only off */
+ bool aeAddedOn = false;
+ bool aeAddedOff = false;
+
+ const auto &analogGainModeInfo = controlsInfo.find(&controls::AnalogueGainMode);
+ if (analogGainModeInfo != controlsInfo.end()) {
+ for (const auto &value : analogGainModeInfo->second.values()) {
+ switch (value.get<int32_t>()) {
+ case controls::AnalogueGainModeAuto:
+ if (!aeAddedOn)
+ aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON);
+ aeAddedOn = true;
+ break;
+ case controls::AnalogueGainModeDisabled:
+ if (!aeAddedOff)
+ aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_OFF);
+ aeAddedOff = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ const auto &exposureTimeModeInfo = controlsInfo.find(&controls::ExposureTimeMode);
+ if (exposureTimeModeInfo != controlsInfo.end()) {
+ for (const auto &value : exposureTimeModeInfo->second.values()) {
+ switch (value.get<int32_t>()) {
+ case controls::ExposureTimeModeAuto:
+ if (!aeAddedOn)
+ aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON);
+ aeAddedOn = true;
+ break;
+ case controls::ExposureTimeModeDisabled:
+ if (!aeAddedOff)
+ aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_OFF);
+ aeAddedOff = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (aeAvailableModes.empty())
+ aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON);
staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,
aeAvailableModes);
+ /* In libcamera, turning off AE is equivalient to locking. */
+ uint8_t aeLockAvailable = aeAddedOff ? ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE
+ : ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
+ staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
+ aeLockAvailable);
+
int64_t minFrameDurationNsec = -1;
int64_t maxFrameDurationNsec = -1;
const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);
@@ -946,10 +996,6 @@ int CameraCapabilities::initializeStaticMetadata()
staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
sceneModesOverride);
- uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;
- staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
- aeLockAvailable);
-
uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;
staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
awbLockAvailable);
@@ -1358,6 +1404,9 @@ std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateManual() cons
if (!manualTemplate)
return nullptr;
+ uint8_t aeMode = ANDROID_CONTROL_AE_MODE_OFF;
+ manualTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
+
return manualTemplate;
}
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index ef4fbab8..d5027ec5 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -263,7 +263,9 @@ CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor(
CameraDevice::CameraDevice(unsigned int id, std::shared_ptr<Camera> camera)
: id_(id), state_(State::Stopped), camera_(std::move(camera)),
- facing_(CAMERA_FACING_FRONT), orientation_(0)
+ facing_(CAMERA_FACING_FRONT), orientation_(0),
+ aeOn_(true), aeLocked_(false), lastExposureTime_(0),
+ lastAnalogueGain_(1.0f), lastDigitalGain_(1.0f)
{
camera_->requestCompleted.connect(this, &CameraDevice::requestComplete);
@@ -857,6 +859,62 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
controls.set(controls::draft::TestPatternMode, testPatternMode);
}
+ /*
+ * \todo Can we trust that we won't receive values that we didn't
+ * report supporting?
+ */
+ if (settings.getEntry(ANDROID_CONTROL_AE_LOCK, &entry))
+ aeLocked_ = *entry.data.u8 != ANDROID_CONTROL_AE_LOCK_OFF;
+
+ if (settings.getEntry(ANDROID_CONTROL_AE_MODE, &entry))
+ aeOn_ = *entry.data.u8 != ANDROID_CONTROL_AE_MODE_OFF;
+
+ AeMode aeMode;
+ if (aeLocked_ && aeOn_)
+ aeMode = AeMode::Lock;
+ else if (aeLocked_ && !aeOn_)
+ aeMode = AeMode::Manual;
+ else if (!aeLocked_ && aeOn_)
+ aeMode = AeMode::Auto;
+ else /* !aeLocked_ && !aeOn_ */
+ aeMode = AeMode::Manual;
+
+ /* Save this so that we can recover it in the result */
+ descriptor->aeMode_ = aeMode;
+
+ const auto &eInfo = camera_->controls().find(&controls::ExposureTimeMode);
+ if (eInfo != camera_->controls().end()) {
+ controls.set(controls::ExposureTimeMode,
+ aeMode == AeMode::Auto ?
+ controls::ExposureTimeModeAuto :
+ controls::ExposureTimeModeDisabled);
+ }
+
+ const auto &gInfo = camera_->controls().find(&controls::AnalogueGainMode);
+ if (gInfo != camera_->controls().end()) {
+ controls.set(controls::AnalogueGainMode,
+ aeMode == AeMode::Auto ?
+ controls::AnalogueGainModeAuto :
+ controls::AnalogueGainModeDisabled);
+ }
+
+ if (settings.getEntry(ANDROID_SENSOR_EXPOSURE_TIME, &entry)) {
+ const auto &info = camera_->controls().find(&controls::ExposureTime);
+ if (info != camera_->controls().end()) {
+ lastExposureTime_ = (*entry.data.i64) / 1000;
+ /* Don't disable libcamera's internal AeMode::Lock */
+ if (aeMode != AeMode::Lock)
+ controls.set(controls::ExposureTime, lastExposureTime_);
+ }
+ }
+
+ /* Trigger libcamera's locked -> manual state change */
+ if (aeMode == AeMode::Manual && !settings.hasEntry(ANDROID_SENSOR_EXPOSURE_TIME)) {
+ const auto &info = camera_->controls().find(&controls::ExposureTime);
+ if (info != camera_->controls().end())
+ controls.set(controls::ExposureTime, lastExposureTime_);
+ }
+
return 0;
}
@@ -1345,11 +1403,16 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
resultMetadata->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
value32);
- value = ANDROID_CONTROL_AE_LOCK_OFF;
- resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, value);
+ uint8_t aeLock = (descriptor.aeMode_ == AeMode::Lock)
+ ? ANDROID_CONTROL_AE_LOCK_ON
+ : ANDROID_CONTROL_AE_LOCK_OFF;
+ resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);
- value = ANDROID_CONTROL_AE_MODE_ON;
- resultMetadata->addEntry(ANDROID_CONTROL_AE_MODE, value);
+ /* Locked means auto + locked in android */
+ uint8_t aeMode = (descriptor.aeMode_ != AeMode::Manual)
+ ? ANDROID_CONTROL_AE_MODE_ON
+ : ANDROID_CONTROL_AE_MODE_OFF;
+ resultMetadata->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);
if (settings.getEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry))
/*
@@ -1366,6 +1429,31 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
resultMetadata->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, value);
value = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ if (metadata.contains(controls::AeState)) {
+ switch (metadata.get(controls::AeState)) {
+ case controls::AeStateInactive:
+ value = ANDROID_CONTROL_AE_STATE_INACTIVE;
+ break;
+ case controls::AeStateSearching:
+ value = ANDROID_CONTROL_AE_STATE_SEARCHING;
+ break;
+ case controls::AeStateConverged:
+ value = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ break;
+ case controls::AeStateFlashRequired:
+ value = ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED;
+ break;
+ case controls::AeStatePrecapture:
+ value = ANDROID_CONTROL_AE_STATE_PRECAPTURE;
+ break;
+ default:
+ if (descriptor.aeMode_ == AeMode::Lock) {
+ value = ANDROID_CONTROL_AE_STATE_LOCKED;
+ break;
+ }
+ LOG(HAL, Error) << "Invalid AeState, setting converged";
+ }
+ }
resultMetadata->addEntry(ANDROID_CONTROL_AE_STATE, value);
value = ANDROID_CONTROL_AF_MODE_OFF;
diff --git a/src/android/camera_device.h b/src/android/camera_device.h
index b7d774fe..f693cdbc 100644
--- a/src/android/camera_device.h
+++ b/src/android/camera_device.h
@@ -73,6 +73,12 @@ private:
CameraDevice(unsigned int id, std::shared_ptr<libcamera::Camera> camera);
+ enum class AeMode {
+ Auto,
+ Lock,
+ Manual,
+ };
+
struct Camera3RequestDescriptor {
enum class Status {
Pending,
@@ -96,6 +102,9 @@ private:
camera3_capture_result_t captureResult_ = {};
Status status_ = Status::Pending;
+
+ /* The libcamera internal AE state for this request */
+ AeMode aeMode_ = AeMode::Auto;
};
enum class State {
@@ -146,6 +155,13 @@ private:
int facing_;
int orientation_;
+ /* Track the last-set android AE controls */
+ bool aeOn_;
+ bool aeLocked_;
+ int32_t lastExposureTime_;
+ float lastAnalogueGain_;
+ float lastDigitalGain_;
+
CameraMetadata lastSettings_;
};
--
2.27.0
More information about the libcamera-devel
mailing list