<div dir="ltr"><div dir="ltr">Hi Jean-Michel,<div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, 7 Jun 2021 at 13:35, Jean-Michel Hautbois <<a href="mailto:jeanmichel.hautbois@ideasonboard.com">jeanmichel.hautbois@ideasonboard.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">Setting analogue gain for a specific sensor is not a straghtforward<br>
operation, as one needs to know how the gain is calculated for it.<br>
<br>
This commit introduces a new camera sensor helper in libipa which aims<br>
to solve this specific issue.<br>
It is based on the MIPI alliance Specification for Camera Command Set<br>
and implements, for now, only the analogue "Global gain" mode.<br></blockquote><div><br></div><div>I know this has probably been discussed in detail internally, but what provisions</div><div>do you expect for gain formulas that do not conform to the CCI formula, or those</div><div>that are entirely table based?</div><div> </div><div>Thanks,</div><div>Naush</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">
<br>
Is makes it possible to only have 4 parameters to store per sensor, and<br>
the gain calculation is then done identically for all of them. This<br>
commit gives the gains for imx219 (based on RPi cam_helper), ov5670 and<br>
ov5693.<br>
<br>
Adding a new sensor is pretty straightfoward as one only needs to<br>
implement the sub-class for it and register that class to the<br>
CameraSensorHelperFactory.<br>
<br>
Signed-off-by: Jean-Michel Hautbois <<a href="mailto:jeanmichel.hautbois@ideasonboard.com" target="_blank">jeanmichel.hautbois@ideasonboard.com</a>><br>
---<br>
src/ipa/libipa/camera_sensor_helper.cpp | 361 ++++++++++++++++++++++++<br>
src/ipa/libipa/camera_sensor_helper.h | 91 ++++++<br>
src/ipa/libipa/meson.build | 2 +<br>
3 files changed, 454 insertions(+)<br>
create mode 100644 src/ipa/libipa/camera_sensor_helper.cpp<br>
create mode 100644 src/ipa/libipa/camera_sensor_helper.h<br>
<br>
diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp<br>
new file mode 100644<br>
index 00000000..2bd82861<br>
--- /dev/null<br>
+++ b/src/ipa/libipa/camera_sensor_helper.cpp<br>
@@ -0,0 +1,361 @@<br>
+/* SPDX-License-Identifier: BSD-2-Clause */<br>
+/*<br>
+ * Copyright (C) 2021 Ideas On Board<br>
+ *<br>
+ * camera_sensor_helper.cpp - helper class providing camera informations<br>
+ */<br>
+#include "camera_sensor_helper.h"<br>
+<br>
+#include <map><br>
+<br>
+#include "libcamera/internal/log.h"<br>
+<br>
+/**<br>
+ * \file camera_sensor_helper.h<br>
+ * \brief Create helper class for each sensor<br>
+ *<br>
+ * Each camera sensor supported by libcamera may need specific informations to<br>
+ * be sent (analogue gain is sensor dependant for instance).<br>
+ *<br>
+ * Every subclass of CameraSensorHelper shall be registered with libipa using<br>
+ * the REGISTER_CAMERA_SENSOR_HELPER() macro.<br>
+ */<br>
+<br>
+namespace libcamera {<br>
+<br>
+LOG_DEFINE_CATEGORY(CameraSensorHelper)<br>
+<br>
+namespace ipa {<br>
+<br>
+/**<br>
+ * \class CameraSensorHelper<br>
+ * \brief Create and give helpers for each camera sensor in the pipeline<br>
+ *<br>
+ * CameraSensorHelper instances are unique and sensor dependant.<br>
+ */<br>
+<br>
+/**<br>
+ * \brief Construct a CameraSensorHelper instance<br>
+ * \param[in] name The sensor model name<br>
+ *<br>
+ * The CameraSensorHelper instances shall never be constructed manually, but always<br>
+ * through the CameraSensorHelperFactory::create() method implemented by the<br>
+ * respective factories.<br>
+ */<br>
+<br>
+CameraSensorHelper::CameraSensorHelper(const char *name)<br>
+ : name_(name)<br>
+{<br>
+ analogueGain_ = { GlobalGain, 1, 1, 0, 0 };<br>
+}<br>
+<br>
+CameraSensorHelper::~CameraSensorHelper()<br>
+{<br>
+}<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelper::getGainCode(double gain)<br>
+ * \brief Get the analogue gain code to pass to V4L2 subdev control<br>
+ * \param[in] gain The real gain to pass<br>
+ *<br>
+ * This function aims to abstract the calculation of the gain letting the IPA<br>
+ * use the real gain for its estimations.<br>
+ *<br>
+ * The parameters come from the MIPI Alliance Camera Specification for<br>
+ * Camera Command Set (CCS).<br>
+ */<br>
+uint32_t CameraSensorHelper::getGainCode(double gain) const<br>
+{<br>
+ /* \todo we only support the global gain mode for now */<br>
+ if (analogueGain_.type != GlobalGain)<br>
+ return UINT32_MAX;<br>
+<br>
+ if (analogueGain_.m0 == 0)<br>
+ return (analogueGain_.c0 - gain * analogueGain_.c1) / (gain * analogueGain_.m1);<br>
+ if (analogueGain_.m1 == 0)<br>
+ return (gain * analogueGain_.c1 - analogueGain_.c0) / analogueGain_.m0;<br>
+<br>
+ LOG(CameraSensorHelper, Error) << "For any given image sensor either m0 or m1 shall be zero.";<br>
+ return 1;<br>
+}<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelper::getGain<br>
+ * \brief Get the real gain from the V4l2 subdev control gain<br>
+ * \param[in] gainCode The V4l2 subdev control gain<br>
+ *<br>
+ * This function aims to abstract the calculation of the gain letting the IPA<br>
+ * use the real gain for its estimations. It is the counterpart of the function<br>
+ * CameraSensorHelper::getGainCode.<br>
+ *<br>
+ * The parameters come from the MIPI Alliance Camera Specification for<br>
+ * Camera Command Set (CCS).<br>
+ */<br>
+double CameraSensorHelper::getGain(uint32_t gainCode) const<br>
+{<br>
+ if (analogueGain_.type != GlobalGain)<br>
+ return UINT32_MAX;<br>
+<br>
+ if (analogueGain_.m0 == 0)<br>
+ return analogueGain_.c0 / (analogueGain_.m1 * gainCode + analogueGain_.c1);<br>
+ if (analogueGain_.m1 == 0)<br>
+ return (analogueGain_.m0 * gainCode + analogueGain_.c0) / analogueGain_.c1;<br>
+<br>
+ LOG(CameraSensorHelper, Error) << "For any given image sensor either m0 or m1 shall be zero.";<br>
+ return 1.0;<br>
+}<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelper::name()<br>
+ * \brief Retrieve the camera sensor helper name<br>
+ * \return The camera sensor helper name<br>
+ */<br>
+<br>
+/**<br>
+ * \enum CameraSensorHelper::AnalogueGainCapability<br>
+ * \brief Specify the Gain mode supported by the sensor<br>
+ *<br>
+ * Describes the image sensor analog Gain capabilities.<br>
+ * Two modes are possible, depending on the sensor: Global and Alternate.<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::GlobalGain<br>
+ * \brief Sensor supports Global gain<br>
+ *<br>
+ * The relationship between the integer Gain parameter and the resulting Gain<br>
+ * multiplier is given by the following equation:<br>
+ *<br>
+ * \f$\frac{m0x+c0}{m1x+c1}\f$<br>
+ *<br>
+ * Where 'x' is the gain control parameter, and m0, m1, c0 and c1 are<br>
+ * image-sensor-specific constants exposed by the sensor.<br>
+ * These constants are static parameters, and for any given image sensor either<br>
+ * m0 or m1 shall be zero.<br>
+ *<br>
+ * The full Gain equation therefore reduces to either:<br>
+ *<br>
+ * \f$\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::AlternateGlobalGain<br>
+ * \brief Sensor supports Analogue Global gain (introduced in CCS v1.1)<br>
+ *<br>
+ * Starting with CCS v1.1, Alternate Global Analog Gain is also available.<br>
+ * If the image sensor supports it, then the global analog Gain can be controlled<br>
+ * by linear and exponential gain formula:<br>
+ *<br>
+ * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal} \f$<br>
+ * \todo not implemented in libipa<br>
+ */<br>
+<br>
+/**<br>
+ * \struct CameraSensorHelper::analogueGainConstants<br>
+ * \brief Analogue gain constants used for gain calculation<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGainConstants::type<br>
+ * \brief Analogue gain coding type<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGainConstants::m0<br>
+ * \brief Constant used in the analog Gain control coding/decoding.<br>
+ *<br>
+ * Note: either m0 or m1 shall be zero.<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGainConstants::c0<br>
+ * \brief Constant used in the analog Gain control coding/decoding.<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGainConstants::m1<br>
+ * \brief Constant used in the analog Gain control coding/decoding.<br>
+ *<br>
+ * Note: either m0 or m1 shall be zero.<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGainConstants::c1<br>
+ * \brief Constant used in the analog Gain control coding/decoding.<br>
+ */<br>
+<br>
+/**<br>
+ * \var CameraSensorHelper::analogueGain_<br>
+ * \brief The analogue gain parameters used for calculation<br>
+ *<br>
+ * The analogue gain is calculated through a formula, and its parameters are<br>
+ * sensor specific. Use this variable to store the values at init time.<br>
+ *<br>
+ */<br>
+<br>
+/**<br>
+ * \class CameraSensorHelperFactory<br>
+ * \brief Registration of CameraSensorHelperFactory classes and creation of instances<br>
+ *<br>
+ * To facilitate discovery and instantiation of CameraSensorHelper classes, the<br>
+ * CameraSensorHelperFactory class maintains a registry of camera sensor helper<br>
+ * classes. Each CameraSensorHelper subclass shall register itself using the<br>
+ * REGISTER_CAMERA_SENSOR_HELPER() macro, which will create a corresponding<br>
+ * instance of a CameraSensorHelperFactory subclass and register it with the<br>
+ * static list of factories.<br>
+ */<br>
+<br>
+/**<br>
+ * \brief Construct a camera sensor helper factory<br>
+ * \param[in] name Name of the camera sensor helper class<br>
+ *<br>
+ * Creating an instance of the factory registers it with the global list of<br>
+ * factories, accessible through the factories() function.<br>
+ *<br>
+ * The factory \a name is used for debug purpose and shall be unique.<br>
+ */<br>
+<br>
+CameraSensorHelperFactory::CameraSensorHelperFactory(const char *name)<br>
+ : name_(name)<br>
+{<br>
+ registerType(this);<br>
+}<br>
+<br>
+/**<br>
+ * \brief Create an instance of the CameraSensorHelper corresponding to the factory<br>
+ *<br>
+ * \return A unique pointer to a new instance of the CameraSensorHelper subclass<br>
+ * corresponding to the factory<br>
+ */<br>
+std::unique_ptr<CameraSensorHelper> CameraSensorHelperFactory::create()<br>
+{<br>
+ CameraSensorHelper *handler = createInstance();<br>
+ return std::unique_ptr<CameraSensorHelper>(handler);<br>
+}<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelperFactory::name()<br>
+ * \brief Retrieve the factory name<br>
+ * \return The factory name<br>
+ */<br>
+<br>
+/**<br>
+ * \brief Add a camera sensor helper class to the registry<br>
+ * \param[in] factory Factory to use to construct the camera sensor helper<br>
+ *<br>
+ * The caller is responsible to guarantee the uniqueness of the camera sensor helper<br>
+ * name.<br>
+ */<br>
+void CameraSensorHelperFactory::registerType(CameraSensorHelperFactory *factory)<br>
+{<br>
+ std::vector<CameraSensorHelperFactory *> &factories = CameraSensorHelperFactory::factories();<br>
+<br>
+ factories.push_back(factory);<br>
+}<br>
+<br>
+/**<br>
+ * \brief Retrieve the list of all camera sensor helper factories<br>
+ *<br>
+ * The static factories map is defined inside the function to ensures it gets<br>
+ * initialized on first use, without any dependency on link order.<br>
+ *<br>
+ * \return The list of camera sensor helper factories<br>
+ */<br>
+std::vector<CameraSensorHelperFactory *> &CameraSensorHelperFactory::factories()<br>
+{<br>
+ static std::vector<CameraSensorHelperFactory *> factories;<br>
+ return factories;<br>
+}<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelperFactory::createInstance()<br>
+ * \brief Create an instance of the CameraSensorHelper corresponding to the factory<br>
+ *<br>
+ * This virtual function is implemented by the REGISTER_CAMERA_SENSOR_HELPER()<br>
+ * macro. It creates a camera sensor helper instance associated with the camera<br>
+ * sensor model.<br>
+ *<br>
+ * \return A pointer to a newly constructed instance of the CameraSensorHelper<br>
+ * subclass corresponding to the factory<br>
+ */<br>
+<br>
+/**<br>
+ * \def REGISTER_CAMERA_SENSOR_HELPER<br>
+ * \brief Register a camera sensor helper with the camera sensor helper factory<br>
+ * \param[in] name Sensor model name used to register the class<br>
+ * \param[in] handler Class name of CameraSensorHelper derived class to register<br>
+ *<br>
+ * Register a CameraSensorHelper subclass with the factory and make it available to<br>
+ * try and match devices.<br>
+ */<br>
+<br>
+/**<br>
+ * \class CameraSensorHelperImx219<br>
+ * \brief Create and give helpers for the imx219 sensor<br>
+ */<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelperImx219::CameraSensorHelperImx219<br>
+ * \brief Construct a CameraSensorHelperImx219 instance for imx219<br>
+ * \param[in] name The sensor model name<br>
+ */<br>
+class CameraSensorHelperImx219 : public CameraSensorHelper<br>
+{<br>
+public:<br>
+ CameraSensorHelperImx219(const char *name);<br>
+};<br>
+REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)<br>
+CameraSensorHelperImx219::CameraSensorHelperImx219(const char *name)<br>
+ : CameraSensorHelper(name)<br>
+{<br>
+ analogueGain_ = { GlobalGain, 0, -1, 256, 256 };<br>
+}<br>
+<br>
+/**<br>
+ * \class CameraSensorHelperOv5670<br>
+ * \brief Create and give helpers for the ov5670 sensor<br>
+ */<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelperOv5670::CameraSensorHelperOv5670<br>
+ * \brief Construct a CameraSensorHelperOv5670 instance for ov5670<br>
+ * \param[in] name The sensor model name<br>
+ */<br>
+class CameraSensorHelperOv5670 : public CameraSensorHelper<br>
+{<br>
+public:<br>
+ CameraSensorHelperOv5670(const char *name);<br>
+};<br>
+REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)<br>
+CameraSensorHelperOv5670::CameraSensorHelperOv5670(const char *name)<br>
+ : CameraSensorHelper(name)<br>
+{<br>
+ analogueGain_ = { GlobalGain, 1, 0, 0, 256 };<br>
+}<br>
+<br>
+/**<br>
+ * \class CameraSensorHelperOv5693<br>
+ * \brief Create and give helpers for the ov5693 sensor<br>
+ */<br>
+<br>
+/**<br>
+ * \fn CameraSensorHelperOv5693::CameraSensorHelperOv5693<br>
+ * \brief Construct a CameraSensorHelperOv5693 instance for ov5693<br>
+ * \param[in] name The sensor model name<br>
+ */<br>
+class CameraSensorHelperOv5693 : public CameraSensorHelper<br>
+{<br>
+public:<br>
+ CameraSensorHelperOv5693(const char *name);<br>
+};<br>
+REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)<br>
+CameraSensorHelperOv5693::CameraSensorHelperOv5693(const char *name)<br>
+ : CameraSensorHelper(name)<br>
+{<br>
+ analogueGain_ = { GlobalGain, 1, 0, 0, 16 };<br>
+}<br>
+<br>
+} /* namespace ipa */<br>
+<br>
+} /* namespace libcamera */<br>
+<br>
diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h<br>
new file mode 100644<br>
index 00000000..63031902<br>
--- /dev/null<br>
+++ b/src/ipa/libipa/camera_sensor_helper.h<br>
@@ -0,0 +1,91 @@<br>
+/* SPDX-License-Identifier: BSD-2-Clause */<br>
+/*<br>
+ * Copyright (C) 2021 Ideas On Board<br>
+ *<br>
+ * camera_sensor_helper.h - helper class providing camera informations<br>
+ */<br>
+#ifndef __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__<br>
+#define __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__<br>
+<br>
+#include <stdint.h><br>
+<br>
+#include <string><br>
+<br>
+#include <libcamera/class.h><br>
+#include <libcamera/object.h><br>
+<br>
+namespace libcamera {<br>
+<br>
+namespace ipa {<br>
+<br>
+class CameraSensorHelper;<br>
+<br>
+class CameraSensorHelper : public Object<br>
+{<br>
+public:<br>
+ CameraSensorHelper(const char *name);<br>
+ virtual ~CameraSensorHelper();<br>
+<br>
+ const std::string &name() const { return name_; }<br>
+ uint32_t getGainCode(double gain) const;<br>
+ double getGain(uint32_t gainCode) const;<br>
+<br>
+protected:<br>
+ enum AnalogueGainCapability : uint16_t {<br>
+ GlobalGain = 0,<br>
+ AlternateGlobalGain = 2,<br>
+ };<br>
+<br>
+ struct analogueGainConstants {<br>
+ uint16_t type;<br>
+ int16_t m0;<br>
+ int16_t c0;<br>
+ int16_t m1;<br>
+ int16_t c1;<br>
+ };<br>
+ analogueGainConstants analogueGain_;<br>
+<br>
+private:<br>
+ std::string name_;<br>
+ friend class CameraSensorHelperFactory;<br>
+};<br>
+<br>
+class CameraSensorHelperFactory<br>
+{<br>
+public:<br>
+ CameraSensorHelperFactory(const char *name);<br>
+ virtual ~CameraSensorHelperFactory() = default;<br>
+<br>
+ std::unique_ptr<CameraSensorHelper> create();<br>
+<br>
+ const std::string &name() const { return name_; }<br>
+<br>
+ static void registerType(CameraSensorHelperFactory *factory);<br>
+ static std::vector<CameraSensorHelperFactory *> &factories();<br>
+<br>
+private:<br>
+ virtual CameraSensorHelper *createInstance() = 0;<br>
+<br>
+ std::string name_;<br>
+};<br>
+<br>
+#define REGISTER_CAMERA_SENSOR_HELPER(name, handler) \<br>
+ class handler##Factory final : public CameraSensorHelperFactory \<br>
+ { \<br>
+ public: \<br>
+ handler##Factory() : CameraSensorHelperFactory(#handler) {} \<br>
+ \<br>
+ private: \<br>
+ CameraSensorHelper *createInstance() \<br>
+ { \<br>
+ return new handler(name); \<br>
+ } \<br>
+ }; \<br>
+ static handler##Factory global_##handler##Factory;<br>
+<br>
+} /* namespace ipa */<br>
+<br>
+} /* namespace libcamera */<br>
+<br>
+#endif /* __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__ */<br>
+<br>
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build<br>
index 038fc490..dc90542c 100644<br>
--- a/src/ipa/libipa/meson.build<br>
+++ b/src/ipa/libipa/meson.build<br>
@@ -2,11 +2,13 @@<br>
<br>
libipa_headers = files([<br>
'algorithm.h',<br>
+ 'camera_sensor_helper.h',<br>
'histogram.h'<br>
])<br>
<br>
libipa_sources = files([<br>
'algorithm.cpp',<br>
+ 'camera_sensor_helper.cpp',<br>
'histogram.cpp'<br>
])<br>
<br>
-- <br>
2.30.2<br>
<br>
</blockquote></div></div>