<div dir="ltr">Hi all,<div><br></div><div>Gentle ping to have some feedback for this patch.</div><div><br></div><div>All other patches in this series have 2x R-b tags, so once this has another review, I think</div><div>the series can be merged.</div><div><br></div><div>Regards,</div><div>Naush</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 25 May 2021 at 12:42, Naushir Patuck <<a href="mailto:naush@raspberrypi.com">naush@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">Switch the ipa and cam_helper code to use libcamera::utils::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>
Reviewed-by: David Plowman <<a href="mailto:david.plowman@raspberrypi.com" target="_blank">david.plowman@raspberrypi.com</a>><br>
---<br>
src/ipa/raspberrypi/cam_helper.cpp | 20 +++---<br>
src/ipa/raspberrypi/cam_helper.hpp | 10 +--<br>
src/ipa/raspberrypi/controller/camera_mode.h | 6 +-<br>
src/ipa/raspberrypi/raspberrypi.cpp | 64 +++++++++++---------<br>
4 files changed, 55 insertions(+), 45 deletions(-)<br>
<br>
diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp<br>
index 09917f3cc079..7b4331a87a42 100644<br>
--- a/src/ipa/raspberrypi/cam_helper.cpp<br>
+++ b/src/ipa/raspberrypi/cam_helper.cpp<br>
@@ -18,6 +18,7 @@<br>
<br>
using namespace RPiController;<br>
using namespace libcamera;<br>
+using libcamera::utils::Duration;<br>
<br>
namespace libcamera {<br>
LOG_DECLARE_CATEGORY(IPARPI)<br>
@@ -61,20 +62,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(const Duration &exposure) const<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>
<br>
-uint32_t CamHelper::GetVBlanking(double &exposure, double minFrameDuration,<br>
- double maxFrameDuration) const<br>
+uint32_t CamHelper::GetVBlanking(Duration &exposure,<br>
+ const Duration &minFrameDuration,<br>
+ const Duration &maxFrameDuration) const<br>
{<br>
uint32_t frameLengthMin, frameLengthMax, vblank;<br>
uint32_t exposureLines = ExposureLines(exposure);<br>
@@ -85,8 +87,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 +184,7 @@ void CamHelper::parseEmbeddedData(Span<const uint8_t> buffer,<br>
return;<br>
}<br>
<br>
- deviceStatus.shutter_speed = Exposure(exposureLines);<br>
+ deviceStatus.shutter_speed = Exposure(exposureLines).get<std::micro>();<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..07481e4174a7 100644<br>
--- a/src/ipa/raspberrypi/cam_helper.hpp<br>
+++ b/src/ipa/raspberrypi/cam_helper.hpp<br>
@@ -15,6 +15,7 @@<br>
#include "controller/metadata.hpp"<br>
#include "md_parser.hpp"<br>
<br>
+#include "libcamera/internal/utils.h"<br>
#include "libcamera/internal/v4l2_videodevice.h"<br>
<br>
namespace RPiController {<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(const libcamera::utils::Duration &exposure) const;<br>
+ libcamera::utils::Duration Exposure(uint32_t exposure_lines) const;<br>
+ virtual uint32_t GetVBlanking(libcamera::utils::Duration &exposure,<br>
+ const libcamera::utils::Duration &minFrameDuration,<br>
+ const libcamera::utils::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..2aa2335dcf90 100644<br>
--- a/src/ipa/raspberrypi/controller/camera_mode.h<br>
+++ b/src/ipa/raspberrypi/controller/camera_mode.h<br>
@@ -8,6 +8,8 @@<br>
<br>
#include <libcamera/transform.h><br>
<br>
+#include "libcamera/internal/utils.h"<br>
+<br>
// Description of a "camera mode", holding enough information for control<br>
// algorithms to adapt their behaviour to the different modes of the camera,<br>
// including binning, scaling, cropping etc.<br>
@@ -33,8 +35,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>
+ libcamera::utils::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..4e02e94084f7 100644<br>
--- a/src/ipa/raspberrypi/raspberrypi.cpp<br>
+++ b/src/ipa/raspberrypi/raspberrypi.cpp<br>
@@ -55,19 +55,22 @@<br>
<br>
namespace libcamera {<br>
<br>
+using namespace std::literals::chrono_literals;<br>
+using utils::Duration;<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 +114,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>
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 +171,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>
@@ -311,10 +315,10 @@ void IPARPi::setMode(const CameraSensorInfo &sensorInfo)<br>
mode_.noise_factor = sqrt(mode_.bin_x * mode_.bin_y);<br>
<br>
/*<br>
- * Calculate the line length in nanoseconds as the ratio between<br>
- * the line length in pixels and the pixel rate.<br>
+ * Calculate the line length as the ratio between the line length in<br>
+ * 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 +391,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 = DefaultExposureTime.get<std::micro>();<br>
agcStatus.analogue_gain = DefaultAnalogueGain;<br>
applyAGC(&agcStatus, ctrls);<br>
<br>
@@ -862,7 +866,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 +941,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 +1016,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 = helper_->Exposure(exposureLines).get<std::micro>();<br>
deviceStatus.analogue_gain = helper_->Gain(gainCode);<br>
<br>
LOG(IPARPI, Debug) << "Metadata - Exposure : "<br>
@@ -1057,10 +1061,11 @@ 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>
@@ -1076,20 +1081,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>(minFrameDuration_.get<std::micro>()),<br>
+ static_cast<int64_t>(maxFrameDuration_.get<std::micro>()) });<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(maxShutter.get<std::micro>());<br>
}<br>
<br>
void IPARPi::applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls)<br>
@@ -1097,9 +1102,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>