<div dir="ltr"><div dir="ltr">Hi David,<div><br></div><div>Thank you for your work.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 10 Mar 2021 at 17:23, 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">CamHelpers get virtual Prepare() and Process() methods, running just<br>
before and just after the ISP, just like Raspberry Pi Algorithms.<br>
<br>
The Prepare() method is able to parse the register dumps in embedded<br>
data buffers, and can be specialised to perform custom processing when<br>
necessary.<br>
<br>
The IPA itself no longer performs this register parsing, it just has<br>
to call the new Prepare() and Process() methods.<br>
---<br>
 src/ipa/raspberrypi/cam_helper.cpp  | 49 ++++++++++++++++<br>
 src/ipa/raspberrypi/cam_helper.hpp  | 14 ++++-<br>
 src/ipa/raspberrypi/raspberrypi.cpp | 88 ++++++++---------------------<br>
 3 files changed, 84 insertions(+), 67 deletions(-)<br>
<br>
diff --git a/src/ipa/raspberrypi/cam_helper.cpp b/src/ipa/raspberrypi/cam_helper.cpp<br>
index 0ae0baa0..fc69f4cb 100644<br>
--- a/src/ipa/raspberrypi/cam_helper.cpp<br>
+++ b/src/ipa/raspberrypi/cam_helper.cpp<br>
@@ -17,6 +17,11 @@<br>
 #include "md_parser.hpp"<br>
<br>
 using namespace RPiController;<br>
+using namespace libcamera;<br>
+<br>
+namespace libcamera {<br>
+LOG_DECLARE_CATEGORY(IPARPI)<br>
+}<br></blockquote><div><br></div><div>Is this namespace enclosure needed for some reason?</div><div>Seems to compile well enough without it.  I wonder if we should add a</div><div>category for cam_helper based logging?</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>
 static std::map<std::string, CamHelperCreateFunc> cam_helpers;<br>
<br>
@@ -45,6 +50,17 @@ CamHelper::~CamHelper()<br>
        delete parser_;<br>
 }<br>
<br>
+void CamHelper::Prepare(const Span<uint8_t> &buffer,<br>
+                       const ControlList &controls, Metadata &metadata)<br>
+{<br>
+       parseRegisters(buffer, controls, metadata);<br>
+}<br>
+<br>
+void CamHelper::Process([[maybe_unused]] StatisticsPtr &stats,<br>
+                       [[maybe_unused]] Metadata &metadata)<br>
+{<br>
+}<br>
+<br>
 uint32_t CamHelper::ExposureLines(double exposure_us) const<br>
 {<br>
        assert(initialized_);<br>
@@ -139,6 +155,39 @@ unsigned int CamHelper::MistrustFramesModeSwitch() const<br>
        return 0;<br>
 }<br>
<br>
+void CamHelper::parseRegisters(const Span<uint8_t> &buffer,<br>
+                              const ControlList &controls, Metadata &metadata)<br>
+{<br></blockquote><div><br></div><div>Bit of a nit-pick (sorry) , but could you consider a few renames:</div><div><br></div><div>s/parseRegisters/parseEmbeddedData/</div><div>s/controls/sensorControls/</div><div>s/metadata/controllerMetadata/</div><div> </div><div>Took me a bit of inspection to remind myself what those variables represented.</div><div>Not too fussed either way though.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+       struct DeviceStatus deviceStatus = {};<br>
+       bool success = false;<br>
+       uint32_t exposureLines, gainCode;<br>
+<br>
+       if (buffer.size()) {<br>
+               parser_->SetBufferSize(buffer.size());<br>
+               success = parser_->Parse(buffer.data()) == MdParser::Status::OK &&<br>
+                         parser_->GetExposureLines(exposureLines) == MdParser::Status::OK &&<br>
+                         parser_->GetGainCode(gainCode) == MdParser::Status::OK;<br>
+<br>
+               if (!success)<br>
+                       LOG(IPARPI, Error) << "Embedded buffer parsing failed";<br>
+       }<br>
+<br>
+       if (!success) {<br>
+               exposureLines = controls.get(V4L2_CID_EXPOSURE).get<int32_t>();<br>
+               gainCode = controls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();<br>
+       }<br>
+<br>
+       deviceStatus.shutter_speed = Exposure(exposureLines);<br>
+       deviceStatus.analogue_gain = Gain(gainCode);<br>
+<br>
+       LOG(IPARPI, Debug) << "Metadata - Exposure : "<br>
+                          << deviceStatus.shutter_speed<br>
+                          << " Gain : "<br>
+                          << deviceStatus.analogue_gain;<br>
+<br>
+       metadata.Set("device.status", deviceStatus);<br>
+}<br>
+<br>
 RegisterCamHelper::RegisterCamHelper(char const *cam_name,<br>
                                     CamHelperCreateFunc create_func)<br>
 {<br>
diff --git a/src/ipa/raspberrypi/cam_helper.hpp b/src/ipa/raspberrypi/cam_helper.hpp<br>
index 1b2d6eec..ce5b82d2 100644<br>
--- a/src/ipa/raspberrypi/cam_helper.hpp<br>
+++ b/src/ipa/raspberrypi/cam_helper.hpp<br>
@@ -8,8 +8,13 @@<br>
<br>
 #include <string><br>
<br>
+#include <libcamera/controls.h><br>
+#include <libcamera/span.h><br>
+<br>
 #include "camera_mode.h"<br>
+#include "controller/controller.hpp"<br>
 #include "md_parser.hpp"<br>
+#include "controller/metadata.hpp"<br></blockquote><div><br></div><div>This will need to be ordered alphabetically.</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>
 #include "libcamera/internal/v4l2_videodevice.h"<br>
<br>
@@ -65,7 +70,10 @@ public:<br>
        CamHelper(MdParser *parser, unsigned int frameIntegrationDiff);<br>
        virtual ~CamHelper();<br>
        void SetCameraMode(const CameraMode &mode);<br>
-       MdParser &Parser() const { return *parser_; }<br>
+       virtual void Prepare(const libcamera::Span<uint8_t> &buffer,<br>
+                            const libcamera::ControlList &controls,<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>
@@ -81,6 +89,10 @@ public:<br>
        virtual unsigned int MistrustFramesModeSwitch() const;<br>
<br>
 protected:<br>
+       void parseRegisters(const libcamera::Span<uint8_t> &buffer,<br>
+                           const libcamera::ControlList &controls,<br>
+                           Metadata &metadata);<br>
+<br>
        MdParser *parser_;<br>
        CameraMode mode_;<br>
<br>
diff --git a/src/ipa/raspberrypi/raspberrypi.cpp b/src/ipa/raspberrypi/raspberrypi.cpp<br>
index 7904225a..d699540a 100644<br>
--- a/src/ipa/raspberrypi/raspberrypi.cpp<br>
+++ b/src/ipa/raspberrypi/raspberrypi.cpp<br>
@@ -103,9 +103,6 @@ private:<br>
        void returnEmbeddedBuffer(unsigned int bufferId);<br>
        void prepareISP(const ipa::RPi::ISPConfig &data);<br>
        void reportMetadata();<br>
-       bool parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus);<br>
-       void fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,<br>
-                             struct DeviceStatus &deviceStatus);<br>
        void processStats(unsigned int bufferId);<br>
        void applyFrameDurations(double minFrameDuration, double maxFrameDuration);<br>
        void applyAGC(const struct AgcStatus *agcStatus, ControlList &ctrls);<br>
