/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2021, Google Inc. * * camera_sensor_helper.cpp - Helper class that performs sensor-specific * parameter computations */ #include "camera_sensor_helper.h" #include <libcamera/base/log.h> /** * \file camera_sensor_helper.h * \brief Helper class that performs sensor-specific parameter computations * * Computation of sensor configuration parameters is a sensor specific * operation. Each CameraHelper derived class computes the value of * configuration parameters, for example the analogue gain value, using * sensor-specific functions and constants. * * Every subclass of CameraSensorHelper shall be registered with libipa using * the REGISTER_CAMERA_SENSOR_HELPER() macro. */ namespace libcamera { LOG_DEFINE_CATEGORY(CameraSensorHelper) namespace ipa { /** * \class CameraSensorHelper * \brief Base class for computing sensor tuning parameters using * sensor-specific constants * * Instances derived from CameraSensorHelper class are sensor-specific. * Each supported sensor will have an associated base class defined. */ /** * \brief Construct a CameraSensorHelper instance * * CameraSensorHelper derived class instances shall never be constructed * manually but always through the CameraSensorHelperFactory::create() function. */ /** * \brief Compute gain code from the analogue gain absolute value * \param[in] gain The real gain to pass * * This function aims to abstract the calculation of the gain letting the IPA * use the real gain for its estimations. * * The parameters come from the MIPI Alliance Camera Specification for * Camera Command Set (CCS). * * \return The gain code to pass to V4L2 */ uint32_t CameraSensorHelper::gainCode(double gain) const { ASSERT(analogueGainConstants_.m0 == 0 || analogueGainConstants_.m1 == 0); ASSERT(analogueGainConstants_.type == AnalogueGainLinear); return (analogueGainConstants_.c0 - analogueGainConstants_.c1 * gain) / (analogueGainConstants_.m1 * gain - analogueGainConstants_.m0); } /** * \brief Compute the real gain from the V4L2 subdev control gain code * \param[in] gainCode The V4L2 subdev control gain * * This function aims to abstract the calculation of the gain letting the IPA * use the real gain for its estimations. It is the counterpart of the function * CameraSensorHelper::gainCode. * * The parameters come from the MIPI Alliance Camera Specification for * Camera Command Set (CCS). * * \return The real gain */ double CameraSensorHelper::gain(uint32_t gainCode) const { ASSERT(analogueGainConstants_.m0 == 0 || analogueGainConstants_.m1 == 0); ASSERT(analogueGainConstants_.type == AnalogueGainLinear); return (analogueGainConstants_.m0 * static_cast<double>(gainCode) + analogueGainConstants_.c0) / (analogueGainConstants_.m1 * static_cast<double>(gainCode) + analogueGainConstants_.c1); } /** * \enum CameraSensorHelper::AnalogueGainType * \brief The gain calculation modes as defined by the MIPI CCS * * Describes the image sensor analogue gain capabilities. * Two modes are possible, depending on the sensor: Linear and Exponential. */ /** * \var CameraSensorHelper::AnalogueGainLinear * \brief Gain is computed using linear gain estimation * * The relationship between the integer gain parameter and the resulting gain * multiplier is given by the following equation: * * \f$gain=\frac{m0x+c0}{m1x+c1}\f$ * * Where 'x' is the gain control parameter, and m0, m1, c0 and c1 are * image-sensor-specific constants of the sensor. * These constants are static parameters, and for any given image sensor either * m0 or m1 shall be zero. * * The full Gain equation therefore reduces to either: * * \f$gain=\frac{c0}{m1x+c1}\f$ or \f$\frac{m0x+c0}{c1}\f$ */ /** * \var CameraSensorHelper::AnalogueGainExponential * \brief Gain is computed using exponential gain estimation * (introduced in CCS v1.1) * * Starting with CCS v1.1, Alternate Global Analogue Gain is also available. * If the image sensor supports it, then the global analogue gain can be * controlled by linear and exponential gain formula: * * \f$gain = analogLinearGainGlobal * 2^{analogExponentialGainGlobal}\f$ * \todo not implemented in libipa */ /** * \struct CameraSensorHelper::AnalogueGainConstants * \brief Analogue gain constants used for gain calculation */ /** * \var CameraSensorHelper::AnalogueGainConstants::type * \brief Analogue gain calculation mode */ /** * \var CameraSensorHelper::AnalogueGainConstants::m0 * \brief Constant used in the analogue Gain coding/decoding * * \note Either m0 or m1 shall be zero. */ /** * \var CameraSensorHelper::AnalogueGainConstants::c0 * \brief Constant used in the analogue gain coding/decoding */ /** * \var CameraSensorHelper::AnalogueGainConstants::m1 * \brief Constant used in the analogue gain coding/decoding * * \note Either m0 or m1 shall be zero. */ /** * \var CameraSensorHelper::AnalogueGainConstants::c1 * \brief Constant used in the analogue gain coding/decoding */ /** * \var CameraSensorHelper::analogueGainConstants_ * \brief The analogue gain parameters used for calculation * * The analogue gain is calculated through a formula, and its parameters are * sensor specific. Use this variable to store the values at init time. */ /** * \class CameraSensorHelperFactory * \brief Registration of CameraSensorHelperFactory classes and creation of instances * * To facilitate discovery and instantiation of CameraSensorHelper classes, the * CameraSensorHelperFactory class maintains a registry of camera sensor helper * sub-classes. Each CameraSensorHelper subclass shall register itself using the * REGISTER_CAMERA_SENSOR_HELPER() macro, which will create a corresponding * instance of a CameraSensorHelperFactory subclass and register it with the * static list of factories. */ /** * \brief Construct a camera sensor helper factory * \param[in] name Name of the camera sensor helper class * * Creating an instance of the factory registers it with the global list of * factories, accessible through the factories() function. * * The factory \a name is used for debug purpose and shall be unique. */ CameraSensorHelperFactory::CameraSensorHelperFactory(const std::string name) : name_(name) { registerType(this); } /** * \brief Create an instance of the CameraSensorHelper corresponding to * a named factory * \param[in] name Name of the factory * * \return A unique pointer to a new instance of the CameraSensorHelper subclass * corresponding to the named factory or a null pointer if no such factory * exists */ std::unique_ptr<CameraSensorHelper> CameraSensorHelperFactory::create(const std::string &name) { std::vector<CameraSensorHelperFactory *> &factories = CameraSensorHelperFactory::factories(); for (CameraSensorHelperFactory *factory : factories) { if (name != factory->name_) continue; CameraSensorHelper *helper = factory->createInstance(); return std::unique_ptr<CameraSensorHelper>(helper); } return nullptr; } /** * \brief Add a camera sensor helper class to the registry * \param[in] factory Factory to use to construct the camera sensor helper * * The caller is responsible to guarantee the uniqueness of the camera sensor * helper name. */ void CameraSensorHelperFactory::registerType(CameraSensorHelperFactory *factory) { std::vector<CameraSensorHelperFactory *> &factories = CameraSensorHelperFactory::factories(); factories.push_back(factory); } /** * \brief Retrieve the list of all camera sensor helper factories * \return The list of camera sensor helper factories */ std::vector<CameraSensorHelperFactory *> &CameraSensorHelperFactory::factories() { /* * The static factories map is defined inside the function to ensure * it gets initialized on first use, without any dependency on link * order. */ static std::vector<CameraSensorHelperFactory *> factories; return factories; } /** * \fn CameraSensorHelperFactory::createInstance() * \brief Create an instance of the CameraSensorHelper corresponding to the * factory * * This virtual function is implemented by the REGISTER_CAMERA_SENSOR_HELPER() * macro. It creates a camera sensor helper instance associated with the camera * sensor model. * * \return A pointer to a newly constructed instance of the CameraSensorHelper * subclass corresponding to the factory */ /** * \var CameraSensorHelperFactory::name_ * \brief The name of the factory */ /** * \def REGISTER_CAMERA_SENSOR_HELPER * \brief Register a camera sensor helper with the camera sensor helper factory * \param[in] name Sensor model name used to register the class * \param[in] helper Class name of CameraSensorHelper derived class to register * * Register a CameraSensorHelper subclass with the factory and make it available * to try and match sensors. */ /* ----------------------------------------------------------------------------- * Sensor-specific subclasses */ #ifndef __DOXYGEN__ class CameraSensorHelperImx219 : public CameraSensorHelper { public: CameraSensorHelperImx219() { analogueGainConstants_ = { AnalogueGainLinear, 0, -1, 256, 256 }; } }; REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219) class CameraSensorHelperImx258 : public CameraSensorHelper { public: CameraSensorHelperImx258() { analogueGainConstants_ = { AnalogueGainLinear, 0, 512, -1, 512 }; } }; REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258) class CameraSensorHelperOv5670 : public CameraSensorHelper { public: CameraSensorHelperOv5670() { analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 128 }; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670) class CameraSensorHelperOv5693 : public CameraSensorHelper { public: CameraSensorHelperOv5693() { analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 16 }; } }; REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693) class CameraSensorHelperOv8865 : public CameraSensorHelper { public: CameraSensorHelperOv8865() { analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 128 }; } }; REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865) class CameraSensorHelperOv13858 : public CameraSensorHelper { public: CameraSensorHelperOv13858() { analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 128 }; } }; REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858) #endif /* __DOXYGEN__ */ } /* namespace ipa */ } /* namespace libcamera */