<div dir="ltr"><div dir="ltr">Hi David,<div><br></div><div>Thank you for your review feedback.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 19 May 2021 at 15:09, David Plowman <<a href="mailto:david.plowman@raspberrypi.com" target="_blank">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">Hi Naush<br>
<br>
Thanks for this patch.<br>
<br>
On Tue, 18 May 2021 at 11:09, Naushir Patuck <<a href="mailto:naush@raspberrypi.com" target="_blank">naush@raspberrypi.com</a>> wrote:<br>
><br>
> Switch the ipa and cam_helper code to use RPiController::Duration for<br>
> all time based variables. This improves code readability and avoids<br>
> possible errors when converting between time bases.<br>
><br>
> Signed-off-by: Naushir Patuck <<a href="mailto:naush@raspberrypi.com" target="_blank">naush@raspberrypi.com</a>><br>
> ---<br>
> src/ipa/raspberrypi/cam_helper.cpp | 19 +++---<br>
> src/ipa/raspberrypi/cam_helper.hpp | 10 +--<br>
> src/ipa/raspberrypi/controller/camera_mode.h | 5 +-<br>
> src/ipa/raspberrypi/raspberrypi.cpp | 67 +++++++++++---------<br>
> 4 files changed, 56 insertions(+), 45 deletions(-)<br>
><br>
> diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp<br>
> index 09917f3cc079..e2b6c8eb8e03 100644<br>
> --- a/src/ipa/raspberrypi/cam_helper.cpp<br>
> +++ b/src/ipa/raspberrypi/cam_helper.cpp<br>
> @@ -61,20 +61,21 @@ void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats,<br>
> {<br>
> }<br>
><br>
> -uint32_t CamHelper::ExposureLines(double exposure_us) const<br>
> +uint32_t CamHelper::ExposureLines(Duration exposure) const<br>
<br>
I take it we're happy to pass these by value. I assume they're not<br>
big, just a double plus some kind of time unit?<br></blockquote><div><br></div><div>There is minimal overhead, but perhaps I should change to a const</div><div>reference to be consistent.</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>
> {<br>
> assert(initialized_);<br>
> - return exposure_us * 1000.0 / mode_.line_length;<br>
> + return exposure / mode_.line_length;<br>
> }<br>
><br>
> -double CamHelper::Exposure(uint32_t exposure_lines) const<br>
> +Duration CamHelper::Exposure(uint32_t exposure_lines) const<br>
> {<br>
> assert(initialized_);<br>
> - return exposure_lines * mode_.line_length / 1000.0;<br>
> + return exposure_lines * mode_.line_length;<br>
<br>
Yes, I do prefer this!<br>
<br>
> }<br>
><br>
> -uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,<br>
> - double maxFrameDuration) const<br>
> +uint32_t CamHelper::GetVBlanking(Duration &exposure,<br>
> + Duration minFrameDuration,<br>
> + Duration maxFrameDuration) const<br>
> {<br>
> uint32_t frameLengthMin, frameLengthMax, vblank;<br>
> uint32_t exposureLines = ExposureLines(exposure);<br>
> @@ -85,8 +86,8 @@ uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,<br>
> * minFrameDuration and maxFrameDuration are clamped by the caller<br>
> * based on the limits for the active sensor mode.<br>
> */<br>
> - frameLengthMin = 1e3 * minFrameDuration / mode_.line_length;<br>
> - frameLengthMax = 1e3 * maxFrameDuration / mode_.line_length;<br>
> + frameLengthMin = minFrameDuration / mode_.line_length;<br>
> + frameLengthMax = maxFrameDuration / mode_.line_length;<br>
><br>
> /*<br>
> * Limit the exposure to the maximum frame duration requested, and<br>
> @@ -182,7 +183,7 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,<br>
> return;<br>
> }<br>
><br>
> - deviceStatus.shutter_speed = Exposure(exposureLines);<br>
> + deviceStatus.shutter_speed = DurationValue<std::micro>(Exposure(exposureLines));<br>
<br>
Ah yes, so this is one of those "in between" changes which will get<br>
better again in a later patch...<br></blockquote><div><br></div><div>Yes, this will be reverted in the later patch.</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>
> deviceStatus.analogue_gain = Gain(gainCode);<br>
><br>
> LOG(IPARPI, Debug) << "Metadata updated - Exposure : "<br>
> diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp<br>
> index a52f3f0b583c..a91afaa59909 100644<br>
> --- a/src/ipa/raspberrypi/cam_helper.hpp<br>
> +++ b/src/ipa/raspberrypi/cam_helper.hpp<br>
> @@ -13,6 +13,7 @@<br>
> #include "camera_mode.h"<br>
> #include "controller/controller.hpp"<br>
> #include "controller/metadata.hpp"<br>
> +#include "duration.hpp"<br>
> #include "md_parser.hpp"<br>
><br>
> #include "libcamera/internal/v4l2_videodevice.h"<br>
> @@ -72,10 +73,11 @@ public:<br>
> virtual void Prepare(libcamera::Span<const uint8_t> buffer,<br>
> Metadata &metadata);<br>
> virtual void Process(StatisticsPtr &stats, Metadata &metadata);<br>
> - uint32_t ExposureLines(double exposure_us) const;<br>
> - double Exposure(uint32_t exposure_lines) const; // in us<br>
> - virtual uint32_t GetVBlanking(double &exposure_us, double minFrameDuration,<br>
> - double maxFrameDuration) const;<br>
> + uint32_t ExposureLines(Duration exposure) const;<br>
> + Duration Exposure(uint32_t exposure_lines) const;<br>
> + virtual uint32_t GetVBlanking(Duration &exposure,<br>
> + Duration minFrameDuration,<br>
> + Duration maxFrameDuration) const;<br>
> virtual uint32_t GainCode(double gain) const = 0;<br>
> virtual double Gain(uint32_t gain_code) const = 0;<br>
> virtual void GetDelays(int &exposure_delay, int &gain_delay,<br>
> diff --git a/src/ipa/raspberrypi/controller/camera_mode.h b/src/ipa/raspberrypi/controller/camera_mode.h<br>
> index 256438c931d9..ab7cf2912a06 100644<br>
> --- a/src/ipa/raspberrypi/controller/camera_mode.h<br>
> +++ b/src/ipa/raspberrypi/controller/camera_mode.h<br>
> @@ -6,6 +6,7 @@<br>
> */<br>
> #pragma once<br>
><br>
> +#include "duration.hpp"<br>
> #include <libcamera/transform.h><br>
><br>
> // Description of a "camera mode", holding enough information for control<br>
> @@ -33,8 +34,8 @@ struct CameraMode {<br>
> double scale_x, scale_y;<br>
> // scaling of the noise compared to the native sensor mode<br>
> double noise_factor;<br>
> - // line time in nanoseconds<br>
> - double line_length;<br>
> + // line time<br>
> + RPiController::Duration line_length;<br>
> // any camera transform *not* reflected already in the camera tuning<br>
> libcamera::Transform transform;<br>
> // minimum and maximum fame lengths in units of lines<br>
> diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp<br>
> index 52d91db282ea..994fb7e057a9 100644<br>
> --- a/src/ipa/raspberrypi/raspberrypi.cpp<br>
> +++ b/src/ipa/raspberrypi/raspberrypi.cpp<br>
> @@ -45,6 +45,7 @@<br>
> #include "denoise_algorithm.hpp"<br>
> #include "denoise_status.h"<br>
> #include "dpc_status.h"<br>
> +#include "duration.hpp"<br>
> #include "focus_status.h"<br>
> #include "geq_status.h"<br>
> #include "lux_status.h"<br>
> @@ -55,19 +56,24 @@<br>
><br>
> namespace libcamera {<br>
><br>
> +using namespace std::literals::chrono_literals;<br>
> +using RPiController::Duration;<br>
> +using RPiController::DurationValue;<br>
> +using RPiController::operator<<;<br>
> +<br>
> /* Configure the sensor with these values initially. */<br>
> constexpr double DefaultAnalogueGain = 1.0;<br>
> -constexpr unsigned int DefaultExposureTime = 20000;<br>
> -constexpr double defaultMinFrameDuration = 1e6 / 30.0;<br>
> -constexpr double defaultMaxFrameDuration = 1e6 / 0.01;<br>
> +constexpr Duration DefaultExposureTime = 20.0ms;<br>
> +constexpr Duration defaultMinFrameDuration = 1.0s / 30.0;<br>
> +constexpr Duration defaultMaxFrameDuration = 100.0s;<br>
><br>
> /*<br>
> - * Determine the minimum allowable inter-frame duration (in us) to run the<br>
> - * controller algorithms. If the pipeline handler provider frames at a rate<br>
> - * higher than this, we rate-limit the controller Prepare() and Process() calls<br>
> - * to lower than or equal to this rate.<br>
> + * Determine the minimum allowable inter-frame duration to run the controller<br>
> + * algorithms. If the pipeline handler provider frames at a rate higher than this,<br>
> + * we rate-limit the controller Prepare() and Process() calls to lower than or<br>
> + * equal to this rate.<br>
> */<br>
> -constexpr double controllerMinFrameDuration = 1e6 / 60.0;<br>
> +constexpr Duration controllerMinFrameDuration = 1.0s / 60.0;<br>
><br>
> LOG_DEFINE_CATEGORY(IPARPI)<br>
><br>
> @@ -111,7 +117,8 @@ private:<br>
> void reportMetadata();<br>
> void fillDeviceStatus(const ControlList &sensorControls);<br>
> void processStats(unsigned int bufferId);<br>
> - void applyFrameDurations(double minFrameDuration, double maxFrameDuration);<br>
> + void applyFrameDurations(const Duration &minFrameDuration,<br>
> + const Duration &maxFrameDuration);<br>
<br>
Some pass-by-reference, I notice. Do we want to be consistent? Are we<br>
bothered (I'm not...)?<br></blockquote><div><br></div><div>I will change to using const references in the other places to be consistent.</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>
> void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);<br>
> void applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls);<br>
> void applyDG(const struct AgcStatus *dgStatus, ControlList &ctrls);<br>
> @@ -167,9 +174,9 @@ private:<br>
> /* Distinguish the first camera start from others. */<br>
> bool firstStart_;<br>
><br>
> - /* Frame duration (1/fps) limits, given in microseconds. */<br>
> - double minFrameDuration_;<br>
> - double maxFrameDuration_;<br>
> + /* Frame duration (1/fps) limits. */<br>
> + Duration minFrameDuration_;<br>
> + Duration maxFrameDuration_;<br>
> };<br>
><br>
> int IPARPi::init(const IPASettings &settings, ipa::RPi::SensorConfig *sensorConfig)<br>
> @@ -314,7 +321,7 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)<br>
> * Calculate the line length in nanoseconds as the ratio between<br>
<br>
Elsewhere you've tended to remove the mention of units, so does it<br>
want the same here?<br></blockquote><div><br></div><div>Oops, that one I missed.</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>
> * the line length in pixels and the pixel rate.<br>
> */<br>
> - mode_.line_length = 1e9 * sensorInfo.lineLength / sensorInfo.pixelRate;<br>
> + mode_.line_length = sensorInfo.lineLength * (1.0s / sensorInfo.pixelRate);<br>
><br>
> /*<br>
> * Set the frame length limits for the mode to ensure exposure and<br>
> @@ -387,7 +394,7 @@ int IPARPi::configure(const CameraSensorInfo &sensorInfo,<br>
> /* Supply initial values for gain and exposure. */<br>
> ControlList ctrls(sensorCtrls_);<br>
> AgcStatus agcStatus;<br>
> - agcStatus.shutter_time = DefaultExposureTime;<br>
> + agcStatus.shutter_time = DurationValue<std::micro>(DefaultExposureTime);<br>
> agcStatus.analogue_gain = DefaultAnalogueGain;<br>
> applyAGC(&agcStatus, ctrls);<br>
><br>
> @@ -862,7 +869,7 @@ void IPARPi::queueRequest(const ControlList &controls)<br>
><br>
> case controls::FRAME_DURATIONS: {<br>
> auto frameDurations = ctrl.second.get<Span<const int64_t>>();<br>
> - applyFrameDurations(frameDurations[0], frameDurations[1]);<br>
> + applyFrameDurations(frameDurations[0] * 1.0us, frameDurations[1] * 1.0us);<br>
> break;<br>
> }<br>
><br>
> @@ -937,9 +944,9 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)<br>
> returnEmbeddedBuffer(data.embeddedBufferId);<br>
><br>
> /* Allow a 10% margin on the comparison below. */<br>
> - constexpr double eps = controllerMinFrameDuration * 1e3 * 0.1;<br>
> + Duration delta = (frameTimestamp - lastRunTimestamp_) * 1.0ns;<br>
> if (lastRunTimestamp_ && frameCount_ > dropFrameCount_ &&<br>
> - frameTimestamp - lastRunTimestamp_ + eps < controllerMinFrameDuration * 1e3) {<br>
> + delta < controllerMinFrameDuration * 0.9) {<br>
> /*<br>
> * Ensure we merge the previous frame's metadata with the current<br>
> * frame. This will not overwrite exposure/gain values for the<br>
> @@ -1012,7 +1019,7 @@ void IPARPi::fillDeviceStatus(const ControlList &sensorControls)<br>
> int32_t exposureLines = sensorControls.get(V4L2_CID_EXPOSURE).get<int32_t>();<br>
> int32_t gainCode = sensorControls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();<br>
><br>
> - deviceStatus.shutter_speed = helper_->Exposure(exposureLines);<br>
> + deviceStatus.shutter_speed = DurationValue<std::micro>(helper_->Exposure(exposureLines));<br>
> deviceStatus.analogue_gain = helper_->Gain(gainCode);<br>
><br>
> LOG(IPARPI, Debug) << "Metadata - Exposure : "<br>
> @@ -1057,17 +1064,18 @@ void IPARPi::applyAWB(const struct AwbStatus *awbStatus, ControlList &ctrls)<br>
> static_cast<int32_t>(awbStatus->gain_b * 1000));<br>
> }<br>
><br>
> -void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuration)<br>
> +void IPARPi::applyFrameDurations(const Duration &minFrameDuration,<br>
> + const Duration &maxFrameDuration)<br>
> {<br>
> - const double minSensorFrameDuration = 1e-3 * mode_.min_frame_length * mode_.line_length;<br>
> - const double maxSensorFrameDuration = 1e-3 * mode_.max_frame_length * mode_.line_length;<br>
> + const Duration minSensorFrameDuration = mode_.min_frame_length * mode_.line_length;<br>
> + const Duration maxSensorFrameDuration = mode_.max_frame_length * mode_.line_length;<br>
><br>
> /*<br>
> * This will only be applied once AGC recalculations occur.<br>
> * The values may be clamped based on the sensor mode capabilities as well.<br>
> */<br>
> - minFrameDuration_ = minFrameDuration ? minFrameDuration : defaultMaxFrameDuration;<br>
> - maxFrameDuration_ = maxFrameDuration ? maxFrameDuration : defaultMinFrameDuration;<br>
> + minFrameDuration_ = (minFrameDuration > 0.0s) ? minFrameDuration : defaultMaxFrameDuration;<br>
> + maxFrameDuration_ = (maxFrameDuration > 0.0s) ? maxFrameDuration : defaultMinFrameDuration;<br>
> minFrameDuration_ = std::clamp(minFrameDuration_,<br>
> minSensorFrameDuration, maxSensorFrameDuration);<br>
> maxFrameDuration_ = std::clamp(maxFrameDuration_,<br>
> @@ -1076,20 +1084,20 @@ void IPARPi::applyFrameDurations(double minFrameDuration, double maxFrameDuratio<br>
><br>
> /* Return the validated limits via metadata. */<br>
> libcameraMetadata_.set(controls::FrameDurations,<br>
> - { static_cast<int64_t>(minFrameDuration_),<br>
> - static_cast<int64_t>(maxFrameDuration_) });<br>
> + { static_cast<int64_t>(DurationValue<std::micro>(minFrameDuration_)),<br>
> + static_cast<int64_t>(DurationValue<std::micro>(minFrameDuration_)) });<br>
<br>
And this will look nicer again once the whole of libcamera adopts<br>
std::chrono! :)<br></blockquote><div><br></div><div>Yes, but that comes later :-)</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>
So no significant comments really from me, thus:<br>
<br>
Reviewed-by: David Plowman <<a href="mailto:david.plowman@raspberrypi.com" target="_blank">david.plowman@raspberrypi.com</a>><br>
<br>
Thanks<br>
David<br>
<br>
><br>
> /*<br>
> * Calculate the maximum exposure time possible for the AGC to use.<br>
> * GetVBlanking() will update maxShutter with the largest exposure<br>
> * value possible.<br>
> */<br>
> - double maxShutter = std::numeric_limits<double>::max();<br>
> + Duration maxShutter = Duration::max();<br>
> helper_->GetVBlanking(maxShutter, minFrameDuration_, maxFrameDuration_);<br>
><br>
> RPiController::AgcAlgorithm *agc = dynamic_cast<RPiController::AgcAlgorithm *>(<br>
> controller_.GetAlgorithm("agc"));<br>
> - agc->SetMaxShutter(maxShutter);<br>
> + agc->SetMaxShutter(DurationValue<std::micro>(maxShutter));<br>
> }<br>
><br>
> void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)<br>
> @@ -1097,9 +1105,8 @@ void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)<br>
> int32_t gainCode = helper_->GainCode(agcStatus->analogue_gain);<br>
><br>
> /* GetVBlanking might clip exposure time to the fps limits. */<br>
> - double exposure = agcStatus->shutter_time;<br>
> - int32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_,<br>
> - maxFrameDuration_);<br>
> + Duration exposure = agcStatus->shutter_time * 1.0us;<br>
> + int32_t vblanking = helper_->GetVBlanking(exposure, minFrameDuration_, maxFrameDuration_);<br>
> int32_t exposureLines = helper_->ExposureLines(exposure);<br>
><br>
> LOG(IPARPI, Debug) << "Applying AGC Exposure: " << exposure<br>
> --<br>
> 2.25.1<br>
><br>
</blockquote></div></div>