[libcamera-devel] [PATCH 15/23] libcamera: controls: Support compound controls in ControlValue
Jacopo Mondi
jacopo at jmondi.org
Mon Jan 13 17:42:37 CET 2020
Add compound controls support to the ControlValue class. The polymorphic class
can now store more than a single element and supports access and
creation through the use of Span<>.
Signed-off-by: Jacopo Mondi <jacopo at jmondi.org>
---
include/libcamera/controls.h | 37 +++-
src/libcamera/controls.cpp | 329 ++++++++++++++++++++++++++++++++---
2 files changed, 333 insertions(+), 33 deletions(-)
diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h
index 8fa33d93b088..bdbdb213528d 100644
--- a/include/libcamera/controls.h
+++ b/include/libcamera/controls.h
@@ -11,6 +11,8 @@
#include <string>
#include <unordered_map>
+#include <libcamera/span.h>
+
namespace libcamera {
class ControlValidator;
@@ -21,6 +23,10 @@ enum ControlType {
ControlTypeInteger32,
ControlTypeInteger64,
ControlTypeFloat,
+ ControlTypeCompoundBool,
+ ControlTypeCompoundInt32,
+ ControlTypeCompoundInt64,
+ ControlTypeCompoundFloat,
};
class ControlValue
@@ -31,12 +37,18 @@ public:
ControlValue(int32_t value);
ControlValue(int64_t value);
ControlValue(float value);
+ ControlValue(Span<bool> &values);
+ ControlValue(Span<int32_t> &values);
+ ControlValue(Span<int64_t> &values);
+ ControlValue(Span<float> &values);
+ ~ControlValue();
ControlType type() const { return type_; }
bool isNone() const { return type_ == ControlTypeNone; }
+ std::size_t numElements() const { return numElements_; }
template<typename T>
- const T &get() const;
+ T get() const;
template<typename T>
void set(const T &value);
@@ -57,6 +69,21 @@ private:
int64_t integer64_;
float float_;
};
+
+ union {
+ void *pvoid_;
+ bool *pbool_;
+ int32_t *p32_;
+ int64_t *p64_;
+ float *pfloat_;
+ };
+
+ std::size_t numElements_;
+
+ void release();
+ bool compareElement(const ControlValue &other) const;
+ bool compareElement(const ControlValue &other, unsigned int i) const;
+ std::string elemToString(unsigned int i) const;
};
class ControlId
@@ -215,13 +242,11 @@ public:
bool contains(unsigned int id) const;
template<typename T>
- const T &get(const Control<T> &ctrl) const
+ const T get(const Control<T> &ctrl) const
{
const ControlValue *val = find(ctrl.id());
- if (!val) {
- static T t(0);
- return t;
- }
+ if (!val)
+ return T{};
return val->get<T>();
}
diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp
index 74ce5d0ba4f1..7718a53911e6 100644
--- a/src/libcamera/controls.cpp
+++ b/src/libcamera/controls.cpp
@@ -9,7 +9,9 @@
#include <iomanip>
#include <sstream>
-#include <string>
+#include <string.h>
+
+#include <libcamera/span.h>
#include "control_validator.h"
#include "log.h"
@@ -60,6 +62,14 @@ LOG_DEFINE_CATEGORY(Controls)
* The control stores a 64-bit integer value
* \var ControlTypeFloat
* The control stores a 32-bit floating point value
+ * \var ControlTypeCompoundBool
+ * The control stores an array of boolean values
+ * \var ControlTypeCompoundInt32
+ * The control stores an array of 32-bit integer values
+ * \var ControlTypeCompoundInt64
+ * The control stores an array of 64-bit integer values
+ * \var ControlTypeCompoundFloat
+ * The control stores an array of 32-bit floating values
*/
/**
@@ -71,7 +81,7 @@ LOG_DEFINE_CATEGORY(Controls)
* \brief Construct an empty ControlValue.
*/
ControlValue::ControlValue()
- : type_(ControlTypeNone)
+ : type_(ControlTypeNone), pvoid_(nullptr), numElements_(0)
{
}
@@ -80,7 +90,8 @@ ControlValue::ControlValue()
* \param[in] value Boolean value to store
*/
ControlValue::ControlValue(bool value)
- : type_(ControlTypeBool), bool_(value)
+ : type_(ControlTypeBool), bool_(value), pvoid_(nullptr),
+ numElements_(1)
{
}
@@ -89,7 +100,8 @@ ControlValue::ControlValue(bool value)
* \param[in] value Integer value to store
*/
ControlValue::ControlValue(int32_t value)
- : type_(ControlTypeInteger32), integer32_(value)
+ : type_(ControlTypeInteger32), integer32_(value), pvoid_(nullptr),
+ numElements_(1)
{
}
@@ -98,7 +110,8 @@ ControlValue::ControlValue(int32_t value)
* \param[in] value Integer value to store
*/
ControlValue::ControlValue(int64_t value)
- : type_(ControlTypeInteger64), integer64_(value)
+ : type_(ControlTypeInteger64), integer64_(value), pvoid_(nullptr),
+ numElements_(1)
{
}
@@ -107,8 +120,73 @@ ControlValue::ControlValue(int64_t value)
* \param[in] value Float value to store
*/
ControlValue::ControlValue(float value)
- : type_(ControlTypeFloat), float_(value)
+ : type_(ControlTypeFloat), float_(value), pvoid_(nullptr),
+ numElements_(1)
+{
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of boolean elements
+ * \param[in] values Span of boolean values to store
+ */
+ControlValue::ControlValue(Span<bool> &values)
+ : type_(ControlTypeCompoundBool), numElements_(values.size())
{
+ pbool_ = new bool[numElements_];
+ memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of 32 bit integers elements
+ * \param[in] values Span of 32 bit integer values to store
+ */
+ControlValue::ControlValue(Span<int32_t> &values)
+ : type_(ControlTypeCompoundInt32), numElements_(values.size())
+{
+ p32_ = new int32_t[numElements_];
+ memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of 64 bit integers elements
+ * \param[in] values Span of 64 bit integer values to store
+ */
+ControlValue::ControlValue(Span<int64_t> &values)
+ : type_(ControlTypeCompoundInt64), numElements_(values.size())
+{
+ p64_ = new int64_t[numElements_];
+ memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
+}
+
+/**
+ * \brief Construct a ControlValue with a Span of float elements
+ * \param[in] values Span of float values to store
+ */
+ControlValue::ControlValue(Span<float> &values)
+ : type_(ControlTypeCompoundFloat), numElements_(values.size())
+{
+ pfloat_ = new float[numElements_];
+ memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
+void ControlValue::release()
+{
+ switch (type_) {
+ case ControlTypeCompoundBool:
+ case ControlTypeCompoundInt32:
+ case ControlTypeCompoundInt64:
+ case ControlTypeCompoundFloat:
+ delete[] pbool_;
+ pbool_ = nullptr;
+ /* fall-through. */
+ default:
+ return;
+ }
+}
+
+ControlValue::~ControlValue()
+{
+ release();
}
/**
@@ -124,24 +202,38 @@ ControlValue::ControlValue(float value)
*/
/**
- * \fn template<typename T> const T &ControlValue::get() const
- * \brief Get the control value
+ * \fn ControlValue::numElements()
+ * \brief Retrieve the number of elements stored in the ControlValue
+ * \return The number of elements stored in the ControlValue
+ */
+
+/**
+ * \fn template<typename T> const T ControlValue::get() const
+ * \brief Get the control values
*
* The control value type shall match the type T, otherwise the behaviour is
* undefined.
*
- * \return The control value
+ * This function applies to ControlValue instances which store a single or
+ * multiple values. The ControlValue's elements are returned in a Span in the
+ * former case.
+ *
+ * \return The control value or a Span of values
*/
/**
- * \fn template<typename T> void ControlValue::set(const T &value)
- * \brief Set the control value to \a value
- * \param[in] value The control value
+ * \fn template<typename T> void ControlValue::set(const T &values)
+ * \brief Set the control values to \a values
+ * \param[in] values The control values
+ *
+ * This function can be used to set the ControlValue to a single value, or
+ * to store multiple values by providing a Span<> of elements to the
+ * function.
*/
#ifndef __DOXYGEN__
template<>
-const bool &ControlValue::get<bool>() const
+bool ControlValue::get<bool>() const
{
ASSERT(type_ == ControlTypeBool);
@@ -149,7 +241,19 @@ const bool &ControlValue::get<bool>() const
}
template<>
-const int32_t &ControlValue::get<int32_t>() const
+Span<bool> ControlValue::get<Span<bool>>() const
+{
+ ASSERT(type_ == ControlTypeCompoundBool);
+
+ /*
+ * Explicitly create a Span<bool> instance, otherwise the compiler
+ * tries to match with the Span class initializer_list constructor.
+ */
+ return Span<bool>(pbool_, static_cast<std::size_t>(numElements_));
+}
+
+template<>
+int32_t ControlValue::get<int32_t>() const
{
ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
@@ -157,7 +261,16 @@ const int32_t &ControlValue::get<int32_t>() const
}
template<>
-const int64_t &ControlValue::get<int64_t>() const
+Span<int32_t> ControlValue::get<Span<int32_t>>() const
+{
+ ASSERT(type_ == ControlTypeCompoundInt32 ||
+ type_ == ControlTypeCompoundInt64);
+
+ return { p32_, numElements_ };
+}
+
+template<>
+int64_t ControlValue::get<int64_t>() const
{
ASSERT(type_ == ControlTypeInteger32 || type_ == ControlTypeInteger64);
@@ -165,62 +278,190 @@ const int64_t &ControlValue::get<int64_t>() const
}
template<>
-const float &ControlValue::get<float>() const
+Span<int64_t> ControlValue::get<Span<int64_t>>() const
+{
+ ASSERT(type_ == ControlTypeCompoundInt32 ||
+ type_ == ControlTypeCompoundInt64);
+
+ return { p64_, numElements_ };
+}
+
+template<>
+float ControlValue::get<float>() const
{
ASSERT(type_ == ControlTypeFloat);
return float_;
}
+template<>
+Span<float> ControlValue::get<Span<float>>() const
+{
+ ASSERT(type_ == ControlTypeCompoundFloat);
+
+ return { pfloat_, numElements_ };
+}
+
template<>
void ControlValue::set<bool>(const bool &value)
{
+ release();
+
type_ = ControlTypeBool;
bool_ = value;
+ numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<bool>>(const Span<bool> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundBool;
+ numElements_ = values.size();
+
+ pbool_ = new bool[numElements_];
+ memcpy(pbool_, values.data(), sizeof(bool) * numElements_);
}
template<>
void ControlValue::set<int32_t>(const int32_t &value)
{
+ release();
+
type_ = ControlTypeInteger32;
integer32_ = value;
+ numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<int32_t>>(const Span<int32_t> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundInt32;
+ numElements_ = values.size();
+
+ p32_ = new int32_t[numElements_];
+ memcpy(p32_, values.data(), sizeof(int32_t) * numElements_);
}
template<>
void ControlValue::set<int64_t>(const int64_t &value)
{
+ release();
+
type_ = ControlTypeInteger64;
integer64_ = value;
+ numElements_ = 1;
+}
+
+template<>
+void ControlValue::set<Span<int64_t>>(const Span<int64_t> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundInt64;
+ numElements_ = values.size();
+
+ p64_ = new int64_t[numElements_];
+ memcpy(p64_, values.data(), sizeof(int64_t) * numElements_);
}
template<>
void ControlValue::set<float>(const float &value)
{
+ release();
+
type_ = ControlTypeFloat;
float_ = value;
+ numElements_ = 1;
}
+
+template<>
+void ControlValue::set<Span<float>>(const Span<float> &values)
+{
+ release();
+
+ type_ = ControlTypeCompoundFloat;
+ numElements_ = values.size();
+
+ pfloat_ = new float[numElements_];
+ memcpy(pfloat_, values.data(), sizeof(float) * numElements_);
+}
+
#endif /* __DOXYGEN__ */
+std::string ControlValue::elemToString(unsigned int i) const
+{
+ switch (type_) {
+ case ControlTypeBool:
+ return bool_ ? "True " : "False ";
+ case ControlTypeInteger32:
+ return std::to_string(integer32_);
+ case ControlTypeInteger64:
+ return std::to_string(integer64_);
+ case ControlTypeFloat:
+ return std::to_string(float_);
+ case ControlTypeCompoundBool:
+ return pbool_[i] ? "True " : "False ";
+ case ControlTypeCompoundInt32:
+ return std::to_string(p32_[i]) + " ";
+ case ControlTypeCompoundInt64:
+ return std::to_string(p64_[i]) + " ";
+ case ControlTypeCompoundFloat:
+ return std::to_string(pfloat_[i]) + " ";
+ default:
+ return "<None>";
+ }
+}
+
/**
* \brief Assemble and return a string describing the value
* \return A string describing the ControlValue
*/
std::string ControlValue::toString() const
+{
+ if (ControlTypeNone)
+ return "<ValueType Error>";
+
+ std::string str;
+ for (unsigned int i = 0; i < numElements_; ++i)
+ str += elemToString(i);
+
+ return str;
+}
+
+bool ControlValue::compareElement(const ControlValue &other) const
{
switch (type_) {
- case ControlTypeNone:
- return "<None>";
case ControlTypeBool:
- return bool_ ? "True" : "False";
+ return bool_ == other.bool_;
case ControlTypeInteger32:
- return std::to_string(integer32_);
+ return integer32_ == other.integer32_;
case ControlTypeInteger64:
- return std::to_string(integer64_);
+ return integer64_ == other.integer64_;
case ControlTypeFloat:
- return std::to_string(float_);
+ return float_ == other.float_;
+ default:
+ return false;
}
+}
- return "<ValueType Error>";
+bool ControlValue::compareElement(const ControlValue &other, unsigned int i) const
+{
+ switch (type_) {
+ case ControlTypeCompoundBool:
+ return pbool_[i] == other.pbool_[i];
+ case ControlTypeCompoundInt32:
+ return p32_[i] == other.p32_[i];
+ case ControlTypeCompoundInt64:
+ return p64_[i] == other.p64_[i];
+ case ControlTypeCompoundFloat:
+ return pfloat_[i] == other.pfloat_[i];
+ default:
+ return false;
+ }
}
/**
@@ -232,15 +473,25 @@ bool ControlValue::operator==(const ControlValue &other) const
if (type_ != other.type_)
return false;
+ if (numElements_ != other.numElements())
+ return false;
+
switch (type_) {
case ControlTypeBool:
- return bool_ == other.bool_;
case ControlTypeInteger32:
- return integer32_ == other.integer32_;
case ControlTypeInteger64:
- return integer64_ == other.integer64_;
case ControlTypeFloat:
- return float_ == other.float_;
+ return compareElement(other);
+ case ControlTypeCompoundBool:
+ case ControlTypeCompoundInt32:
+ case ControlTypeCompoundInt64:
+ case ControlTypeCompoundFloat:
+ for (unsigned int i = 0; i < numElements_; ++i) {
+ if (!compareElement(other, i))
+ return false;
+ }
+
+ return true;
default:
return false;
}
@@ -360,23 +611,47 @@ Control<bool>::Control(unsigned int id, const char *name)
{
}
+template<>
+Control<Span<bool>>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeCompoundBool)
+{
+}
+
template<>
Control<int32_t>::Control(unsigned int id, const char *name)
: ControlId(id, name, ControlTypeInteger32)
{
}
+template<>
+Control<Span<int32_t>>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeCompoundInt32)
+{
+}
+
template<>
Control<int64_t>::Control(unsigned int id, const char *name)
: ControlId(id, name, ControlTypeInteger64)
{
}
+template<>
+Control<Span<int64_t>>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeCompoundInt64)
+{
+}
+
template<>
Control<float>::Control(unsigned int id, const char *name)
: ControlId(id, name, ControlTypeFloat)
{
}
+
+template<>
+Control<Span<float>>::Control(unsigned int id, const char *name)
+ : ControlId(id, name, ControlTypeCompoundFloat)
+{
+}
#endif /* __DOXYGEN__ */
/**
--
2.24.0
More information about the libcamera-devel
mailing list