@@ -913,35 +910,37 @@ void IPARPi::returnEmbeddedBuffer(unsigned int bufferId)<br>
<br>
 void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)<br>
 {<br>
-       struct DeviceStatus deviceStatus = {};<br>
-       bool success = false;<br>
+       Span<uint8_t> embeddedBuffer;<br>
+       bool returnEmbedded = false;<br>
+<br>
+       rpiMetadata_.Clear();<br>
<br>
        if (data.embeddedBufferPresent) {<br>
                /*<br>
                 * Pipeline handler has supplied us with an embedded data buffer,<br>
-                * so parse it and extract the exposure and gain.<br>
+                * we must pass it to the CamHelper for parsing.<br>
                 */<br>
-               success = parseEmbeddedData(data.embeddedBufferId, deviceStatus);<br>
-<br>
-               /* Done with embedded data now, return to pipeline handler asap. */<br>
-               returnEmbeddedBuffer(data.embeddedBufferId);<br>
+               auto it = buffers_.find(data.embeddedBufferId);<br>
+               if (it == buffers_.end())<br>
+                       LOG(IPARPI, Error) << "Could not find embedded buffer!";<br></blockquote><div><br></div><div>This really should never happen, perhaps an assert in its place?</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">
+               else {<br>
+                       embeddedBuffer = it->second.maps()[0];<br>
+                       returnEmbedded = true;<br>
+               }<br>
        }<br>
<br>
-       if (!success) {<br>
-               /*<br>
-                * Pipeline handler has not supplied an embedded data buffer,<br>
-                * or embedded data buffer parsing has failed for some reason,<br>
-                * so pull the exposure and gain values from the control list.<br>
-                */<br>
-               int32_t exposureLines = data.controls.get(V4L2_CID_EXPOSURE).get<int32_t>();<br>
-               int32_t gainCode = data.controls.get(V4L2_CID_ANALOGUE_GAIN).get<int32_t>();<br>
-               fillDeviceStatus(exposureLines, gainCode, deviceStatus);<br>
-       }<br>
+       /*<br>
+        * This will add the DeviceStatus to the metadata, and depending on the<br>
+        * sensor, may do additional custom processing.<br>
+        */<br>
+       helper_->Prepare(embeddedBuffer, data.controls, rpiMetadata_);<br>
+<br>
+       /* Done with embedded data now, return to pipeline handler asap. */<br>
+       if (returnEmbedded)<br>
+               returnEmbeddedBuffer(data.embeddedBufferId);<br></blockquote><div><br></div><div>I think this should happen unconditionally - but as before, returnEmbedded should never</div><div>be false.   If the earlier code was changed to an assert, you could remove returnEmbedded.</div><div><br></div><div>Regards,</div><div>Naush</div><div><br></div><div></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">
        ControlList ctrls(ispCtrls_);<br>
<br>
-       rpiMetadata_.Clear();<br>
-       rpiMetadata_.Set("device.status", deviceStatus);<br>
        controller_.Prepare(&rpiMetadata_);<br>
<br>
        /* Lock the metadata buffer to avoid constant locks/unlocks. */<br>
@@ -991,50 +990,6 @@ void IPARPi::prepareISP(const ipa::RPi::ISPConfig &data)<br>
                setIspControls.emit(ctrls);<br>
 }<br>
<br>
-bool IPARPi::parseEmbeddedData(unsigned int bufferId, struct DeviceStatus &deviceStatus)<br>
-{<br>
-       auto it = buffers_.find(bufferId);<br>
-       if (it == buffers_.end()) {<br>
-               LOG(IPARPI, Error) << "Could not find embedded buffer!";<br>
-               return false;<br>
-       }<br>
-<br>
-       Span<uint8_t> mem = it->second.maps()[0];<br>
-       helper_->Parser().SetBufferSize(mem.size());<br>
-       RPiController::MdParser::Status status = helper_->Parser().Parse(mem.data());<br>
-       if (status != RPiController::MdParser::Status::OK) {<br>
-               LOG(IPARPI, Error) << "Embedded Buffer parsing failed, error " << status;<br>
-               return false;<br>
-       } else {<br>
-               uint32_t exposureLines, gainCode;<br>
-               if (helper_->Parser().GetExposureLines(exposureLines) != RPiController::MdParser::Status::OK) {<br>
-                       LOG(IPARPI, Error) << "Exposure time failed";<br>
-                       return false;<br>
-               }<br>
-<br>
-               if (helper_->Parser().GetGainCode(gainCode) != RPiController::MdParser::Status::OK) {<br>
-                       LOG(IPARPI, Error) << "Gain failed";<br>
-                       return false;<br>
-               }<br>
-<br>
-               fillDeviceStatus(exposureLines, gainCode, deviceStatus);<br>
-       }<br>
-<br>
-       return true;<br>
-}<br>
-<br>
-void IPARPi::fillDeviceStatus(uint32_t exposureLines, uint32_t gainCode,<br>
-                             struct DeviceStatus &deviceStatus)<br>
-{<br>
-       deviceStatus.shutter_speed = helper_->Exposure(exposureLines);<br>
-       deviceStatus.analogue_gain = helper_->Gain(gainCode);<br>
-<br>
-       LOG(IPARPI, Debug) << "Metadata - Exposure : "<br>
-                          << deviceStatus.shutter_speed<br>
-                          << " Gain : "<br>
-                          << deviceStatus.analogue_gain;<br>
-}<br>
-<br>
 void IPARPi::processStats(unsigned int bufferId)<br>
 {<br>
        auto it = buffers_.find(bufferId);<br>
@@ -1046,6 +1001,7 @@ void IPARPi::processStats(unsigned int bufferId)<br>
        Span<uint8_t> mem = it->second.maps()[0];<br>
        bcm2835_isp_stats *stats = reinterpret_cast<bcm2835_isp_stats *>(mem.data());<br>
        RPiController::StatisticsPtr statistics = std::make_shared<bcm2835_isp_stats>(*stats);<br>
+       helper_->Process(statistics, rpiMetadata_);<br>
        controller_.Process(statistics, &rpiMetadata_);<br>
<br>
        struct AgcStatus agcStatus;<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>