<div dir="ltr"><div dir="ltr">Hi David,</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, 16 Nov 2020 at 16:49, David Plowman <<a href="mailto:david.plowman@raspberrypi.com">david.plowman@raspberrypi.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">When an application has specified fixed exposure time and/or gain they<br>
must be programmed into the sensor immediately, even before the sensor<br>
has been started. For this to happen they must be written into the<br>
image metadata when the SwitchMode method is invoked.<br>
<br>
We also make the default exposure/gain, when nothing has been set,<br>
customisable in the tuning file.<br>
<br>
Signed-off-by: David Plowman <<a href="mailto:david.plowman@raspberrypi.com" target="_blank">david.plowman@raspberrypi.com</a>><br></blockquote><div><br></div><div>Reviewed-by: Naushir Patuck <<a href="mailto:naush@raspberrypi.com">naush@raspberrypi.com</a>></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
---<br>
 src/ipa/raspberrypi/controller/rpi/agc.cpp | 74 +++++++++++++++++-----<br>
 src/ipa/raspberrypi/controller/rpi/agc.hpp |  2 +<br>
 2 files changed, 60 insertions(+), 16 deletions(-)<br>
<br>
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.cpp b/src/ipa/raspberrypi/controller/rpi/agc.cpp<br>
index 6de56def..7c7944e8 100644<br>
--- a/src/ipa/raspberrypi/controller/rpi/agc.cpp<br>
+++ b/src/ipa/raspberrypi/controller/rpi/agc.cpp<br>
@@ -147,6 +147,9 @@ void AgcConfig::Read(boost::property_tree::ptree const &params)<br>
        fast_reduce_threshold =<br>
                params.get<double>("fast_reduce_threshold", 0.4);<br>
        base_ev = params.get<double>("base_ev", 1.0);<br>
+       // Start with quite a low value as ramping up is easier than ramping down.<br>
+       default_exposure_time = params.get<double>("default_exposure_time", 1000);<br>
+       default_analogue_gain = params.get<double>("default_analogue_gain", 1.0);<br>
 }<br>
<br>
 Agc::Agc(Controller *controller)<br>
@@ -222,14 +225,42 @@ void Agc::SetConstraintMode(std::string const &constraint_mode_name)<br>
 void Agc::SwitchMode([[maybe_unused]] CameraMode const &camera_mode,<br>
                     Metadata *metadata)<br>
 {<br>
-       // On a mode switch, it's possible the exposure profile could change,<br>
-       // so we run through the dividing up of exposure/gain again and<br>
-       // write the results into the metadata we've been given.<br>
-       if (status_.total_exposure_value) {<br>
-               housekeepConfig();<br>
+       housekeepConfig();<br>
+<br>
+       if (fixed_shutter_ != 0.0 && fixed_analogue_gain_ != 0.0) {<br>
+               // We're going to reset the algorithm here with these fixed values.<br>
+<br>
+               fetchAwbStatus(metadata);<br>
+               double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 });<br>
+               assert(min_colour_gain != 0.0);<br>
+<br>
+               // This is the equivalent of computeTargetExposure and applyDigitalGain.<br>
+               target_.total_exposure_no_dg = fixed_shutter_ * fixed_analogue_gain_;<br>
+               target_.total_exposure = target_.total_exposure_no_dg / min_colour_gain;<br>
+<br>
+               // Equivalent of filterExposure. This resets any "history".<br>
+               filtered_ = target_;<br>
+<br>
+               // Equivalent of divideUpExposure.<br>
+               filtered_.shutter = fixed_shutter_;<br>
+               filtered_.analogue_gain = fixed_analogue_gain_;<br>
+       } else if (status_.total_exposure_value) {<br>
+               // On a mode switch, it's possible the exposure profile could change,<br>
+               // or a fixed exposure/gain might be set so we divide up the exposure/<br>
+               // gain again, but we don't change any target values.<br>
                divideUpExposure();<br>
-               writeAndFinish(metadata, false);<br>
+       } else {<br>
+               // We come through here on startup, when at least one of the shutter<br>
+               // or gain has not been fixed. We must still write those values out so<br>
+               // that they will be applied immediately. We supply some arbitrary defaults<br>
+               // for any that weren't set.<br>
+<br>
+               // Equivalent of divideUpExposure.<br>
+               filtered_.shutter = fixed_shutter_ ? fixed_shutter_ : config_.default_exposure_time;<br>
+               filtered_.analogue_gain = fixed_analogue_gain_ ? fixed_analogue_gain_ : config_.default_analogue_gain;<br>
        }<br>
