ipa: raspberry: Port to the new AEGC controls
The newly introduced controls to drive the AEGC algorithm allow to control the computation of the exposure time and analogue gain separately. The RPi AEGC implementation already computes the shutter and gain values separately but does not expose separate functions to control them. Augment the AgcAlgorithm interface to allow pausing/resuming the shutter and gain automatic computations separately and plumb them to the newly introduced controls. Add safety checks to ignore ExposureTime and AnalogueGain values if the algorithms are not paused, and report the correct AeState value by checking if both algorithms have been paused or if they have converged. Signed-off-by: Jacopo Mondi <jacopo@jmondi.org> Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Acked-by: David Plowman <david.plowman@raspberrypi.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
parent
72b2c9dddf
commit
c45a2682c3
6 changed files with 167 additions and 35 deletions
|
@ -55,8 +55,15 @@ constexpr Duration controllerMinFrameDuration = 1.0s / 30.0;
|
||||||
|
|
||||||
/* List of controls handled by the Raspberry Pi IPA */
|
/* List of controls handled by the Raspberry Pi IPA */
|
||||||
const ControlInfoMap::Map ipaControls{
|
const ControlInfoMap::Map ipaControls{
|
||||||
{ &controls::AeEnable, ControlInfo(false, true) },
|
{ &controls::ExposureTimeMode,
|
||||||
|
ControlInfo(static_cast<int32_t>(controls::ExposureTimeModeAuto),
|
||||||
|
static_cast<int32_t>(controls::ExposureTimeModeManual),
|
||||||
|
static_cast<int32_t>(controls::ExposureTimeModeAuto)) },
|
||||||
{ &controls::ExposureTime, ControlInfo(0, 66666) },
|
{ &controls::ExposureTime, ControlInfo(0, 66666) },
|
||||||
|
{ &controls::AnalogueGainMode,
|
||||||
|
ControlInfo(static_cast<int32_t>(controls::AnalogueGainModeAuto),
|
||||||
|
static_cast<int32_t>(controls::AnalogueGainModeManual),
|
||||||
|
static_cast<int32_t>(controls::AnalogueGainModeAuto)) },
|
||||||
{ &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },
|
{ &controls::AnalogueGain, ControlInfo(1.0f, 16.0f) },
|
||||||
{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },
|
{ &controls::AeMeteringMode, ControlInfo(controls::AeMeteringModeValues) },
|
||||||
{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },
|
{ &controls::AeConstraintMode, ControlInfo(controls::AeConstraintModeValues) },
|
||||||
|
@ -749,6 +756,42 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
af->setMode(mode->second);
|
af->setMode(mode->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Because some AE controls are mode-specific, handle the AE-related
|
||||||
|
* mode changes first.
|
||||||
|
*/
|
||||||
|
const auto analogueGainMode = controls.get(controls::AnalogueGainMode);
|
||||||
|
const auto exposureTimeMode = controls.get(controls::ExposureTimeMode);
|
||||||
|
|
||||||
|
if (analogueGainMode || exposureTimeMode) {
|
||||||
|
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
||||||
|
controller_.getAlgorithm("agc"));
|
||||||
|
if (agc) {
|
||||||
|
if (analogueGainMode) {
|
||||||
|
if (*analogueGainMode == controls::AnalogueGainModeManual)
|
||||||
|
agc->disableAutoGain();
|
||||||
|
else
|
||||||
|
agc->enableAutoGain();
|
||||||
|
|
||||||
|
libcameraMetadata_.set(controls::AnalogueGainMode,
|
||||||
|
*analogueGainMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exposureTimeMode) {
|
||||||
|
if (*exposureTimeMode == controls::ExposureTimeModeManual)
|
||||||
|
agc->disableAutoExposure();
|
||||||
|
else
|
||||||
|
agc->enableAutoExposure();
|
||||||
|
|
||||||
|
libcameraMetadata_.set(controls::ExposureTimeMode,
|
||||||
|
*exposureTimeMode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(IPARPI, Warning)
|
||||||
|
<< "Could not set AnalogueGainMode or ExposureTimeMode - no AGC algorithm";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Iterate over controls */
|
/* Iterate over controls */
|
||||||
for (auto const &ctrl : controls) {
|
for (auto const &ctrl : controls) {
|
||||||
LOG(IPARPI, Debug) << "Request ctrl: "
|
LOG(IPARPI, Debug) << "Request ctrl: "
|
||||||
|
@ -756,23 +799,8 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
<< " = " << ctrl.second.toString();
|
<< " = " << ctrl.second.toString();
|
||||||
|
|
||||||
switch (ctrl.first) {
|
switch (ctrl.first) {
|
||||||
case controls::AE_ENABLE: {
|
case controls::EXPOSURE_TIME_MODE:
|
||||||
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
break; /* We already handled this one above */
|
||||||
controller_.getAlgorithm("agc"));
|
|
||||||
if (!agc) {
|
|
||||||
LOG(IPARPI, Warning)
|
|
||||||
<< "Could not set AE_ENABLE - no AGC algorithm";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctrl.second.get<bool>() == false)
|
|
||||||
agc->disableAuto();
|
|
||||||
else
|
|
||||||
agc->enableAuto();
|
|
||||||
|
|
||||||
libcameraMetadata_.set(controls::AeEnable, ctrl.second.get<bool>());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case controls::EXPOSURE_TIME: {
|
case controls::EXPOSURE_TIME: {
|
||||||
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
||||||
|
@ -783,6 +811,13 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore manual exposure time when the auto exposure
|
||||||
|
* algorithm is running.
|
||||||
|
*/
|
||||||
|
if (agc->autoExposureEnabled())
|
||||||
|
break;
|
||||||
|
|
||||||
/* The control provides units of microseconds. */
|
/* The control provides units of microseconds. */
|
||||||
agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);
|
agc->setFixedExposureTime(0, ctrl.second.get<int32_t>() * 1.0us);
|
||||||
|
|
||||||
|
@ -790,6 +825,9 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case controls::ANALOGUE_GAIN_MODE:
|
||||||
|
break; /* We already handled this one above */
|
||||||
|
|
||||||
case controls::ANALOGUE_GAIN: {
|
case controls::ANALOGUE_GAIN: {
|
||||||
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
||||||
controller_.getAlgorithm("agc"));
|
controller_.getAlgorithm("agc"));
|
||||||
|
@ -799,6 +837,13 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore manual analogue gain value when the auto gain
|
||||||
|
* algorithm is running.
|
||||||
|
*/
|
||||||
|
if (agc->autoGainEnabled())
|
||||||
|
break;
|
||||||
|
|
||||||
agc->setFixedAnalogueGain(0, ctrl.second.get<float>());
|
agc->setFixedAnalogueGain(0, ctrl.second.get<float>());
|
||||||
|
|
||||||
libcameraMetadata_.set(controls::AnalogueGain,
|
libcameraMetadata_.set(controls::AnalogueGain,
|
||||||
|
@ -855,6 +900,13 @@ void IpaBase::applyControls(const ControlList &controls)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore AE_EXPOSURE_MODE if the shutter or the gain
|
||||||
|
* are in auto mode.
|
||||||
|
*/
|
||||||
|
if (agc->autoExposureEnabled() || agc->autoGainEnabled())
|
||||||
|
break;
|
||||||
|
|
||||||
int32_t idx = ctrl.second.get<int32_t>();
|
int32_t idx = ctrl.second.get<int32_t>();
|
||||||
if (ExposureModeTable.count(idx)) {
|
if (ExposureModeTable.count(idx)) {
|
||||||
agc->setExposureMode(ExposureModeTable.at(idx));
|
agc->setExposureMode(ExposureModeTable.at(idx));
|
||||||
|
@ -1334,9 +1386,19 @@ void IpaBase::reportMetadata(unsigned int ipaContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
AgcPrepareStatus *agcPrepareStatus = rpiMetadata.getLocked<AgcPrepareStatus>("agc.prepare_status");
|
AgcPrepareStatus *agcPrepareStatus = rpiMetadata.getLocked<AgcPrepareStatus>("agc.prepare_status");
|
||||||
if (agcPrepareStatus) {
|
if (agcPrepareStatus)
|
||||||
libcameraMetadata_.set(controls::AeLocked, agcPrepareStatus->locked);
|
|
||||||
libcameraMetadata_.set(controls::DigitalGain, agcPrepareStatus->digitalGain);
|
libcameraMetadata_.set(controls::DigitalGain, agcPrepareStatus->digitalGain);
|
||||||
|
|
||||||
|
RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
|
||||||
|
controller_.getAlgorithm("agc"));
|
||||||
|
if (agc) {
|
||||||
|
if (!agc->autoExposureEnabled() && !agc->autoGainEnabled())
|
||||||
|
libcameraMetadata_.set(controls::AeState, controls::AeStateIdle);
|
||||||
|
else if (agcPrepareStatus)
|
||||||
|
libcameraMetadata_.set(controls::AeState,
|
||||||
|
agcPrepareStatus->locked
|
||||||
|
? controls::AeStateConverged
|
||||||
|
: controls::AeStateSearching);
|
||||||
}
|
}
|
||||||
|
|
||||||
LuxStatus *luxStatus = rpiMetadata.getLocked<LuxStatus>("lux.status");
|
LuxStatus *luxStatus = rpiMetadata.getLocked<LuxStatus>("lux.status");
|
||||||
|
|
|
@ -30,8 +30,12 @@ public:
|
||||||
virtual void setMeteringMode(std::string const &meteringModeName) = 0;
|
virtual void setMeteringMode(std::string const &meteringModeName) = 0;
|
||||||
virtual void setExposureMode(std::string const &exposureModeName) = 0;
|
virtual void setExposureMode(std::string const &exposureModeName) = 0;
|
||||||
virtual void setConstraintMode(std::string const &contraintModeName) = 0;
|
virtual void setConstraintMode(std::string const &contraintModeName) = 0;
|
||||||
virtual void enableAuto() = 0;
|
virtual void enableAutoExposure() = 0;
|
||||||
virtual void disableAuto() = 0;
|
virtual void disableAutoExposure() = 0;
|
||||||
|
virtual bool autoExposureEnabled() const = 0;
|
||||||
|
virtual void enableAutoGain() = 0;
|
||||||
|
virtual void disableAutoGain() = 0;
|
||||||
|
virtual bool autoGainEnabled() const = 0;
|
||||||
virtual void setActiveChannels(const std::vector<unsigned int> &activeChannels) = 0;
|
virtual void setActiveChannels(const std::vector<unsigned int> &activeChannels) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -74,22 +74,62 @@ int Agc::checkChannel(unsigned int channelIndex) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agc::disableAuto()
|
void Agc::disableAutoExposure()
|
||||||
{
|
{
|
||||||
LOG(RPiAgc, Debug) << "disableAuto";
|
LOG(RPiAgc, Debug) << "disableAutoExposure";
|
||||||
|
|
||||||
/* All channels are enabled/disabled together. */
|
/* All channels are enabled/disabled together. */
|
||||||
for (auto &data : channelData_)
|
for (auto &data : channelData_)
|
||||||
data.channel.disableAuto();
|
data.channel.disableAutoExposure();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Agc::enableAuto()
|
void Agc::enableAutoExposure()
|
||||||
{
|
{
|
||||||
LOG(RPiAgc, Debug) << "enableAuto";
|
LOG(RPiAgc, Debug) << "enableAutoExposure";
|
||||||
|
|
||||||
/* All channels are enabled/disabled together. */
|
/* All channels are enabled/disabled together. */
|
||||||
for (auto &data : channelData_)
|
for (auto &data : channelData_)
|
||||||
data.channel.enableAuto();
|
data.channel.enableAutoExposure();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Agc::autoExposureEnabled() const
|
||||||
|
{
|
||||||
|
LOG(RPiAgc, Debug) << "autoExposureEnabled";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always have at least one channel, and since all channels are
|
||||||
|
* enabled and disabled together we can simply check the first one.
|
||||||
|
*/
|
||||||
|
return channelData_[0].channel.autoExposureEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Agc::disableAutoGain()
|
||||||
|
{
|
||||||
|
LOG(RPiAgc, Debug) << "disableAutoGain";
|
||||||
|
|
||||||
|
/* All channels are enabled/disabled together. */
|
||||||
|
for (auto &data : channelData_)
|
||||||
|
data.channel.disableAutoGain();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Agc::enableAutoGain()
|
||||||
|
{
|
||||||
|
LOG(RPiAgc, Debug) << "enableAutoGain";
|
||||||
|
|
||||||
|
/* All channels are enabled/disabled together. */
|
||||||
|
for (auto &data : channelData_)
|
||||||
|
data.channel.enableAutoGain();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Agc::autoGainEnabled() const
|
||||||
|
{
|
||||||
|
LOG(RPiAgc, Debug) << "autoGainEnabled";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We always have at least one channel, and since all channels are
|
||||||
|
* enabled and disabled together we can simply check the first one.
|
||||||
|
*/
|
||||||
|
return channelData_[0].channel.autoGainEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Agc::getConvergenceFrames() const
|
unsigned int Agc::getConvergenceFrames() const
|
||||||
|
|
|
@ -40,8 +40,12 @@ public:
|
||||||
void setMeteringMode(std::string const &meteringModeName) override;
|
void setMeteringMode(std::string const &meteringModeName) override;
|
||||||
void setExposureMode(std::string const &exposureModeName) override;
|
void setExposureMode(std::string const &exposureModeName) override;
|
||||||
void setConstraintMode(std::string const &contraintModeName) override;
|
void setConstraintMode(std::string const &contraintModeName) override;
|
||||||
void enableAuto() override;
|
void enableAutoExposure() override;
|
||||||
void disableAuto() override;
|
void disableAutoExposure() override;
|
||||||
|
bool autoExposureEnabled() const override;
|
||||||
|
void enableAutoGain() override;
|
||||||
|
void disableAutoGain() override;
|
||||||
|
bool autoGainEnabled() const override;
|
||||||
void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;
|
void switchMode(CameraMode const &cameraMode, Metadata *metadata) override;
|
||||||
void prepare(Metadata *imageMetadata) override;
|
void prepare(Metadata *imageMetadata) override;
|
||||||
void process(StatisticsPtr &stats, Metadata *imageMetadata) override;
|
void process(StatisticsPtr &stats, Metadata *imageMetadata) override;
|
||||||
|
|
|
@ -319,18 +319,36 @@ int AgcChannel::read(const libcamera::YamlObject ¶ms,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgcChannel::disableAuto()
|
void AgcChannel::disableAutoExposure()
|
||||||
{
|
{
|
||||||
fixedExposureTime_ = status_.exposureTime;
|
fixedExposureTime_ = status_.exposureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgcChannel::enableAutoExposure()
|
||||||
|
{
|
||||||
|
fixedExposureTime_ = 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AgcChannel::autoExposureEnabled() const
|
||||||
|
{
|
||||||
|
return fixedExposureTime_ == 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgcChannel::disableAutoGain()
|
||||||
|
{
|
||||||
fixedAnalogueGain_ = status_.analogueGain;
|
fixedAnalogueGain_ = status_.analogueGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AgcChannel::enableAuto()
|
void AgcChannel::enableAutoGain()
|
||||||
{
|
{
|
||||||
fixedExposureTime_ = 0s;
|
|
||||||
fixedAnalogueGain_ = 0;
|
fixedAnalogueGain_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AgcChannel::autoGainEnabled() const
|
||||||
|
{
|
||||||
|
return fixedAnalogueGain_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int AgcChannel::getConvergenceFrames() const
|
unsigned int AgcChannel::getConvergenceFrames() const
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -96,8 +96,12 @@ public:
|
||||||
void setMeteringMode(std::string const &meteringModeName);
|
void setMeteringMode(std::string const &meteringModeName);
|
||||||
void setExposureMode(std::string const &exposureModeName);
|
void setExposureMode(std::string const &exposureModeName);
|
||||||
void setConstraintMode(std::string const &contraintModeName);
|
void setConstraintMode(std::string const &contraintModeName);
|
||||||
void enableAuto();
|
void enableAutoExposure();
|
||||||
void disableAuto();
|
void disableAutoExposure();
|
||||||
|
bool autoExposureEnabled() const;
|
||||||
|
void enableAutoGain();
|
||||||
|
void disableAutoGain();
|
||||||
|
bool autoGainEnabled() const;
|
||||||
void switchMode(CameraMode const &cameraMode, Metadata *metadata);
|
void switchMode(CameraMode const &cameraMode, Metadata *metadata);
|
||||||
void prepare(Metadata *imageMetadata);
|
void prepare(Metadata *imageMetadata);
|
||||||
void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,
|
void process(StatisticsPtr &stats, DeviceStatus const &deviceStatus, Metadata *imageMetadata,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue