summaryrefslogtreecommitdiff
path: root/src/ipa/libipa
diff options
context:
space:
mode:
Diffstat (limited to 'src/ipa/libipa')
-rw-r--r--src/ipa/libipa/algorithm.cpp39
-rw-r--r--src/ipa/libipa/algorithm.h24
-rw-r--r--src/ipa/libipa/camera_sensor_helper.cpp322
-rw-r--r--src/ipa/libipa/camera_sensor_helper.h89
-rw-r--r--src/ipa/libipa/histogram.cpp153
-rw-r--r--src/ipa/libipa/histogram.h40
-rw-r--r--src/ipa/libipa/ipa_interface_wrapper.cpp285
-rw-r--r--src/ipa/libipa/ipa_interface_wrapper.h61
-rw-r--r--src/ipa/libipa/meson.build12
9 files changed, 675 insertions, 350 deletions
diff --git a/src/ipa/libipa/algorithm.cpp b/src/ipa/libipa/algorithm.cpp
new file mode 100644
index 00000000..930f9353
--- /dev/null
+++ b/src/ipa/libipa/algorithm.cpp
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Ideas On Board
+ *
+ * algorithm.cpp - ISP control algorithms
+ */
+
+#include "algorithm.h"
+
+/**
+ * \file algorithm.h
+ * \brief Algorithm common interface
+ */
+
+namespace libcamera {
+
+/**
+ * \brief The IPA namespace
+ *
+ * The IPA namespace groups all types specific to IPA modules. It serves as the
+ * top-level namespace for the IPA library libipa, and also contains
+ * module-specific namespaces for IPA modules.
+ */
+namespace ipa {
+
+/**
+ * \class Algorithm
+ * \brief The base class for all IPA algorithms
+ *
+ * The Algorithm class defines a standard interface for IPA algorithms. By
+ * abstracting algorithms, it makes possible the implementation of generic code
+ * to manage algorithms regardless of their specific type.
+ */
+
+Algorithm::~Algorithm() = default;
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/algorithm.h b/src/ipa/libipa/algorithm.h
new file mode 100644
index 00000000..89cee4c4
--- /dev/null
+++ b/src/ipa/libipa/algorithm.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Ideas On Board
+ *
+ * algorithm.h - ISP control algorithm interface
+ */
+#ifndef __LIBCAMERA_IPA_LIBIPA_ALGORITHM_H__
+#define __LIBCAMERA_IPA_LIBIPA_ALGORITHM_H__
+
+namespace libcamera {
+
+namespace ipa {
+
+class Algorithm
+{
+public:
+ virtual ~Algorithm();
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_LIBIPA_ALGORITHM_H__ */
diff --git a/src/ipa/libipa/camera_sensor_helper.cpp b/src/ipa/libipa/camera_sensor_helper.cpp
new file mode 100644
index 00000000..84d8ccf7
--- /dev/null
+++ b/src/ipa/libipa/camera_sensor_helper.cpp
@@ -0,0 +1,322 @@
+/* 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() method.
+ */
+
+/**
+ * \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 CameraSensorHelperOv5670 : public CameraSensorHelper
+{
+public:
+ CameraSensorHelperOv5670()
+ {
+ analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 256 };
+ }
+};
+REGISTER_CAMERA_SENSOR_HELPER("ov5670", CameraSensorHelperOv5670)
+
+class CameraSensorHelperOv5693 : public CameraSensorHelper
+{
+public:
+ CameraSensorHelperOv5693()
+ {
+ analogueGainConstants_ = { AnalogueGainLinear, 1, 0, 0, 16 };
+ }
+};
+REGISTER_CAMERA_SENSOR_HELPER("ov5693", CameraSensorHelperOv5693)
+
+#endif /* __DOXYGEN__ */
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/camera_sensor_helper.h b/src/ipa/libipa/camera_sensor_helper.h
new file mode 100644
index 00000000..a7e4ab3b
--- /dev/null
+++ b/src/ipa/libipa/camera_sensor_helper.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2021, Google Inc.
+ *
+ * camera_sensor_helper.h - Helper class that performs sensor-specific parameter computations
+ */
+#ifndef __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__
+#define __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <libcamera/base/class.h>
+
+namespace libcamera {
+
+namespace ipa {
+
+class CameraSensorHelper
+{
+public:
+ CameraSensorHelper() = default;
+ virtual ~CameraSensorHelper() = default;
+
+ virtual uint32_t gainCode(double gain) const;
+ virtual double gain(uint32_t gainCode) const;
+
+protected:
+ enum AnalogueGainType {
+ AnalogueGainLinear,
+ AnalogueGainExponential,
+ };
+
+ struct AnalogueGainConstants {
+ AnalogueGainType type;
+ int16_t m0;
+ int16_t c0;
+ int16_t m1;
+ int16_t c1;
+ };
+
+ AnalogueGainConstants analogueGainConstants_;
+
+private:
+ LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelper)
+};
+
+class CameraSensorHelperFactory
+{
+public:
+ CameraSensorHelperFactory(const std::string name);
+ virtual ~CameraSensorHelperFactory() = default;
+
+ static std::unique_ptr<CameraSensorHelper> create(const std::string &name);
+
+ static void registerType(CameraSensorHelperFactory *factory);
+ static std::vector<CameraSensorHelperFactory *> &factories();
+
+protected:
+ virtual CameraSensorHelper *createInstance() = 0;
+
+private:
+ LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraSensorHelperFactory)
+
+ std::string name_;
+};
+
+#define REGISTER_CAMERA_SENSOR_HELPER(name, helper) \
+class helper##Factory final : public CameraSensorHelperFactory \
+{ \
+public: \
+ helper##Factory() : CameraSensorHelperFactory(name) {} \
+ \
+private: \
+ CameraSensorHelper *createInstance() \
+ { \
+ return new helper(); \
+ } \
+}; \
+static helper##Factory global_##helper##Factory;
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_LIBIPA_CAMERA_SENSOR_HELPER_H__ */
diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp
new file mode 100644
index 00000000..fb1eb2a2
--- /dev/null
+++ b/src/ipa/libipa/histogram.cpp
@@ -0,0 +1,153 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * histogram.cpp - histogram calculations
+ */
+#include "histogram.h"
+
+#include <cmath>
+
+#include <libcamera/base/log.h>
+
+/**
+ * \file histogram.h
+ * \brief Class to represent Histograms and manipulate them
+ */
+
+namespace libcamera {
+
+namespace ipa {
+
+/**
+ * \class Histogram
+ * \brief The base class for creating histograms
+ *
+ * This class stores a cumulative frequency histogram, which is a mapping that
+ * counts the cumulative number of observations in all of the bins up to the
+ * specified bin. It can be used to find quantiles and averages between quantiles.
+ */
+
+/**
+ * \brief Create a cumulative histogram
+ * \param[in] data A pre-sorted histogram to be passed
+ */
+Histogram::Histogram(Span<uint32_t> data)
+{
+ cumulative_.reserve(data.size());
+ cumulative_.push_back(0);
+ for (const uint32_t &value : data)
+ cumulative_.push_back(cumulative_.back() + value);
+}
+
+/**
+ * \fn Histogram::bins()
+ * \brief Retrieve the number of bins currently used by the Histogram
+ * \return Number of bins
+ */
+
+/**
+ * \fn Histogram::total()
+ * \brief Retrieve the total number of values in the data set
+ * \return Number of values
+ */
+
+/**
+ * \brief Cumulative frequency up to a (fractional) point in a bin.
+ * \param[in] bin The bin up to which to cumulate
+ *
+ * With F(p) the cumulative frequency of the histogram, the value is 0 at
+ * the bottom of the histogram, and the maximum is the number of bins.
+ * The pixels are spread evenly throughout the “bin” in which they lie, so that
+ * F(p) is a continuous (monotonically increasing) function.
+ *
+ * \return The cumulative frequency from 0 up to the specified bin
+ */
+uint64_t Histogram::cumulativeFrequency(double bin) const
+{
+ if (bin <= 0)
+ return 0;
+ else if (bin >= bins())
+ return total();
+ int b = static_cast<int32_t>(bin);
+ return cumulative_[b] +
+ (bin - b) * (cumulative_[b + 1] - cumulative_[b]);
+}
+
+/**
+ * \brief Return the (fractional) bin of the point through the histogram
+ * \param[in] q the desired point (0 <= q <= 1)
+ * \param[in] first low limit (default is 0)
+ * \param[in] last high limit (default is UINT_MAX)
+ *
+ * A quantile gives us the point p = Q(q) in the range such that a proportion
+ * q of the pixels lie below p. A familiar quantile is Q(0.5) which is the median
+ * of a distribution.
+ *
+ * \return The fractional bin of the point
+ */
+double Histogram::quantile(double q, uint32_t first, uint32_t last) const
+{
+ if (last == UINT_MAX)
+ last = cumulative_.size() - 2;
+ ASSERT(first <= last);
+
+ uint64_t item = q * total();
+ /* Binary search to find the right bin */
+ while (first < last) {
+ int middle = (first + last) / 2;
+ /* Is it between first and middle ? */
+ if (cumulative_[middle + 1] > item)
+ last = middle;
+ else
+ first = middle + 1;
+ }
+ ASSERT(item >= cumulative_[first] && item <= cumulative_[last + 1]);
+
+ double frac;
+ if (cumulative_[first + 1] == cumulative_[first])
+ frac = 0;
+ else
+ frac = (item - cumulative_[first]) / (cumulative_[first + 1] - cumulative_[first]);
+ return first + frac;
+}
+
+/**
+ * \brief Calculate the mean between two quantiles
+ * \param[in] lowQuantile low Quantile
+ * \param[in] highQuantile high Quantile
+ *
+ * Quantiles are not ideal for metering as they suffer several limitations.
+ * Instead, a concept is introduced here: inter-quantile mean.
+ * It returns the mean of all pixels between lowQuantile and highQuantile.
+ *
+ * \return The mean histogram bin value between the two quantiles
+ */
+double Histogram::interQuantileMean(double lowQuantile, double highQuantile) const
+{
+ ASSERT(highQuantile > lowQuantile);
+ /* Proportion of pixels which lies below lowQuantile */
+ double lowPoint = quantile(lowQuantile);
+ /* Proportion of pixels which lies below highQuantile */
+ double highPoint = quantile(highQuantile, static_cast<uint32_t>(lowPoint));
+ double sumBinFreq = 0, cumulFreq = 0;
+
+ for (double p_next = floor(lowPoint) + 1.0;
+ p_next <= ceil(highPoint);
+ lowPoint = p_next, p_next += 1.0) {
+ int bin = floor(lowPoint);
+ double freq = (cumulative_[bin + 1] - cumulative_[bin])
+ * (std::min(p_next, highPoint) - lowPoint);
+
+ /* Accumulate weigthed bin */
+ sumBinFreq += bin * freq;
+ /* Accumulate weights */
+ cumulFreq += freq;
+ }
+ /* add 0.5 to give an average for bin mid-points */
+ return sumBinFreq / cumulFreq + 0.5;
+}
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
diff --git a/src/ipa/libipa/histogram.h b/src/ipa/libipa/histogram.h
new file mode 100644
index 00000000..c2761cb2
--- /dev/null
+++ b/src/ipa/libipa/histogram.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2019, Raspberry Pi (Trading) Limited
+ *
+ * histogram.h - histogram calculation interface
+ */
+#ifndef __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__
+#define __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__
+
+#include <assert.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include <libcamera/base/span.h>
+
+namespace libcamera {
+
+namespace ipa {
+
+class Histogram
+{
+public:
+ Histogram(Span<uint32_t> data);
+ size_t bins() const { return cumulative_.size() - 1; }
+ uint64_t total() const { return cumulative_[cumulative_.size() - 1]; }
+ uint64_t cumulativeFrequency(double bin) const;
+ double quantile(double q, uint32_t first = 0, uint32_t last = UINT_MAX) const;
+ double interQuantileMean(double lowQuantile, double hiQuantile) const;
+
+private:
+ std::vector<uint64_t> cumulative_;
+};
+
+} /* namespace ipa */
+
+} /* namespace libcamera */
+
+#endif /* __LIBCAMERA_IPA_LIBIPA_HISTOGRAM_H__ */
diff --git a/src/ipa/libipa/ipa_interface_wrapper.cpp b/src/ipa/libipa/ipa_interface_wrapper.cpp
deleted file mode 100644
index cee532e3..00000000
--- a/src/ipa/libipa/ipa_interface_wrapper.cpp
+++ /dev/null
@@ -1,285 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_interface_wrapper.cpp - Image Processing Algorithm interface wrapper
- */
-
-#include "ipa_interface_wrapper.h"
-
-#include <map>
-#include <string.h>
-#include <unistd.h>
-#include <vector>
-
-#include <libcamera/ipa/ipa_interface.h>
-
-#include "libcamera/internal/byte_stream_buffer.h"
-#include "libcamera/internal/camera_sensor.h"
-
-/**
- * \file ipa_interface_wrapper.h
- * \brief Image Processing Algorithm interface wrapper
- */
-
-namespace libcamera {
-
-/**
- * \class IPAInterfaceWrapper
- * \brief Wrap an IPAInterface and expose it as an ipa_context
- *
- * This class implements the ipa_context API based on a provided IPAInterface.
- * It helps IPAs that implement the IPAInterface API to provide the external
- * ipa_context API.
- *
- * To use the wrapper, an IPA module simple creates a new instance of its
- * IPAInterface implementation, and passes it to the constructor of the
- * IPAInterfaceWrapper. As IPAInterfaceWrapper inherits from ipa_context, the
- * constructed wrapper can then be directly returned from the IPA module's
- * ipaCreate() function.
- *
- * \code{.cpp}
- * class MyIPA : public IPAInterface
- * {
- * ...
- * };
- *
- * struct ipa_context *ipaCreate()
- * {
- * return new IPAInterfaceWrapper(std::make_unique<MyIPA>());
- * }
- * \endcode
- *
- * The wrapper takes ownership of the IPAInterface and will automatically
- * delete it when the wrapper is destroyed.
- */
-
-/**
- * \brief Construct an IPAInterfaceWrapper wrapping \a interface
- * \param[in] interface The interface to wrap
- */
-IPAInterfaceWrapper::IPAInterfaceWrapper(std::unique_ptr<IPAInterface> interface)
- : ipa_(std::move(interface)), callbacks_(nullptr), cb_ctx_(nullptr)
-{
- ops = &operations_;
-
- ipa_->queueFrameAction.connect(this, &IPAInterfaceWrapper::queueFrameAction);
-}
-
-void IPAInterfaceWrapper::destroy(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- delete ctx;
-}
-
-void *IPAInterfaceWrapper::get_interface(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- return ctx->ipa_.get();
-}
-
-void IPAInterfaceWrapper::init(struct ipa_context *_ctx,
- const struct ipa_settings *settings)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- IPASettings ipaSettings{
- .configurationFile = settings->configuration_file
- };
- ctx->ipa_->init(ipaSettings);
-}
-
-int IPAInterfaceWrapper::start(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- return ctx->ipa_->start();
-}
-
-void IPAInterfaceWrapper::stop(struct ipa_context *_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->ipa_->stop();
-}
-
-void IPAInterfaceWrapper::register_callbacks(struct ipa_context *_ctx,
- const struct ipa_callback_ops *callbacks,
- void *cb_ctx)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->callbacks_ = callbacks;
- ctx->cb_ctx_ = cb_ctx;
-}
-
-void IPAInterfaceWrapper::configure(struct ipa_context *_ctx,
- const struct ipa_sensor_info *sensor_info,
- const struct ipa_stream *streams,
- unsigned int num_streams,
- const struct ipa_control_info_map *maps,
- unsigned int num_maps)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
-
- ctx->serializer_.reset();
-
- /* Translate the IPA sensor info. */
- CameraSensorInfo sensorInfo{};
- sensorInfo.model = sensor_info->model;
- sensorInfo.bitsPerPixel = sensor_info->bits_per_pixel;
- sensorInfo.activeAreaSize = { sensor_info->active_area.width,
- sensor_info->active_area.height };
- sensorInfo.analogCrop = { sensor_info->analog_crop.left,
- sensor_info->analog_crop.top,
- sensor_info->analog_crop.width,
- sensor_info->analog_crop.height };
- sensorInfo.outputSize = { sensor_info->output_size.width,
- sensor_info->output_size.height };
- sensorInfo.pixelRate = sensor_info->pixel_rate;
- sensorInfo.lineLength = sensor_info->line_length;
-
- /* Translate the IPA stream configurations map. */
- std::map<unsigned int, IPAStream> ipaStreams;
-
- for (unsigned int i = 0; i < num_streams; ++i) {
- const struct ipa_stream &stream = streams[i];
-
- ipaStreams[stream.id] = {
- stream.pixel_format,
- Size(stream.width, stream.height),
- };
- }
-
- /* Translate the IPA entity controls map. */
- std::map<unsigned int, const ControlInfoMap &> entityControls;
- std::map<unsigned int, ControlInfoMap> infoMaps;
-
- for (unsigned int i = 0; i < num_maps; ++i) {
- const struct ipa_control_info_map &ipa_map = maps[i];
- ByteStreamBuffer byteStream(ipa_map.data, ipa_map.size);
- unsigned int id = ipa_map.id;
-
- infoMaps[id] = ctx->serializer_.deserialize<ControlInfoMap>(byteStream);
- entityControls.emplace(id, infoMaps[id]);
- }
-
- /* \todo Translate the ipaConfig and result. */
- IPAOperationData ipaConfig;
- ctx->ipa_->configure(sensorInfo, ipaStreams, entityControls, ipaConfig,
- nullptr);
-}
-
-void IPAInterfaceWrapper::map_buffers(struct ipa_context *_ctx,
- const struct ipa_buffer *_buffers,
- size_t num_buffers)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- std::vector<IPABuffer> buffers(num_buffers);
-
- for (unsigned int i = 0; i < num_buffers; ++i) {
- const struct ipa_buffer &_buffer = _buffers[i];
- IPABuffer &buffer = buffers[i];
- std::vector<FrameBuffer::Plane> &planes = buffer.planes;
-
- buffer.id = _buffer.id;
-
- planes.resize(_buffer.num_planes);
- for (unsigned int j = 0; j < _buffer.num_planes; ++j) {
- planes[j].fd = FileDescriptor(_buffer.planes[j].dmabuf);
- planes[j].length = _buffer.planes[j].length;
- }
- }
-
- ctx->ipa_->mapBuffers(buffers);
-}
-
-void IPAInterfaceWrapper::unmap_buffers(struct ipa_context *_ctx,
- const unsigned int *_ids,
- size_t num_buffers)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- std::vector<unsigned int> ids(_ids, _ids + num_buffers);
- ctx->ipa_->unmapBuffers(ids);
-}
-
-void IPAInterfaceWrapper::process_event(struct ipa_context *_ctx,
- const struct ipa_operation_data *data)
-{
- IPAInterfaceWrapper *ctx = static_cast<IPAInterfaceWrapper *>(_ctx);
- IPAOperationData opData;
-
- opData.operation = data->operation;
-
- opData.data.resize(data->num_data);
- memcpy(opData.data.data(), data->data,
- data->num_data * sizeof(*data->data));
-
- opData.controls.resize(data->num_lists);
- for (unsigned int i = 0; i < data->num_lists; ++i) {
- const struct ipa_control_list *c_list = &data->lists[i];
- ByteStreamBuffer byteStream(c_list->data, c_list->size);
- opData.controls[i] = ctx->serializer_.deserialize<ControlList>(byteStream);
- }
-
- ctx->ipa_->processEvent(opData);
-}
-
-void IPAInterfaceWrapper::queueFrameAction(unsigned int frame,
- const IPAOperationData &data)
-{
- if (!callbacks_)
- return;
-
- struct ipa_operation_data c_data;
- c_data.operation = data.operation;
- c_data.data = data.data.data();
- c_data.num_data = data.data.size();
-
- struct ipa_control_list control_lists[data.controls.size()];
- c_data.lists = control_lists;
- c_data.num_lists = data.controls.size();
-
- std::size_t listsSize = 0;
- for (const auto &list : data.controls)
- listsSize += serializer_.binarySize(list);
-
- std::vector<uint8_t> binaryData(listsSize);
- ByteStreamBuffer byteStreamBuffer(binaryData.data(), listsSize);
-
- unsigned int i = 0;
- for (const auto &list : data.controls) {
- struct ipa_control_list &c_list = control_lists[i];
- c_list.size = serializer_.binarySize(list);
-
- ByteStreamBuffer b = byteStreamBuffer.carveOut(c_list.size);
- serializer_.serialize(list, b);
-
- c_list.data = b.base();
- }
-
- callbacks_->queue_frame_action(cb_ctx_, frame, c_data);
-}
-
-#ifndef __DOXYGEN__
-/*
- * This construct confuses Doygen and makes it believe that all members of the
- * operations is a member of IPAInterfaceWrapper. It must thus be hidden.
- */
-const struct ipa_context_ops IPAInterfaceWrapper::operations_ = {
- .destroy = &IPAInterfaceWrapper::destroy,
- .get_interface = &IPAInterfaceWrapper::get_interface,
- .init = &IPAInterfaceWrapper::init,
- .start = &IPAInterfaceWrapper::start,
- .stop = &IPAInterfaceWrapper::stop,
- .register_callbacks = &IPAInterfaceWrapper::register_callbacks,
- .configure = &IPAInterfaceWrapper::configure,
- .map_buffers = &IPAInterfaceWrapper::map_buffers,
- .unmap_buffers = &IPAInterfaceWrapper::unmap_buffers,
- .process_event = &IPAInterfaceWrapper::process_event,
-};
-#endif
-
-} /* namespace libcamera */
diff --git a/src/ipa/libipa/ipa_interface_wrapper.h b/src/ipa/libipa/ipa_interface_wrapper.h
deleted file mode 100644
index a1c70159..00000000
--- a/src/ipa/libipa/ipa_interface_wrapper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * ipa_interface_wrapper.h - Image Processing Algorithm interface wrapper
- */
-#ifndef __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__
-#define __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__
-
-#include <memory>
-
-#include <libcamera/ipa/ipa_interface.h>
-
-#include "libcamera/internal/control_serializer.h"
-
-namespace libcamera {
-
-class IPAInterfaceWrapper : public ipa_context
-{
-public:
- IPAInterfaceWrapper(std::unique_ptr<IPAInterface> interface);
-
-private:
- static void destroy(struct ipa_context *ctx);
- static void *get_interface(struct ipa_context *ctx);
- static void init(struct ipa_context *ctx,
- const struct ipa_settings *settings);
- static int start(struct ipa_context *ctx);
- static void stop(struct ipa_context *ctx);
- static void register_callbacks(struct ipa_context *ctx,
- const struct ipa_callback_ops *callbacks,
- void *cb_ctx);
- static void configure(struct ipa_context *ctx,
- const struct ipa_sensor_info *sensor_info,
- const struct ipa_stream *streams,
- unsigned int num_streams,
- const struct ipa_control_info_map *maps,
- unsigned int num_maps);
- static void map_buffers(struct ipa_context *ctx,
- const struct ipa_buffer *c_buffers,
- size_t num_buffers);
- static void unmap_buffers(struct ipa_context *ctx,
- const unsigned int *ids,
- size_t num_buffers);
- static void process_event(struct ipa_context *ctx,
- const struct ipa_operation_data *data);
-
- static const struct ipa_context_ops operations_;
-
- void queueFrameAction(unsigned int frame, const IPAOperationData &data);
-
- std::unique_ptr<IPAInterface> ipa_;
- const struct ipa_callback_ops *callbacks_;
- void *cb_ctx_;
-
- ControlSerializer serializer_;
-};
-
-} /* namespace libcamera */
-
-#endif /* __LIBCAMERA_IPA_INTERFACE_WRAPPER_H__ */
diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
index 22626405..3fda7c00 100644
--- a/src/ipa/libipa/meson.build
+++ b/src/ipa/libipa/meson.build
@@ -1,15 +1,19 @@
# SPDX-License-Identifier: CC0-1.0
libipa_headers = files([
- 'ipa_interface_wrapper.h',
+ 'algorithm.h',
+ 'camera_sensor_helper.h',
+ 'histogram.h'
])
libipa_sources = files([
- 'ipa_interface_wrapper.cpp',
+ 'algorithm.cpp',
+ 'camera_sensor_helper.cpp',
+ 'histogram.cpp'
])
libipa_includes = include_directories('..')
-libipa = static_library('ipa', libipa_sources,
+libipa = static_library('ipa', [libipa_sources, libipa_headers],
include_directories : ipa_includes,
- dependencies : libcamera_dep)
+ dependencies : libcamera_private)