[libcamera-devel] [PATCH v4 4/5] ipa: raspberrypi: Pass the maximum allowable shutter speed into the AGC

Laurent Pinchart laurent.pinchart at ideasonboard.com
Thu Feb 4 21:59:06 CET 2021


Hi Naush,

Thank you for the patch.

On Fri, Jan 29, 2021 at 11:16:15AM +0000, Naushir Patuck wrote:
> In order to provide an optimal split between shutter speed and gain, the
> AGC must know the maximum allowable shutter speed, as limited by the
> maximum frame duration (either application provided or the default).
> 
> Add a new API function, SetMaxShutter, to the AgcAlgorithm class. The
> IPA provides the the maximum shutter speed for AGC calculations.

s/the the/the/

> This applies to both the manual and auto AGC modes.
> 
> Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> Reviewed-by: David Plowman <david.plowman at raspberrypi.com>
> Reviewed-by: Jacopo Mondi <jacopo at jmondi.org>
> ---
>  .../raspberrypi/controller/agc_algorithm.hpp  |  1 +
>  src/ipa/raspberrypi/controller/rpi/agc.cpp    | 48 +++++++++++++------
>  src/ipa/raspberrypi/controller/rpi/agc.hpp    |  3 ++
>  src/ipa/raspberrypi/raspberrypi.cpp           | 12 +++++
>  4 files changed, 49 insertions(+), 15 deletions(-)
> 
> diff --git a/src/ipa/raspberrypi/controller/agc_algorithm.hpp b/src/ipa/raspberrypi/controller/agc_algorithm.hpp
> index 981f1de2f0e4..f97deb0fca59 100644
> --- a/src/ipa/raspberrypi/controller/agc_algorithm.hpp
> +++ b/src/ipa/raspberrypi/controller/agc_algorithm.hpp
> @@ -19,6 +19,7 @@ public:
>  	virtual void SetEv(double ev) = 0;
>  	virtual void SetFlickerPeriod(double flicker_period) = 0;
>  	virtual void SetFixedShutter(double fixed_shutter) = 0; // microseconds
> +	virtual void SetMaxShutter(double max_shutter) = 0; // microseconds
>  	virtual void SetFixedAnalogueGain(double fixed_analogue_gain) = 0;
>  	virtual void SetMeteringMode(std::string const &metering_mode_name) = 0;
>  	virtual void SetExposureMode(std::string const &exposure_mode_name) = 0;
> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp
> index eddd1684da12..0023d50029f1 100644
> --- a/src/ipa/raspberrypi/controller/rpi/agc.cpp
> +++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp
> @@ -157,7 +157,7 @@ Agc::Agc(Controller *controller)
>  	  frame_count_(0), lock_count_(0),
>  	  last_target_exposure_(0.0),
>  	  ev_(1.0), flicker_period_(0.0),
> -	  fixed_shutter_(0), fixed_analogue_gain_(0.0)
> +	  max_shutter_(0), fixed_shutter_(0), fixed_analogue_gain_(0.0)
>  {
>  	memset(&awb_, 0, sizeof(awb_));
>  	// Setting status_.total_exposure_value_ to zero initially tells us
> @@ -227,11 +227,16 @@ void Agc::SetFlickerPeriod(double flicker_period)
>  	flicker_period_ = flicker_period;
>  }
>  
> +void Agc::SetMaxShutter(double max_shutter)
> +{
> +	max_shutter_ = max_shutter;
> +}
> +
>  void Agc::SetFixedShutter(double fixed_shutter)
>  {
>  	fixed_shutter_ = fixed_shutter;
>  	// Set this in case someone calls Pause() straight after.
> -	status_.shutter_time = fixed_shutter;
> +	status_.shutter_time = clipShutter(fixed_shutter_);
>  }
>  
>  void Agc::SetFixedAnalogueGain(double fixed_analogue_gain)
> @@ -261,7 +266,8 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,
>  {
>  	housekeepConfig();
>  
> -	if (fixed_shutter_ != 0.0 && fixed_analogue_gain_ != 0.0) {
> +	double fixed_shutter = clipShutter(fixed_shutter_);
> +	if (fixed_shutter != 0.0 && fixed_analogue_gain_ != 0.0) {
>  		// We're going to reset the algorithm here with these fixed values.
>  
>  		fetchAwbStatus(metadata);
> @@ -269,14 +275,14 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,
>  		ASSERT(min_colour_gain != 0.0);
>  
>  		// This is the equivalent of computeTargetExposure and applyDigitalGain.
> -		target_.total_exposure_no_dg = fixed_shutter_ * fixed_analogue_gain_;
> +		target_.total_exposure_no_dg = fixed_shutter * fixed_analogue_gain_;
>  		target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain;
>  
>  		// Equivalent of filterExposure. This resets any "history".
>  		filtered_ = target_;
>  
>  		// Equivalent of divideUpExposure.
> -		filtered_.shutter = fixed_shutter_;
> +		filtered_.shutter = fixed_shutter;
>  		filtered_.analogue_gain = fixed_analogue_gain_;
>  	} else if (status_.total_exposure_value) {
>  		// On a mode switch, it's possible the exposure profile could change,
> @@ -290,7 +296,7 @@ void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,
>  		// for any that weren't set.
>  
>  		// Equivalent of divideUpExposure.
> -		filtered_.shutter = fixed_shutter_ ? fixed_shutter_ : config_.default_exposure_time;
> +		filtered_.shutter = fixed_shutter ? fixed_shutter : config_.default_exposure_time;
>  		filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain;
>  	}
>  
> @@ -403,7 +409,8 @@ void Agc::housekeepConfig()
>  {
>  	// First fetch all the up-to-date settings, so no one else has to do it.
>  	status_.ev = ev_;
> -	status_.fixed_shutter = fixed_shutter_;
> +	double fixed_shutter = clipShutter(fixed_shutter_);
> +	status_.fixed_shutter = fixed_shutter;

You could write

	status_.fixed_shutter = clipShutter(fixed_shutter_);

>  	status_.fixed_analogue_gain = fixed_analogue_gain_;
>  	status_.flicker_period = flicker_period_;
>  	LOG(RPiAgc, Debug) << "ev " << status_.ev << " fixed_shutter "
> @@ -582,13 +589,15 @@ void Agc::computeTargetExposure(double gain)
>  		target_.total_exposure = current_.total_exposure_no_dg * gain;
>  		// The final target exposure is also limited to what the exposure
>  		// mode allows.
> +		double max_shutter = status_.fixed_shutter != 0.0
> +					     ? status_.fixed_shutter
> +					     : exposure_mode_->shutter.back();

The indentation is a bit weird, how about this ?

		double max_shutter = status_.fixed_shutter != 0.0
				   ? status_.fixed_shutter
				   : exposure_mode_->shutter.back();

Those are minor issues,

Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

If you're fine with these changes, there's no need to resent, I'll fix
when applying.

> +		max_shutter = clipShutter(max_shutter);
>  		double max_total_exposure =
> -			(status_.fixed_shutter != 0.0
> -			 ? status_.fixed_shutter
> -			 : exposure_mode_->shutter.back()) *
> +			max_shutter *
>  			(status_.fixed_analogue_gain != 0.0
> -			 ? status_.fixed_analogue_gain
> -			 : exposure_mode_->gain.back());
> +				 ? status_.fixed_analogue_gain
> +				 : exposure_mode_->gain.back());
>  		target_.total_exposure = std::min(target_.total_exposure,
>  						  max_total_exposure);
>  	}
> @@ -671,6 +680,7 @@ void Agc::divideUpExposure()
>  	shutter_time = status_.fixed_shutter != 0.0
>  			       ? status_.fixed_shutter
>  			       : exposure_mode_->shutter[0];
> +	shutter_time = clipShutter(shutter_time);
>  	analogue_gain = status_.fixed_analogue_gain != 0.0
>  				? status_.fixed_analogue_gain
>  				: exposure_mode_->gain[0];
> @@ -678,14 +688,15 @@ void Agc::divideUpExposure()
>  		for (unsigned int stage = 1;
>  		     stage < exposure_mode_->gain.size(); stage++) {
>  			if (status_.fixed_shutter == 0.0) {
> -				if (exposure_mode_->shutter[stage] *
> -					    analogue_gain >=
> +				double stage_shutter =
> +					clipShutter(exposure_mode_->shutter[stage]);
> +				if (stage_shutter * analogue_gain >=
>  				    exposure_value) {
>  					shutter_time =
>  						exposure_value / analogue_gain;
>  					break;
>  				}
> -				shutter_time = exposure_mode_->shutter[stage];
> +				shutter_time = stage_shutter;
>  			}
>  			if (status_.fixed_analogue_gain == 0.0) {
>  				if (exposure_mode_->gain[stage] *
> @@ -740,6 +751,13 @@ void Agc::writeAndFinish(Metadata *image_metadata, bool desaturate)
>  			   << " analogue gain " << filtered_.analogue_gain;
>  }
>  
> +double Agc::clipShutter(double shutter)
> +{
> +	if (max_shutter_)
> +		shutter = std::min(shutter, max_shutter_);
> +	return shutter;
> +}
> +
>  // Register algorithm with the system.
>  static Algorithm *Create(Controller *controller)
>  {
> diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp
> index 05c334e4a1de..0427fb59ec1b 100644
> --- a/src/ipa/raspberrypi/controller/rpi/agc.hpp
> +++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp
> @@ -78,6 +78,7 @@ public:
>  	unsigned int GetConvergenceFrames() const override;
>  	void SetEv(double ev) override;
>  	void SetFlickerPeriod(double flicker_period) override;
> +	void SetMaxShutter(double max_shutter) override; // microseconds
>  	void SetFixedShutter(double fixed_shutter) override; // microseconds
>  	void SetFixedAnalogueGain(double fixed_analogue_gain) override;
>  	void SetMeteringMode(std::string const &metering_mode_name) override;
> @@ -100,6 +101,7 @@ private:
>  	void filterExposure(bool desaturate);
>  	void divideUpExposure();
>  	void writeAndFinish(Metadata *image_metadata, bool desaturate);
> +	double clipShutter(double shutter);
>  	AgcMeteringMode *metering_mode_;
>  	AgcExposureMode *exposure_mode_;
>  	AgcConstraintMode *constraint_mode_;
> @@ -126,6 +128,7 @@ private:
>  	std::string constraint_mode_name_;
>  	double ev_;
>  	double flicker_period_;
> +	double max_shutter_;
>  	double fixed_shutter_;
>  	double fixed_analogue_gain_;
>  };
> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp
> index e4911b734e20..8c0e699184f6 100644
> --- a/src/ipa/raspberrypi/raspberrypi.cpp
> +++ b/src/ipa/raspberrypi/raspberrypi.cpp
> @@ -1006,6 +1006,18 @@ void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuratio
>  	libcameraMetadata_.set(controls::FrameDurations,
>  			       { static_cast<int64_t>(minFrameDuration_),
>  				 static_cast<int64_t>(maxFrameDuration_) });
> +
> +	/*
> +	 * Calculate the maximum exposure time possible for the AGC to use.
> +	 * GetVBlanking() will update maxShutter with the largest exposure
> +	 * value possible.
> +	 */
> +	double maxShutter = std::numeric_limits<double>::max();
> +	helper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_);
> +
> +	RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(
> +		controller_.GetAlgorithm("agc"));
> +	agc->SetMaxShutter(maxShutter);
>  }
>  
>  void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list