mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-20 19:05:05 +03:00
libcamera: Rename "shutter speed" to "exposure time"
The terms "shutter" and "shutter speed" are used through libcamera to mean "exposure time". This is confusing, both due to "speed" being used as "time" while it should be the inverse (i.e. a maximum speed should correspond to the minimum time), and due to "shutter speed" and "exposure time" being used in different places with the same meaning. To improve clarity of the code base and the documentation, use "exposure time" consistently to replace "shutter speed". This rename highlighted another vocabulary issue in libcamera. The ExposureModeHelper::splitExposure() function used to document that it splits "exposure time into shutter time and gain". It has been reworded to "split exposure into exposure time and gain". That is not entirely satisfactory, as "exposure" has a defined meaning in photography (see https://en.wikipedia.org/wiki/Exposure_(photography)) that is not expressed as a duration. This issue if left to be addressed separately. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
parent
e5f8d40bad
commit
d0478c41f4
33 changed files with 334 additions and 327 deletions
|
@ -67,7 +67,7 @@ int AgcExposureMode::read(const libcamera::YamlObject ¶ms)
|
|||
auto value = params["shutter"].getList<double>();
|
||||
if (!value)
|
||||
return -EINVAL;
|
||||
std::transform(value->begin(), value->end(), std::back_inserter(shutter),
|
||||
std::transform(value->begin(), value->end(), std::back_inserter(exposureTime),
|
||||
[](double v) { return v * 1us; });
|
||||
|
||||
value = params["gain"].getList<double>();
|
||||
|
@ -75,13 +75,13 @@ int AgcExposureMode::read(const libcamera::YamlObject ¶ms)
|
|||
return -EINVAL;
|
||||
gain = std::move(*value);
|
||||
|
||||
if (shutter.size() < 2 || gain.size() < 2) {
|
||||
if (exposureTime.size() < 2 || gain.size() < 2) {
|
||||
LOG(RPiAgc, Error)
|
||||
<< "AgcExposureMode: must have at least two entries in exposure profile";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (shutter.size() != gain.size()) {
|
||||
if (exposureTime.size() != gain.size()) {
|
||||
LOG(RPiAgc, Error)
|
||||
<< "AgcExposureMode: expect same number of exposure and gain entries in exposure profile";
|
||||
return -EINVAL;
|
||||
|
@ -262,7 +262,7 @@ int AgcConfig::read(const libcamera::YamlObject ¶ms)
|
|||
}
|
||||
|
||||
AgcChannel::ExposureValues::ExposureValues()
|
||||
: shutter(0s), analogueGain(0),
|
||||
: exposureTime(0s), analogueGain(0),
|
||||
totalExposure(0s), totalExposureNoDG(0s)
|
||||
{
|
||||
}
|
||||
|
@ -271,7 +271,7 @@ AgcChannel::AgcChannel()
|
|||
: meteringMode_(nullptr), exposureMode_(nullptr), constraintMode_(nullptr),
|
||||
frameCount_(0), lockCount_(0),
|
||||
lastTargetExposure_(0s), ev_(1.0), flickerPeriod_(0s),
|
||||
maxShutter_(0s), fixedShutter_(0s), fixedAnalogueGain_(0.0)
|
||||
maxExposureTime_(0s), fixedExposureTime_(0s), fixedAnalogueGain_(0.0)
|
||||
{
|
||||
/* Set AWB default values in case early frames have no updates in metadata. */
|
||||
awb_.gainR = 1.0;
|
||||
|
@ -312,31 +312,31 @@ int AgcChannel::read(const libcamera::YamlObject ¶ms,
|
|||
exposureMode_ = &config_.exposureModes[exposureModeName_];
|
||||
constraintModeName_ = config_.defaultConstraintMode;
|
||||
constraintMode_ = &config_.constraintModes[constraintModeName_];
|
||||
/* Set up the "last shutter/gain" values, in case AGC starts "disabled". */
|
||||
status_.shutterTime = config_.defaultExposureTime;
|
||||
/* Set up the "last exposure time/gain" values, in case AGC starts "disabled". */
|
||||
status_.exposureTime = config_.defaultExposureTime;
|
||||
status_.analogueGain = config_.defaultAnalogueGain;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AgcChannel::disableAuto()
|
||||
{
|
||||
fixedShutter_ = status_.shutterTime;
|
||||
fixedExposureTime_ = status_.exposureTime;
|
||||
fixedAnalogueGain_ = status_.analogueGain;
|
||||
}
|
||||
|
||||
void AgcChannel::enableAuto()
|
||||
{
|
||||
fixedShutter_ = 0s;
|
||||
fixedExposureTime_ = 0s;
|
||||
fixedAnalogueGain_ = 0;
|
||||
}
|
||||
|
||||
unsigned int AgcChannel::getConvergenceFrames() const
|
||||
{
|
||||
/*
|
||||
* If shutter and gain have been explicitly set, there is no
|
||||
* If exposure time and gain have been explicitly set, there is no
|
||||
* convergence to happen, so no need to drop any frames - return zero.
|
||||
*/
|
||||
if (fixedShutter_ && fixedAnalogueGain_)
|
||||
if (fixedExposureTime_ && fixedAnalogueGain_)
|
||||
return 0;
|
||||
else
|
||||
return config_.convergenceFrames;
|
||||
|
@ -364,16 +364,16 @@ void AgcChannel::setFlickerPeriod(Duration flickerPeriod)
|
|||
flickerPeriod_ = flickerPeriod;
|
||||
}
|
||||
|
||||
void AgcChannel::setMaxShutter(Duration maxShutter)
|
||||
void AgcChannel::setMaxExposureTime(Duration maxExposureTime)
|
||||
{
|
||||
maxShutter_ = maxShutter;
|
||||
maxExposureTime_ = maxExposureTime;
|
||||
}
|
||||
|
||||
void AgcChannel::setFixedShutter(Duration fixedShutter)
|
||||
void AgcChannel::setFixedExposureTime(Duration fixedExposureTime)
|
||||
{
|
||||
fixedShutter_ = fixedShutter;
|
||||
fixedExposureTime_ = fixedExposureTime;
|
||||
/* Set this in case someone calls disableAuto() straight after. */
|
||||
status_.shutterTime = limitShutter(fixedShutter_);
|
||||
status_.exposureTime = limitExposureTime(fixedExposureTime_);
|
||||
}
|
||||
|
||||
void AgcChannel::setFixedAnalogueGain(double fixedAnalogueGain)
|
||||
|
@ -413,22 +413,22 @@ void AgcChannel::switchMode(CameraMode const &cameraMode,
|
|||
double lastSensitivity = mode_.sensitivity;
|
||||
mode_ = cameraMode;
|
||||
|
||||
Duration fixedShutter = limitShutter(fixedShutter_);
|
||||
if (fixedShutter && fixedAnalogueGain_) {
|
||||
Duration fixedExposureTime = limitExposureTime(fixedExposureTime_);
|
||||
if (fixedExposureTime && fixedAnalogueGain_) {
|
||||
/* We're going to reset the algorithm here with these fixed values. */
|
||||
fetchAwbStatus(metadata);
|
||||
double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 });
|
||||
ASSERT(minColourGain != 0.0);
|
||||
|
||||
/* This is the equivalent of computeTargetExposure and applyDigitalGain. */
|
||||
target_.totalExposureNoDG = fixedShutter_ * fixedAnalogueGain_;
|
||||
target_.totalExposureNoDG = fixedExposureTime_ * fixedAnalogueGain_;
|
||||
target_.totalExposure = target_.totalExposureNoDG / minColourGain;
|
||||
|
||||
/* Equivalent of filterExposure. This resets any "history". */
|
||||
filtered_ = target_;
|
||||
|
||||
/* Equivalent of divideUpExposure. */
|
||||
filtered_.shutter = fixedShutter;
|
||||
filtered_.exposureTime = fixedExposureTime;
|
||||
filtered_.analogueGain = fixedAnalogueGain_;
|
||||
} else if (status_.totalExposureValue) {
|
||||
/*
|
||||
|
@ -450,14 +450,15 @@ void AgcChannel::switchMode(CameraMode const &cameraMode,
|
|||
divideUpExposure();
|
||||
} else {
|
||||
/*
|
||||
* We come through here on startup, when at least one of the shutter
|
||||
* or gain has not been fixed. We must still write those values out so
|
||||
* that they will be applied immediately. We supply some arbitrary defaults
|
||||
* for any that weren't set.
|
||||
* We come through here on startup, when at least one of the
|
||||
* exposure time or gain has not been fixed. We must still
|
||||
* write those values out so that they will be applied
|
||||
* immediately. We supply some arbitrary defaults for any that
|
||||
* weren't set.
|
||||
*/
|
||||
|
||||
/* Equivalent of divideUpExposure. */
|
||||
filtered_.shutter = fixedShutter ? fixedShutter : config_.defaultExposureTime;
|
||||
filtered_.exposureTime = fixedExposureTime ? fixedExposureTime : config_.defaultExposureTime;
|
||||
filtered_.analogueGain = fixedAnalogueGain_ ? fixedAnalogueGain_ : config_.defaultAnalogueGain;
|
||||
}
|
||||
|
||||
|
@ -483,7 +484,7 @@ void AgcChannel::prepare(Metadata *imageMetadata)
|
|||
/* Process has run, so we have meaningful values. */
|
||||
DeviceStatus deviceStatus;
|
||||
if (imageMetadata->get("device.status", deviceStatus) == 0) {
|
||||
Duration actualExposure = deviceStatus.shutterSpeed *
|
||||
Duration actualExposure = deviceStatus.exposureTime *
|
||||
deviceStatus.analogueGain;
|
||||
if (actualExposure) {
|
||||
double digitalGain = totalExposureValue / actualExposure;
|
||||
|
@ -537,7 +538,7 @@ void AgcChannel::process(StatisticsPtr &stats, DeviceStatus const &deviceStatus,
|
|||
*/
|
||||
bool desaturate = applyDigitalGain(gain, targetY, channelBound);
|
||||
/*
|
||||
* The last thing is to divide up the exposure value into a shutter time
|
||||
* The last thing is to divide up the exposure value into a exposure time
|
||||
* and analogue gain, according to the current exposure mode.
|
||||
*/
|
||||
divideUpExposure();
|
||||
|
@ -553,7 +554,7 @@ bool AgcChannel::updateLockStatus(DeviceStatus const &deviceStatus)
|
|||
const double resetMargin = 1.5;
|
||||
|
||||
/* Add 200us to the exposure time error to allow for line quantisation. */
|
||||
Duration exposureError = lastDeviceStatus_.shutterSpeed * errorFactor + 200us;
|
||||
Duration exposureError = lastDeviceStatus_.exposureTime * errorFactor + 200us;
|
||||
double gainError = lastDeviceStatus_.analogueGain * errorFactor;
|
||||
Duration targetError = lastTargetExposure_ * errorFactor;
|
||||
|
||||
|
@ -562,15 +563,15 @@ bool AgcChannel::updateLockStatus(DeviceStatus const &deviceStatus)
|
|||
* the values we keep requesting may be unachievable. For this reason
|
||||
* we only insist that we're close to values in the past few frames.
|
||||
*/
|
||||
if (deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed - exposureError &&
|
||||
deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed + exposureError &&
|
||||
if (deviceStatus.exposureTime > lastDeviceStatus_.exposureTime - exposureError &&
|
||||
deviceStatus.exposureTime < lastDeviceStatus_.exposureTime + exposureError &&
|
||||
deviceStatus.analogueGain > lastDeviceStatus_.analogueGain - gainError &&
|
||||
deviceStatus.analogueGain < lastDeviceStatus_.analogueGain + gainError &&
|
||||
status_.targetExposureValue > lastTargetExposure_ - targetError &&
|
||||
status_.targetExposureValue < lastTargetExposure_ + targetError)
|
||||
lockCount_ = std::min(lockCount_ + 1, maxLockCount);
|
||||
else if (deviceStatus.shutterSpeed < lastDeviceStatus_.shutterSpeed - resetMargin * exposureError ||
|
||||
deviceStatus.shutterSpeed > lastDeviceStatus_.shutterSpeed + resetMargin * exposureError ||
|
||||
else if (deviceStatus.exposureTime < lastDeviceStatus_.exposureTime - resetMargin * exposureError ||
|
||||
deviceStatus.exposureTime > lastDeviceStatus_.exposureTime + resetMargin * exposureError ||
|
||||
deviceStatus.analogueGain < lastDeviceStatus_.analogueGain - resetMargin * gainError ||
|
||||
deviceStatus.analogueGain > lastDeviceStatus_.analogueGain + resetMargin * gainError ||
|
||||
status_.targetExposureValue < lastTargetExposure_ - resetMargin * targetError ||
|
||||
|
@ -588,11 +589,11 @@ void AgcChannel::housekeepConfig()
|
|||
{
|
||||
/* First fetch all the up-to-date settings, so no one else has to do it. */
|
||||
status_.ev = ev_;
|
||||
status_.fixedShutter = limitShutter(fixedShutter_);
|
||||
status_.fixedExposureTime = limitExposureTime(fixedExposureTime_);
|
||||
status_.fixedAnalogueGain = fixedAnalogueGain_;
|
||||
status_.flickerPeriod = flickerPeriod_;
|
||||
LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedShutter "
|
||||
<< status_.fixedShutter << " fixedAnalogueGain "
|
||||
LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixedExposureTime "
|
||||
<< status_.fixedExposureTime << " fixedAnalogueGain "
|
||||
<< status_.fixedAnalogueGain;
|
||||
/*
|
||||
* Make sure the "mode" pointers point to the up-to-date things, if
|
||||
|
@ -636,10 +637,10 @@ void AgcChannel::housekeepConfig()
|
|||
|
||||
void AgcChannel::fetchCurrentExposure(DeviceStatus const &deviceStatus)
|
||||
{
|
||||
current_.shutter = deviceStatus.shutterSpeed;
|
||||
current_.exposureTime = deviceStatus.exposureTime;
|
||||
current_.analogueGain = deviceStatus.analogueGain;
|
||||
current_.totalExposure = 0s; /* this value is unused */
|
||||
current_.totalExposureNoDG = current_.shutter * current_.analogueGain;
|
||||
current_.totalExposureNoDG = current_.exposureTime * current_.analogueGain;
|
||||
}
|
||||
|
||||
void AgcChannel::fetchAwbStatus(Metadata *imageMetadata)
|
||||
|
@ -777,17 +778,17 @@ void AgcChannel::computeGain(StatisticsPtr &statistics, Metadata *imageMetadata,
|
|||
|
||||
void AgcChannel::computeTargetExposure(double gain)
|
||||
{
|
||||
if (status_.fixedShutter && status_.fixedAnalogueGain) {
|
||||
if (status_.fixedExposureTime && status_.fixedAnalogueGain) {
|
||||
/*
|
||||
* When ag and shutter are both fixed, we need to drive the
|
||||
* total exposure so that we end up with a digital gain of at least
|
||||
* 1/minColourGain. Otherwise we'd desaturate channels causing
|
||||
* white to go cyan or magenta.
|
||||
* When analogue gain and exposure time are both fixed, we need
|
||||
* to drive the total exposure so that we end up with a digital
|
||||
* gain of at least 1/minColourGain. Otherwise we'd desaturate
|
||||
* channels causing white to go cyan or magenta.
|
||||
*/
|
||||
double minColourGain = std::min({ awb_.gainR, awb_.gainG, awb_.gainB, 1.0 });
|
||||
ASSERT(minColourGain != 0.0);
|
||||
target_.totalExposure =
|
||||
status_.fixedShutter * status_.fixedAnalogueGain / minColourGain;
|
||||
status_.fixedExposureTime * status_.fixedAnalogueGain / minColourGain;
|
||||
} else {
|
||||
/*
|
||||
* The statistics reflect the image without digital gain, so the final
|
||||
|
@ -795,12 +796,12 @@ void AgcChannel::computeTargetExposure(double gain)
|
|||
*/
|
||||
target_.totalExposure = current_.totalExposureNoDG * gain;
|
||||
/* The final target exposure is also limited to what the exposure mode allows. */
|
||||
Duration maxShutter = status_.fixedShutter
|
||||
? status_.fixedShutter
|
||||
: exposureMode_->shutter.back();
|
||||
maxShutter = limitShutter(maxShutter);
|
||||
Duration maxExposureTime = status_.fixedExposureTime
|
||||
? status_.fixedExposureTime
|
||||
: exposureMode_->exposureTime.back();
|
||||
maxExposureTime = limitExposureTime(maxExposureTime);
|
||||
Duration maxTotalExposure =
|
||||
maxShutter *
|
||||
maxExposureTime *
|
||||
(status_.fixedAnalogueGain != 0.0
|
||||
? status_.fixedAnalogueGain
|
||||
: exposureMode_->gain.back());
|
||||
|
@ -884,11 +885,12 @@ void AgcChannel::filterExposure()
|
|||
double stableRegion = config_.stableRegion;
|
||||
|
||||
/*
|
||||
* AGC adapts instantly if both shutter and gain are directly specified
|
||||
* or we're in the startup phase. Also disable the stable region, because we want
|
||||
* to reflect any user exposure/gain updates, however small.
|
||||
* AGC adapts instantly if both exposure time and gain are directly
|
||||
* specified or we're in the startup phase. Also disable the stable
|
||||
* region, because we want to reflect any user exposure/gain updates,
|
||||
* however small.
|
||||
*/
|
||||
if ((status_.fixedShutter && status_.fixedAnalogueGain) ||
|
||||
if ((status_.fixedExposureTime && status_.fixedAnalogueGain) ||
|
||||
frameCount_ <= config_.startupFrames) {
|
||||
speed = 1.0;
|
||||
stableRegion = 0.0;
|
||||
|
@ -916,34 +918,34 @@ void AgcChannel::filterExposure()
|
|||
void AgcChannel::divideUpExposure()
|
||||
{
|
||||
/*
|
||||
* Sending the fixed shutter/gain cases through the same code may seem
|
||||
* unnecessary, but it will make more sense when extend this to cover
|
||||
* variable aperture.
|
||||
* Sending the fixed exposure time/gain cases through the same code may
|
||||
* seem unnecessary, but it will make more sense when extend this to
|
||||
* cover variable aperture.
|
||||
*/
|
||||
Duration exposureValue = filtered_.totalExposureNoDG;
|
||||
Duration shutterTime;
|
||||
Duration exposureTime;
|
||||
double analogueGain;
|
||||
shutterTime = status_.fixedShutter ? status_.fixedShutter
|
||||
: exposureMode_->shutter[0];
|
||||
shutterTime = limitShutter(shutterTime);
|
||||
exposureTime = status_.fixedExposureTime ? status_.fixedExposureTime
|
||||
: exposureMode_->exposureTime[0];
|
||||
exposureTime = limitExposureTime(exposureTime);
|
||||
analogueGain = status_.fixedAnalogueGain != 0.0 ? status_.fixedAnalogueGain
|
||||
: exposureMode_->gain[0];
|
||||
analogueGain = limitGain(analogueGain);
|
||||
if (shutterTime * analogueGain < exposureValue) {
|
||||
if (exposureTime * analogueGain < exposureValue) {
|
||||
for (unsigned int stage = 1;
|
||||
stage < exposureMode_->gain.size(); stage++) {
|
||||
if (!status_.fixedShutter) {
|
||||
Duration stageShutter =
|
||||
limitShutter(exposureMode_->shutter[stage]);
|
||||
if (stageShutter * analogueGain >= exposureValue) {
|
||||
shutterTime = exposureValue / analogueGain;
|
||||
if (!status_.fixedExposureTime) {
|
||||
Duration stageExposureTime =
|
||||
limitExposureTime(exposureMode_->exposureTime[stage]);
|
||||
if (stageExposureTime * analogueGain >= exposureValue) {
|
||||
exposureTime = exposureValue / analogueGain;
|
||||
break;
|
||||
}
|
||||
shutterTime = stageShutter;
|
||||
exposureTime = stageExposureTime;
|
||||
}
|
||||
if (status_.fixedAnalogueGain == 0.0) {
|
||||
if (exposureMode_->gain[stage] * shutterTime >= exposureValue) {
|
||||
analogueGain = exposureValue / shutterTime;
|
||||
if (exposureMode_->gain[stage] * exposureTime >= exposureValue) {
|
||||
analogueGain = exposureValue / exposureTime;
|
||||
break;
|
||||
}
|
||||
analogueGain = exposureMode_->gain[stage];
|
||||
|
@ -951,18 +953,19 @@ void AgcChannel::divideUpExposure()
|
|||
}
|
||||
}
|
||||
}
|
||||
LOG(RPiAgc, Debug) << "Divided up shutter and gain are " << shutterTime << " and "
|
||||
<< analogueGain;
|
||||
LOG(RPiAgc, Debug)
|
||||
<< "Divided up exposure time and gain are " << exposureTime
|
||||
<< " and " << analogueGain;
|
||||
/*
|
||||
* Finally adjust shutter time for flicker avoidance (require both
|
||||
* shutter and gain not to be fixed).
|
||||
* Finally adjust exposure time for flicker avoidance (require both
|
||||
* exposure time and gain not to be fixed).
|
||||
*/
|
||||
if (!status_.fixedShutter && !status_.fixedAnalogueGain &&
|
||||
if (!status_.fixedExposureTime && !status_.fixedAnalogueGain &&
|
||||
status_.flickerPeriod) {
|
||||
int flickerPeriods = shutterTime / status_.flickerPeriod;
|
||||
int flickerPeriods = exposureTime / status_.flickerPeriod;
|
||||
if (flickerPeriods) {
|
||||
Duration newShutterTime = flickerPeriods * status_.flickerPeriod;
|
||||
analogueGain *= shutterTime / newShutterTime;
|
||||
Duration newExposureTime = flickerPeriods * status_.flickerPeriod;
|
||||
analogueGain *= exposureTime / newExposureTime;
|
||||
/*
|
||||
* We should still not allow the ag to go over the
|
||||
* largest value in the exposure mode. Note that this
|
||||
|
@ -971,12 +974,12 @@ void AgcChannel::divideUpExposure()
|
|||
*/
|
||||
analogueGain = std::min(analogueGain, exposureMode_->gain.back());
|
||||
analogueGain = limitGain(analogueGain);
|
||||
shutterTime = newShutterTime;
|
||||
exposureTime = newExposureTime;
|
||||
}
|
||||
LOG(RPiAgc, Debug) << "After flicker avoidance, shutter "
|
||||
<< shutterTime << " gain " << analogueGain;
|
||||
LOG(RPiAgc, Debug) << "After flicker avoidance, exposure time "
|
||||
<< exposureTime << " gain " << analogueGain;
|
||||
}
|
||||
filtered_.shutter = shutterTime;
|
||||
filtered_.exposureTime = exposureTime;
|
||||
filtered_.analogueGain = analogueGain;
|
||||
}
|
||||
|
||||
|
@ -984,7 +987,7 @@ void AgcChannel::writeAndFinish(Metadata *imageMetadata, bool desaturate)
|
|||
{
|
||||
status_.totalExposureValue = filtered_.totalExposure;
|
||||
status_.targetExposureValue = desaturate ? 0s : target_.totalExposure;
|
||||
status_.shutterTime = filtered_.shutter;
|
||||
status_.exposureTime = filtered_.exposureTime;
|
||||
status_.analogueGain = filtered_.analogueGain;
|
||||
/*
|
||||
* Write to metadata as well, in case anyone wants to update the camera
|
||||
|
@ -993,32 +996,32 @@ void AgcChannel::writeAndFinish(Metadata *imageMetadata, bool desaturate)
|
|||
imageMetadata->set("agc.status", status_);
|
||||
LOG(RPiAgc, Debug) << "Output written, total exposure requested is "
|
||||
<< filtered_.totalExposure;
|
||||
LOG(RPiAgc, Debug) << "Camera exposure update: shutter time " << filtered_.shutter
|
||||
LOG(RPiAgc, Debug) << "Camera exposure update: exposure time " << filtered_.exposureTime
|
||||
<< " analogue gain " << filtered_.analogueGain;
|
||||
}
|
||||
|
||||
Duration AgcChannel::limitShutter(Duration shutter)
|
||||
Duration AgcChannel::limitExposureTime(Duration exposureTime)
|
||||
{
|
||||
/*
|
||||
* shutter == 0 is a special case for fixed shutter values, and must pass
|
||||
* through unchanged
|
||||
* exposureTime == 0 is a special case for fixed exposure time values,
|
||||
* and must pass through unchanged.
|
||||
*/
|
||||
if (!shutter)
|
||||
return shutter;
|
||||
if (!exposureTime)
|
||||
return exposureTime;
|
||||
|
||||
shutter = std::clamp(shutter, mode_.minShutter, maxShutter_);
|
||||
return shutter;
|
||||
exposureTime = std::clamp(exposureTime, mode_.minExposureTime, maxExposureTime_);
|
||||
return exposureTime;
|
||||
}
|
||||
|
||||
double AgcChannel::limitGain(double gain) const
|
||||
{
|
||||
/*
|
||||
* Only limit the lower bounds of the gain value to what the sensor limits.
|
||||
* The upper bound on analogue gain will be made up with additional digital
|
||||
* gain applied by the ISP.
|
||||
* Only limit the lower bounds of the gain value to what the sensor
|
||||
* limits. The upper bound on analogue gain will be made up with
|
||||
* additional digital gain applied by the ISP.
|
||||
*
|
||||
* gain == 0.0 is a special case for fixed shutter values, and must pass
|
||||
* through unchanged
|
||||
* gain == 0.0 is a special case for fixed exposure time values, and
|
||||
* must pass through unchanged.
|
||||
*/
|
||||
if (!gain)
|
||||
return gain;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue