libcamera: ipa: raspberrypi: Recalculate camera exposure/gain when camera mode changes

This commit causes the AGC to recalculate its camera exposure/gain
values when the camera mode changes. For example it's possible
that the exposure profile could be changed by the application so
the division between exposure time and analogue gain may be
different.

The other underlying reason (and which this commit accomplishes too)
is that the sensor's line timing may change in a new mode, and because
V4L2 drivers store a number of exposure _lines_, the resulting _time_
will "change under our feet". So we have to go through the process of
recalculating the correct number of lines and writing this back to the
sensor with every mode switch, regardless of anything else.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
This commit is contained in:
David Plowman 2020-06-18 12:12:36 +01:00 committed by Laurent Pinchart
parent ff291b3c15
commit 846e7d999a
3 changed files with 26 additions and 12 deletions

View file

@ -221,6 +221,18 @@ void Agc::SetConstraintMode(std::string const &constraint_mode_name)
constraint_mode_name_ = constraint_mode_name; constraint_mode_name_ = constraint_mode_name;
} }
void Agc::SwitchMode(CameraMode const &camera_mode, Metadata *metadata)
{
// On a mode switch, it's possible the exposure profile could change,
// so we run through the dividing up of exposure/gain again and
// write the results into the metadata we've been given.
if (status_.total_exposure_value) {
housekeepConfig();
divvyupExposure();
writeAndFinish(metadata, false);
}
}
void Agc::Prepare(Metadata *image_metadata) void Agc::Prepare(Metadata *image_metadata)
{ {
AgcStatus status; AgcStatus status;

View file

@ -75,6 +75,7 @@ public:
void SetMeteringMode(std::string const &metering_mode_name) override; void SetMeteringMode(std::string const &metering_mode_name) override;
void SetExposureMode(std::string const &exposure_mode_name) override; void SetExposureMode(std::string const &exposure_mode_name) override;
void SetConstraintMode(std::string const &contraint_mode_name) override; void SetConstraintMode(std::string const &contraint_mode_name) override;
void SwitchMode(CameraMode const &camera_mode, Metadata *metadata) override;
void Prepare(Metadata *image_metadata) override; void Prepare(Metadata *image_metadata) override;
void Process(StatisticsPtr &stats, Metadata *image_metadata) override; void Process(StatisticsPtr &stats, Metadata *image_metadata) override;

View file

@ -247,29 +247,30 @@ void IPARPi::configure(const CameraSensorInfo &sensorInfo,
mistrust_count_ = helper_->MistrustFramesStartup(); mistrust_count_ = helper_->MistrustFramesStartup();
} }
struct AgcStatus agcStatus;
/* These zero values mean not program anything (unless overwritten). */
agcStatus.shutter_time = 0.0;
agcStatus.analogue_gain = 0.0;
if (!controllerInit_) { if (!controllerInit_) {
/* Load the tuning file for this sensor. */ /* Load the tuning file for this sensor. */
controller_.Read(tuningFile_.c_str()); controller_.Read(tuningFile_.c_str());
controller_.Initialise(); controller_.Initialise();
controllerInit_ = true; controllerInit_ = true;
/* Calculate initial values for gain and exposure. */ /* Supply initial values for gain and exposure. */
int32_t gain_code = helper_->GainCode(DEFAULT_ANALOGUE_GAIN); agcStatus.shutter_time = DEFAULT_EXPOSURE_TIME;
int32_t exposure_lines = helper_->ExposureLines(DEFAULT_EXPOSURE_TIME); agcStatus.analogue_gain = DEFAULT_ANALOGUE_GAIN;
ControlList ctrls(unicam_ctrls_);
ctrls.set(V4L2_CID_ANALOGUE_GAIN, gain_code);
ctrls.set(V4L2_CID_EXPOSURE, exposure_lines);
IPAOperationData op;
op.operation = RPI_IPA_ACTION_V4L2_SET_STAGGERED;
op.controls.push_back(ctrls);
queueFrameAction.emit(0, op);
} }
RPi::Metadata metadata; RPi::Metadata metadata;
controller_.SwitchMode(mode_, &metadata); controller_.SwitchMode(mode_, &metadata);
/* SwitchMode may supply updated exposure/gain values to use. */
metadata.Get("agc.status", agcStatus);
if (agcStatus.shutter_time != 0.0 && agcStatus.analogue_gain != 0.0)
applyAGC(&agcStatus);
lastMode_ = mode_; lastMode_ = mode_;
} }