libcamera/src/ipa/libipa/camera_sensor_helper.cpp
Benjamin Bara 7d5b38e2ef libipa: camera_sensor_helper: Add IMX327 helper
Add support for the Sony IMX327, which is added to the kernel with
commit 2d41947ec2c0 ("media: i2c: imx290: Add support for imx327
variant"). It is basically a derivate of the IMX290, therefore also
derive the helper.

Signed-off-by: Benjamin Bara <benjamin.bara@skidata.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
2023-05-19 18:25:59 +01:00

594 lines
16 KiB
C++

/* 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 <cmath>
#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 CameraSensorHelperFactoryBase::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.
*
* \return The gain code to pass to V4L2
*/
uint32_t CameraSensorHelper::gainCode(double gain) const
{
const AnalogueGainConstants &k = gainConstants_;
switch (gainType_) {
case AnalogueGainLinear:
ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
return (k.linear.c0 - k.linear.c1 * gain) /
(k.linear.m1 * gain - k.linear.m0);
case AnalogueGainExponential:
ASSERT(k.exp.a != 0 && k.exp.m != 0);
return std::log2(gain / k.exp.a) / k.exp.m;
default:
ASSERT(false);
return 0;
}
}
/**
* \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.
*
* \return The real gain
*/
double CameraSensorHelper::gain(uint32_t gainCode) const
{
const AnalogueGainConstants &k = gainConstants_;
double gain = static_cast<double>(gainCode);
switch (gainType_) {
case AnalogueGainLinear:
ASSERT(k.linear.m0 == 0 || k.linear.m1 == 0);
return (k.linear.m0 * gain + k.linear.c0) /
(k.linear.m1 * gain + k.linear.c1);
case AnalogueGainExponential:
ASSERT(k.exp.a != 0 && k.exp.m != 0);
return k.exp.a * std::exp2(k.exp.m * gain);
default:
ASSERT(false);
return 0.0;
}
}
/**
* \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 expressed using an exponential model
*
* The relationship between the integer gain parameter and the resulting gain
* multiplier is given by the following equation:
*
* \f$gain = a \cdot 2^{m \cdot x}\f$
*
* Where 'x' is the gain control parameter, and 'a' and 'm' are image
* sensor-specific constants.
*
* This is a subset of the MIPI CCS exponential gain model with the linear
* factor 'a' being a constant, but with the exponent being configurable
* through the 'm' coefficient.
*
* When the gain is expressed in dB, 'a' is equal to 1 and 'm' to
* \f$log_{2}{10^{\frac{1}{20}}}\f$.
*/
/**
* \struct CameraSensorHelper::AnalogueGainLinearConstants
* \brief Analogue gain constants for the linear gain model
*
* \var CameraSensorHelper::AnalogueGainLinearConstants::m0
* \brief Constant used in the linear gain coding/decoding
*
* \note Either m0 or m1 shall be zero.
*
* \var CameraSensorHelper::AnalogueGainLinearConstants::c0
* \brief Constant used in the linear gain coding/decoding
*
* \var CameraSensorHelper::AnalogueGainLinearConstants::m1
* \brief Constant used in the linear gain coding/decoding
*
* \note Either m0 or m1 shall be zero.
*
* \var CameraSensorHelper::AnalogueGainLinearConstants::c1
* \brief Constant used in the linear gain coding/decoding
*/
/**
* \struct CameraSensorHelper::AnalogueGainExpConstants
* \brief Analogue gain constants for the exponential gain model
*
* \var CameraSensorHelper::AnalogueGainExpConstants::a
* \brief Constant used in the exponential gain coding/decoding
*
* \var CameraSensorHelper::AnalogueGainExpConstants::m
* \brief Constant used in the exponential gain coding/decoding
*/
/**
* \struct CameraSensorHelper::AnalogueGainConstants
* \brief Analogue gain model constants
*
* This union stores the constants used to calculate the analogue gain. The
* CameraSensorHelper::gainType_ variable selects which union member is valid.
*
* \var CameraSensorHelper::AnalogueGainConstants::linear
* \brief Constants for the linear gain model
*
* \var CameraSensorHelper::AnalogueGainConstants::exp
* \brief Constants for the exponential gain model
*/
/**
* \var CameraSensorHelper::gainType_
* \brief The analogue gain model type
*/
/**
* \var CameraSensorHelper::gainConstants_
* \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 CameraSensorHelperFactoryBase
* \brief Base class for camera sensor helper factories
*
* The CameraSensorHelperFactoryBase class is the base of all specializations of
* the CameraSensorHelperFactory class template. It implements the factory
* registration, maintains a registry of factories, and provides access to the
* registered factories.
*/
/**
* \brief Construct a camera sensor helper factory base
* \param[in] name Name of the camera sensor helper class
*
* Creating an instance of the factory base registers it with the global list of
* factories, accessible through the factories() function.
*
* The factory \a name is used to look up factories and shall be unique.
*/
CameraSensorHelperFactoryBase::CameraSensorHelperFactoryBase(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> CameraSensorHelperFactoryBase::create(const std::string &name)
{
const std::vector<CameraSensorHelperFactoryBase *> &factories =
CameraSensorHelperFactoryBase::factories();
for (const CameraSensorHelperFactoryBase *factory : factories) {
if (name != factory->name_)
continue;
return factory->createInstance();
}
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 CameraSensorHelperFactoryBase::registerType(CameraSensorHelperFactoryBase *factory)
{
std::vector<CameraSensorHelperFactoryBase *> &factories =
CameraSensorHelperFactoryBase::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<CameraSensorHelperFactoryBase *> &CameraSensorHelperFactoryBase::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<CameraSensorHelperFactoryBase *> factories;
return factories;
}
/**
* \class CameraSensorHelperFactory
* \brief Registration of CameraSensorHelperFactory classes and creation of instances
* \tparam _Helper The camera sensor helper class type for this factory
*
* To facilitate discovery and instantiation of CameraSensorHelper classes, the
* CameraSensorHelperFactory class implements auto-registration of camera sensor
* helpers. 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.
*/
/**
* \fn CameraSensorHelperFactory::CameraSensorHelperFactory(const char *name)
* \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 CameraSensorHelperFactoryBase::factories()
* function.
*
* The factory \a name is used to look up factories and shall be unique.
*/
/**
* \fn CameraSensorHelperFactory::createInstance() const
* \brief Create an instance of the CameraSensorHelper corresponding to the
* factory
*
* \return A unique pointer to a newly constructed instance of the
* CameraSensorHelper subclass corresponding to 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__
/*
* Helper function to compute the m parameter of the exponential gain model
* when the gain code is expressed in dB.
*/
static constexpr double expGainDb(double step)
{
constexpr double log2_10 = 3.321928094887362;
/*
* The gain code is expressed in step * dB (e.g. in 0.1 dB steps):
*
* G_code = G_dB/step = 20/step*log10(G_linear)
*
* Inverting the formula, we get
*
* G_linear = 10^(step/20*G_code) = 2^(log2(10)*step/20*G_code)
*/
return log2_10 * step / 20;
}
class CameraSensorHelperAr0521 : public CameraSensorHelper
{
public:
uint32_t gainCode(double gain) const override;
double gain(uint32_t gainCode) const override;
private:
static constexpr double kStep_ = 16;
};
uint32_t CameraSensorHelperAr0521::gainCode(double gain) const
{
gain = std::clamp(gain, 1.0, 15.5);
unsigned int coarse = std::log2(gain);
unsigned int fine = (gain / (1 << coarse) - 1) * kStep_;
return (coarse << 4) | (fine & 0xf);
}
double CameraSensorHelperAr0521::gain(uint32_t gainCode) const
{
unsigned int coarse = gainCode >> 4;
unsigned int fine = gainCode & 0xf;
return (1 << coarse) * (1 + fine / kStep_);
}
REGISTER_CAMERA_SENSOR_HELPER("ar0521", CameraSensorHelperAr0521)
class CameraSensorHelperImx219 : public CameraSensorHelper
{
public:
CameraSensorHelperImx219()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 0, 256, -1, 256 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("imx219", CameraSensorHelperImx219)
class CameraSensorHelperImx258 : public CameraSensorHelper
{
public:
CameraSensorHelperImx258()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 0, 512, -1, 512 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("imx258", CameraSensorHelperImx258)
class CameraSensorHelperImx290 : public CameraSensorHelper
{
public:
CameraSensorHelperImx290()
{
gainType_ = AnalogueGainExponential;
gainConstants_.exp = { 1.0, expGainDb(0.3) };
}
};
REGISTER_CAMERA_SENSOR_HELPER("imx290", CameraSensorHelperImx290)
class CameraSensorHelperImx327 : public CameraSensorHelperImx290
{
};
REGISTER_CAMERA_SENSOR_HELPER("imx327", CameraSensorHelperImx327)
class CameraSensorHelperImx296 : public CameraSensorHelper
{
public:
CameraSensorHelperImx296()
{
gainType_ = AnalogueGainExponential;
gainConstants_.exp = { 1.0, expGainDb(0.1) };
}
};
REGISTER_CAMERA_SENSOR_HELPER("imx296", CameraSensorHelperImx296)
class CameraSensorHelperImx477 : public CameraSensorHelper
{
public:
CameraSensorHelperImx477()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 0, 1024, -1, 1024 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("imx477", CameraSensorHelperImx477)
class CameraSensorHelperOv2685 : public CameraSensorHelper
{
public:
CameraSensorHelperOv2685()
{
/*
* The Sensor Manual doesn't appear to document the gain model.
* This has been validated with some empirical testing only.
*/
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov2685", CameraSensorHelperOv2685)
class CameraSensorHelperOv2740 : public CameraSensorHelper
{
public:
CameraSensorHelperOv2740()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov2740", CameraSensorHelperOv2740)
class CameraSensorHelperOv4689 : public CameraSensorHelper
{
public:
CameraSensorHelperOv4689()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov4689", CameraSensorHelperOv4689)
class CameraSensorHelperOv5640 : public CameraSensorHelper
{
public:
CameraSensorHelperOv5640()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 16 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov5640", CameraSensorHelperOv5640)
class CameraSensorHelperOv5647 : public CameraSensorHelper
{
public:
CameraSensorHelperOv5647()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 16 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov5647", CameraSensorHelperOv5647)
class CameraSensorHelperOv5670 : public CameraSensorHelper
{
public:
CameraSensorHelperOv5670()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
class CameraSensorHelperOv5675 : public CameraSensorHelper
{
public:
CameraSensorHelperOv5675()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov5675", CameraSensorHelperOv5675)
class CameraSensorHelperOv5693 : public CameraSensorHelper
{
public:
CameraSensorHelperOv5693()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 16 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
class CameraSensorHelperOv8858 : public CameraSensorHelper
{
public:
CameraSensorHelperOv8858()
{
gainType_ = AnalogueGainLinear;
/*
* \todo Validate the selected 1/128 step value as it differs
* from what the sensor manual describes.
*
* See: https://patchwork.linuxtv.org/project/linux-media/patch/20221106171129.166892-2-nicholas@rothemail.net/#142267
*/
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov8858", CameraSensorHelperOv8858)
class CameraSensorHelperOv8865 : public CameraSensorHelper
{
public:
CameraSensorHelperOv8865()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov8865", CameraSensorHelperOv8865)
class CameraSensorHelperOv13858 : public CameraSensorHelper
{
public:
CameraSensorHelperOv13858()
{
gainType_ = AnalogueGainLinear;
gainConstants_.linear = { 1, 0, 0, 128 };
}
};
REGISTER_CAMERA_SENSOR_HELPER("ov13858", CameraSensorHelperOv13858)
#endif /* __DOXYGEN__ */
} /* namespace ipa */
} /* namespace libcamera */