+<br>
+       writeAndFinish(metadata, false);<br>
 }<br>
<br>
 void Agc::Prepare(Metadata *image_metadata)<br>
@@ -475,20 +506,31 @@ void Agc::computeGain(bcm2835_isp_stats *statistics, Metadata *image_metadata,<br>
<br>
 void Agc::computeTargetExposure(double gain)<br>
 {<br>
-       // The statistics reflect the image without digital gain, so the final<br>
-       // total exposure we're aiming for is:<br>
-       target_.total_exposure = current_.total_exposure_no_dg * gain;<br>
-       // The final target exposure is also limited to what the exposure<br>
-       // mode allows.<br>
-       double max_total_exposure =<br>
-               (status_.fixed_shutter != 0.0<br>
+       if (status_.fixed_shutter != 0.0 && status_.fixed_analogue_gain != 0.0) {<br>
+               // When ag and shutter are both fixed, we need to drive the<br>
+               // total exposure so that we end up with a digital gain of at least<br>
+               // 1/min_colour_gain. Otherwise we'd desaturate channels causing<br>
+               // white to go cyan or magenta.<br>
+               double min_colour_gain = std::min({ awb_.gain_r, awb_.gain_g, awb_.gain_b, 1.0 });<br>
+               assert(min_colour_gain != 0.0);<br>
+               target_.total_exposure =<br>
+                       status_.fixed_shutter * status_.fixed_analogue_gain / min_colour_gain;<br>
+       } else {<br>
+               // The statistics reflect the image without digital gain, so the final<br>
+               // total exposure we're aiming for is:<br>
+               target_.total_exposure = current_.total_exposure_no_dg * gain;<br>
+               // The final target exposure is also limited to what the exposure<br>
+               // mode allows.<br>
+               double max_total_exposure =<br>
+                       (status_.fixed_shutter != 0.0<br>
                         ? status_.fixed_shutter<br>
                         : exposure_mode_->shutter.back()) *<br>
-               (status_.fixed_analogue_gain != 0.0<br>
+                       (status_.fixed_analogue_gain != 0.0<br>
                         ? status_.fixed_analogue_gain<br>
                         : exposure_mode_->gain.back());<br>
-       target_.total_exposure = std::min(target_.total_exposure,<br>
-                                         max_total_exposure);<br>
+               target_.total_exposure = std::min(target_.total_exposure,<br>
+                                                 max_total_exposure);<br>
+       }<br>
        LOG(RPiAgc, Debug) << "Target total_exposure " << target_.total_exposure;<br>
 }<br>
<br>
diff --git a/src/ipa/raspberrypi/controller/rpi/agc.hpp b/src/ipa/raspberrypi/controller/rpi/agc.hpp<br>
index e7ac480f..859a9650 100644<br>
--- a/src/ipa/raspberrypi/controller/rpi/agc.hpp<br>
+++ b/src/ipa/raspberrypi/controller/rpi/agc.hpp<br>
@@ -60,6 +60,8 @@ struct AgcConfig {<br>
        std::string default_exposure_mode;<br>
        std::string default_constraint_mode;<br>
        double base_ev;<br>
+       double default_exposure_time;<br>
+       double default_analogue_gain;<br>
 };<br>
<br>
 class Agc : public AgcAlgorithm<br>
-- <br>
2.20.1<br>
<br>
_______________________________________________<br>
libcamera-devel mailing list<br>
<a href="mailto:libcamera-devel@lists.libcamera.org" target="_blank">libcamera-devel@lists.libcamera.org</a><br>
<a href="https://lists.libcamera.org/listinfo/libcamera-devel" rel="noreferrer" target="_blank">https://lists.libcamera.org/listinfo/libcamera-devel</a><br>
</blockquote></div></div>