diff options
Diffstat (limited to 'src/ipa/libipa')
-rw-r--r-- | src/ipa/libipa/algorithm.cpp | 39 | ||||
-rw-r--r-- | src/ipa/libipa/algorithm.h | 24 | ||||
-rw-r--r-- | src/ipa/libipa/camera_sensor_helper.cpp | 322 | ||||
-rw-r--r-- | src/ipa/libipa/camera_sensor_helper.h | 89 | ||||
-rw-r--r-- | src/ipa/libipa/histogram.cpp | 153 | ||||
-rw-r--r-- | src/ipa/libipa/histogram.h | 40 | ||||
-rw-r--r-- | src/ipa/libipa/ipa_interface_wrapper.cpp | 285 | ||||
-rw-r--r-- | src/ipa/libipa/ipa_interface_wrapper.h | 61 | ||||
-rw-r--r-- | src/ipa/libipa/meson.build | 12 |
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) |