Patch Detail
Show a patch.
GET /api/1.1/patches/24063/?format=api
{ "id": 24063, "url": "https://patchwork.libcamera.org/api/1.1/patches/24063/?format=api", "web_url": "https://patchwork.libcamera.org/patch/24063/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20250806-control_storage-v1-3-2ec8424f6f7d@ideasonboard.com>", "date": "2025-08-06T12:30:47", "name": "[3/3] libcamera: Make ControlValue a view", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "d2408fe93db6eb9e3c4b71f7deb9b3b051f94c34", "submitter": { "id": 143, "url": "https://patchwork.libcamera.org/api/1.1/people/143/?format=api", "name": "Jacopo Mondi", "email": "jacopo.mondi@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/24063/mbox/", "series": [ { "id": 5358, "url": "https://patchwork.libcamera.org/api/1.1/series/5358/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5358", "date": "2025-08-06T12:30:44", "name": "libcamera: Make ControlValue a view", "version": 1, "mbox": "https://patchwork.libcamera.org/series/5358/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/24063/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/24063/checks/", "tags": {}, "headers": { "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>", "X-Original-To": "parsemail@patchwork.libcamera.org", "Delivered-To": "parsemail@patchwork.libcamera.org", "Received": [ "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 99A79C32B5\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 6 Aug 2025 12:31:07 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 753A569223;\n\tWed, 6 Aug 2025 14:31:06 +0200 (CEST)", "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 71F8269220\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 6 Aug 2025 14:31:01 +0200 (CEST)", "from [192.168.0.172] (mob-5-90-59-79.net.vodafone.it [5.90.59.79])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id CB7501026; \n\tWed, 6 Aug 2025 14:30:12 +0200 (CEST)" ], "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"kK0WJEa1\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1754483413;\n\tbh=7WiR50/QfSymZzM59S3iRWZ7WjaCz7cx9e44/VLfilY=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:From;\n\tb=kK0WJEa1PVUPYCoUs1ZvplpzJ7S938D2XR6/KKt7EdV/+Uc98OWRuYN8gyaNzqHxL\n\tzYHBwgYrglF8s7N7fk85V5EDh9zTiwJHOP8Mv3WVbqOC/tYYsJ7VkUwhms95CfgsFx\n\tMIuXAwGFWT/0wc1jeWLMGWh7uWNSusjG3dF7w0JA=", "From": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "Date": "Wed, 06 Aug 2025 14:30:47 +0200", "Subject": "[PATCH 3/3] libcamera: Make ControlValue a view", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "7bit", "Message-Id": "<20250806-control_storage-v1-3-2ec8424f6f7d@ideasonboard.com>", "References": "<20250806-control_storage-v1-0-2ec8424f6f7d@ideasonboard.com>", "In-Reply-To": "<20250806-control_storage-v1-0-2ec8424f6f7d@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Jacopo Mondi <jacopo.mondi@ideasonboard.com>", "X-Mailer": "b4 0.14.2", "X-Developer-Signature": "v=1; a=openpgp-sha256; l=21002;\n\ti=jacopo.mondi@ideasonboard.com; h=from:subject:message-id;\n\tbh=7WiR50/QfSymZzM59S3iRWZ7WjaCz7cx9e44/VLfilY=;\n\tb=owEBbQKS/ZANAwAKAXI0Bo8WoVY8AcsmYgBok0sC4Dv/nWRDKwKBVHt1tP1vbDoOBXAl2Jmw9\n\tb9wHwwfjSOJAjMEAAEKAB0WIQS1xD1IgJogio9YOMByNAaPFqFWPAUCaJNLAgAKCRByNAaPFqFW\n\tPKuNEACa3OV9JTi+zvLXjFEpkt+e17PdP7jNvFHUvBbU6Rxzqa0ynDyj4bUZOVBCg851yXzODKJ\n\t/G317yaoOiBtdvnA1mF1sd6YUxxUdbA0uctPtbTzEK3fnDUHqfWEkbjrhEU89j4IKhShfgibV7u\n\tInkvPM2LA5IsT7D9JeFCE7dyGzDUkE9FmIP/AGS8/AcrwWg3LWc2sk54xKXax1NJhhEbT+ntTOZ\n\tV5HzoHIZH/A3WzQnIu0iLwMpkJKGoEueP/byH9SsnwAdb7Ck++IgjRKJ29NEhfFZOQN1PVcBHV3\n\tvT6JDXTj/rU0RCwPLvuFa4ame2RhA08meJ7K9I1/zK0OHuLX/Anj0N8UOKBBC78naZZdTC/6qHS\n\tFDIgSFhp2qPkRsRUUONucC/faCm20KPsAXz4KkktpJ0he0lXRT+cIiAsLof+fOc+yYWpNbNkgWe\n\tr49SCWAuVGF8SkNgI9cYJ0w29v4+xM+ppiXmpPnMTKnFP31a6cYRU3pzxR0VVa3nZOHdzgcbQ6K\n\tmsb8VNYFM2stkghWGzuVaH8MkDjgH6tAWpzPOZMW5f1M4CQjIP1WKYmtZTtB/w9+IvJ3YBQ0Wly\n\t5J2j3U94wZ86YQX9LVtQU0dRaqF0NMr5P/YblnbuBeouoXF3MVpCYPS3+WqNayBwkcJZoTolF6Q\n\tFB17j3QxpAZx+WA==", "X-Developer-Key": "i=jacopo.mondi@ideasonboard.com; a=openpgp;\n\tfpr=72392EDC88144A65C701EA9BA5826A2587AD026B", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.29", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Rename ControlValueView to ControlValue in the whole codebase in\norder to make the libcamera type ControlValue a read-only view over\ncontrol values stored somewhere else.\n\nUsage of this view-like ControlValue class in public API allows to\nprovide the ControlList class with:\n\n\tconst ControlValue get(unsigned int id) const;\n\nthat returns a reference to the value associated with a control id\nwithout making a copy. Similarly, access to the min/max/def members of\na ControlInfo (as well as the list of supported values) now returns\na view without copying the stored values in a temporary ControlValue.\n\nThe actual control values can be copied in the caller by using the\nalready existing\n\n\ttemplate<typename T> [[nodiscard]] auto get() const\n\nfunction.\n\nThe rename on the whole code base has not required many manual\nmodifications in order to keep it compiling. The most notable ones are:\n\n- ControlInfo::values() needs to re-create a vector in order to return\n it\n- A new\n\n\tControlList::set(unsigned int id, const ControlStorage &value)\n\n function had to be added to complement:\n\n\tvoid set(unsigned int id, const ControlValue &value);\n\n This new function serves to support direct initialization of\n controls in a control list with explicit values, in example:\n\n \tlensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE, static_cast<int32_t>(position));\n\n As a ControlValue cannot be constructed with a litterals or with\n values we need to go through a ControlStorage and then copy it to\n the control list backing storage.\n\n- The ControlSerializer class functions binarySize() and store()\n have been moved to work with views\n\n- The control_value.cpp test now actually tests ControlStorage\n\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n---\n include/libcamera/controls.h | 39 ++++++++++--------\n include/libcamera/internal/control_serializer.h | 4 +-\n src/gstreamer/gstlibcamera-controls.cpp.in | 4 +-\n src/libcamera/control_serializer.cpp | 4 +-\n src/libcamera/controls.cpp | 54 +++++++++++++++----------\n src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 4 +-\n src/libcamera/sensor/camera_sensor_legacy.cpp | 2 +-\n src/libcamera/sensor/camera_sensor_raw.cpp | 2 +-\n src/libcamera/v4l2_device.cpp | 2 +-\n src/py/libcamera/py_helpers.cpp | 4 +-\n src/py/libcamera/py_helpers.h | 2 +-\n test/serialization/serialization_test.cpp | 4 +-\n test/v4l2_videodevice/controls.cpp | 4 +-\n 13 files changed, 74 insertions(+), 55 deletions(-)", "diff": "diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h\nindex 8c531cca25538edadd08b8e1662227ba56065e40..a827b1bad9530f073acce112be3cce30f34e4404 100644\n--- a/include/libcamera/controls.h\n+++ b/include/libcamera/controls.h\n@@ -26,7 +26,7 @@\n namespace libcamera {\n \n class ControlValidator;\n-class ControlValueView;\n+class ControlValue;\n \n enum ControlType {\n \tControlTypeNone,\n@@ -162,7 +162,7 @@ public:\n \t\t value.data(), value.size(), sizeof(typename T::value_type));\n \t}\n \n-\texplicit ControlStorage(const ControlValueView &cvv);\n+\tControlStorage(const ControlValue &cvv);\n \n \t~ControlStorage();\n \n@@ -251,23 +251,23 @@ private:\n \t\t std::size_t numElements, std::size_t elementSize);\n };\n \n-class ControlValueView\n+class ControlValue\n {\n public:\n-\tconstexpr ControlValueView() noexcept\n+\tconstexpr ControlValue() noexcept\n \t\t: type_(ControlTypeNone)\n \t{\n \t}\n \n-\tControlValueView(const ControlStorage &cv) noexcept\n-\t\t: ControlValueView(cv.type(), cv.isArray(), cv.numElements(),\n+\tControlValue(const ControlStorage &cv) noexcept\n+\t\t: ControlValue(cv.type(), cv.isArray(), cv.numElements(),\n \t\t\t\t reinterpret_cast<const std::byte *>(cv.data().data()))\n \t{\n \t}\n \n #ifndef __DOXYGEN__\n \t// TODO: should have restricted access?\n-\tControlValueView(ControlType type, bool isArray, std::size_t numElements,\n+\tControlValue(ControlType type, bool isArray, std::size_t numElements,\n \t\t\t const std::byte *data) noexcept\n \t\t: type_(type), isArray_(isArray), numElements_(numElements),\n \t\t data_(data)\n@@ -283,9 +283,9 @@ public:\n \t[[nodiscard]] std::size_t numElements() const { return numElements_; }\n \t[[nodiscard]] Span<const std::byte> data() const;\n \n-\t[[nodiscard]] bool operator==(const ControlValueView &other) const;\n+\t[[nodiscard]] bool operator==(const ControlValue &other) const;\n \n-\t[[nodiscard]] bool operator!=(const ControlValueView &other) const\n+\t[[nodiscard]] bool operator!=(const ControlValue &other) const\n \t{\n \t\treturn !(*this == other);\n \t}\n@@ -313,7 +313,7 @@ private:\n \tconst std::byte *data_ = nullptr;\n };\n \n-std::ostream &operator<<(std::ostream &s, const ControlValueView &v);\n+std::ostream &operator<<(std::ostream &s, const ControlValue &v);\n \n class ControlId\n {\n@@ -405,10 +405,16 @@ public:\n \texplicit ControlInfo(std::set<bool> values, bool def);\n \texplicit ControlInfo(bool value);\n \n-\tconst ControlStorage &min() const { return min_; }\n-\tconst ControlStorage &max() const { return max_; }\n-\tconst ControlStorage &def() const { return def_; }\n-\tconst std::vector<ControlStorage> &values() const { return values_; }\n+\tconst ControlValue min() const { return min_; }\n+\tconst ControlValue max() const { return max_; }\n+\tconst ControlValue def() const { return def_; }\n+\n+\tconst std::vector<ControlValue> values() const {\n+\t\tstd::vector<ControlValue> values;\n+\t\tfor (const auto &val : values_)\n+\t\t\tvalues.emplace_back(val);\n+\t\treturn values;\n+\t}\n \n \tstd::string toString() const;\n \n@@ -513,7 +519,7 @@ public:\n \t\tif (entry == controls_.end())\n \t\t\treturn std::nullopt;\n \n-\t\tconst ControlStorage &val = entry->second;\n+\t\tconst ControlValue val = entry->second;\n \t\treturn val.get<T>();\n \t}\n \n@@ -537,7 +543,8 @@ public:\n \t\tval->set(Span<const typename std::remove_cv_t<V>, Size>{ value.begin(), value.size() });\n \t}\n \n-\tconst ControlStorage &get(unsigned int id) const;\n+\tconst ControlValue get(unsigned int id) const;\n+\tvoid set(unsigned int id, const ControlValue &value);\n \tvoid set(unsigned int id, const ControlStorage &value);\n \n \tconst ControlInfoMap *infoMap() const { return infoMap_; }\ndiff --git a/include/libcamera/internal/control_serializer.h b/include/libcamera/internal/control_serializer.h\nindex a63f8675e3076eddfdda8c7b684499237451596b..9b22c30a6ff34dae3bcff4219745dc0bcf90ae75 100644\n--- a/include/libcamera/internal/control_serializer.h\n+++ b/include/libcamera/internal/control_serializer.h\n@@ -41,10 +41,10 @@ public:\n \tbool isCached(const ControlInfoMap &infoMap);\n \n private:\n-\tstatic size_t binarySize(const ControlStorage &value);\n+\tstatic size_t binarySize(const ControlValue &value);\n \tstatic size_t binarySize(const ControlInfo &info);\n \n-\tstatic void store(const ControlStorage &value, ByteStreamBuffer &buffer);\n+\tstatic void store(const ControlValue &value, ByteStreamBuffer &buffer);\n \tstatic void store(const ControlInfo &info, ByteStreamBuffer &buffer);\n \n \tControlStorage loadControlValue(ByteStreamBuffer &buffer,\ndiff --git a/src/gstreamer/gstlibcamera-controls.cpp.in b/src/gstreamer/gstlibcamera-controls.cpp.in\nindex 346bf83fac076c8fa7c7d6f8a9b281626849aaa1..2a16b39a93d95938022b38c57aab74efa10678cf 100644\n--- a/src/gstreamer/gstlibcamera-controls.cpp.in\n+++ b/src/gstreamer/gstlibcamera-controls.cpp.in\n@@ -159,7 +159,7 @@ bool GstCameraControls::getProperty(guint propId, GValue *value,\n \t\t\t controls::controls.at(propId)->name().c_str());\n \t\treturn true;\n \t}\n-\tconst ControlStorage &cv = controls_acc_.get(propId);\n+\tconst ControlValue &cv = controls_acc_.get(propId);\n \n \tswitch (propId) {\n {%- for vendor, ctrls in controls %}\n@@ -296,7 +296,7 @@ void GstCameraControls::setCamera(const std::shared_ptr<libcamera::Camera> &cam)\n \t control != controls_acc_.end();\n \t ++control) {\n \t\tunsigned int id = control->first;\n-\t\tControlStorage value = control->second;\n+\t\tControlValue value = control->second;\n \n \t\tconst ControlId *cid = capabilities_.idmap().at(id);\n \t\tauto info = capabilities_.find(cid);\ndiff --git a/src/libcamera/control_serializer.cpp b/src/libcamera/control_serializer.cpp\nindex df8bcd8a938c6fd3db252ae56673483fa9923b7d..10f7c0cbacae5937eab53da60a405d0f88a6d57d 100644\n--- a/src/libcamera/control_serializer.cpp\n+++ b/src/libcamera/control_serializer.cpp\n@@ -142,7 +142,7 @@ void ControlSerializer::reset()\n \tcontrolIdMaps_.clear();\n }\n \n-size_t ControlSerializer::binarySize(const ControlStorage &value)\n+size_t ControlSerializer::binarySize(const ControlValue &value)\n {\n \treturn sizeof(ControlType) + value.data().size_bytes();\n }\n@@ -192,7 +192,7 @@ size_t ControlSerializer::binarySize(const ControlList &list)\n \treturn size;\n }\n \n-void ControlSerializer::store(const ControlStorage &value,\n+void ControlSerializer::store(const ControlValue &value,\n \t\t\t ByteStreamBuffer &buffer)\n {\n \tconst ControlType type = value.type();\ndiff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp\nindex cdc4f12d1048d58c558feaa8a17b25814d2dae13..9043b3407d8ebd28a822c2089da44b7897c6f153 100644\n--- a/src/libcamera/controls.cpp\n+++ b/src/libcamera/controls.cpp\n@@ -107,9 +107,9 @@ ControlStorage::ControlStorage()\n }\n \n /**\n- * \\brief Construct a ControlStorage from a ControlValueView\n+ * \\brief Construct a ControlStorage from a ControlValue\n */\n-ControlStorage::ControlStorage(const ControlValueView &cvv)\n+ControlStorage::ControlStorage(const ControlValue &cvv)\n \t: ControlStorage()\n {\n \tset(cvv.type(), cvv.isArray(), cvv.data().data(),\n@@ -223,7 +223,7 @@ Span<uint8_t> ControlStorage::data()\n */\n std::string ControlStorage::toString() const\n {\n-\treturn static_cast<std::ostringstream&&>(std::ostringstream{} << ControlValueView(*this)).str();\n+\treturn static_cast<std::ostringstream&&>(std::ostringstream{} << ControlValue(*this)).str();\n }\n \n /**\n@@ -329,18 +329,18 @@ void ControlStorage::reserve(ControlType type, bool isArray, std::size_t numElem\n }\n \n /**\n- * \\class ControlValueView\n+ * \\class ControlValue\n * \\brief A non-owning view-like type to the value of a control\n */\n \n /**\n- * \\fn ControlValueView::ControlValueView()\n+ * \\fn ControlValue::ControlValue()\n * \\brief Construct an empty view\n * \\sa ControlStorage::ControlStorage()\n */\n \n /**\n- * \\fn ControlValueView::ControlValueView(const ControlStorage &v)\n+ * \\fn ControlValue::ControlValue(const ControlStorage &v)\n * \\brief Construct a view referring to \\a v\n *\n * The constructed view will refer to the value stored by \\a v, and\n@@ -350,31 +350,31 @@ void ControlStorage::reserve(ControlType type, bool isArray, std::size_t numElem\n */\n \n /**\n- * \\fn ControlValueView::operator bool() const\n+ * \\fn ControlValue::operator bool() const\n * \\brief Determine if the referred value is valid\n- * \\sa ControlValueView::isNone()\n+ * \\sa ControlValue::isNone()\n */\n \n /**\n- * \\fn ControlType ControlValueView::type() const\n+ * \\fn ControlType ControlValue::type() const\n * \\copydoc ControlStorage::type()\n * \\sa ControlStorage::type()\n */\n \n /**\n- * \\fn ControlValueView::isNone() const\n+ * \\fn ControlValue::isNone() const\n * \\copydoc ControlStorage::isNone()\n * \\sa ControlStorage::isNone()\n */\n \n /**\n- * \\fn ControlValueView::isArray() const\n+ * \\fn ControlValue::isArray() const\n * \\copydoc ControlStorage::isArray()\n * \\sa ControlStorage::isArray()\n */\n \n /**\n- * \\fn ControlValueView::numElements() const\n+ * \\fn ControlValue::numElements() const\n * \\copydoc ControlStorage::numElements()\n * \\sa ControlStorage::numElements()\n */\n@@ -383,7 +383,7 @@ void ControlStorage::reserve(ControlType type, bool isArray, std::size_t numElem\n * \\copydoc ControlStorage::data()\n * \\sa ControlStorage::data()\n */\n-Span<const std::byte> ControlValueView::data() const\n+Span<const std::byte> ControlValue::data() const\n {\n \treturn { data_, numElements_ * ControlValueSize[type_] };\n }\n@@ -391,9 +391,9 @@ Span<const std::byte> ControlValueView::data() const\n /**\n * \\copydoc ControlStorage::operator==()\n * \\sa ControlStorage::operator==()\n- * \\sa ControlValueView::operator!=()\n+ * \\sa ControlValue::operator!=()\n */\n-bool ControlValueView::operator==(const ControlValueView &other) const\n+bool ControlValue::operator==(const ControlValue &other) const\n {\n \tif (type_ != other.type_)\n \t\treturn false;\n@@ -410,14 +410,14 @@ bool ControlValueView::operator==(const ControlValueView &other) const\n }\n \n /**\n- * \\fn ControlValueView::operator!=() const\n+ * \\fn ControlValue::operator!=() const\n * \\copydoc ControlStorage::operator!=()\n * \\sa ControlStorage::operator!=()\n- * \\sa ControlValueView::operator==()\n+ * \\sa ControlValue::operator==()\n */\n \n /**\n- * \\fn template<typename T> T ControlValueView::get() const\n+ * \\fn template<typename T> T ControlValue::get() const\n * \\copydoc ControlStorage::get()\n * \\sa ControlStorage::get()\n */\n@@ -426,7 +426,7 @@ bool ControlValueView::operator==(const ControlValueView &other) const\n * \\brief Insert a text representation of a value into an output stream\n * \\sa ControlStorage::toString()\n */\n-std::ostream &operator<<(std::ostream &s, const ControlValueView &v)\n+std::ostream &operator<<(std::ostream &s, const ControlValue &v)\n {\n \tconst auto type = v.type();\n \tif (type == ControlTypeNone)\n@@ -1234,7 +1234,7 @@ bool ControlList::contains(unsigned int id) const\n *\n * \\return The control value\n */\n-const ControlStorage &ControlList::get(unsigned int id) const\n+const ControlValue ControlList::get(unsigned int id) const\n {\n \tstatic const ControlStorage zero;\n \n@@ -1257,7 +1257,7 @@ const ControlStorage &ControlList::get(unsigned int id) const\n * The behaviour is undefined if the control \\a id is not supported by the\n * object that the list refers to.\n */\n-void ControlList::set(unsigned int id, const ControlStorage &value)\n+void ControlList::set(unsigned int id, const ControlValue &value)\n {\n \tControlStorage *val = find(id);\n \tif (!val)\n@@ -1266,6 +1266,18 @@ void ControlList::set(unsigned int id, const ControlStorage &value)\n \t*val = value;\n }\n \n+/**\n+ * \\brief Set the value of control \\a id to \\a value\n+ * \\copydoc ControlList::set(unsigned int id, const ControlValue &value)\n+ */\n+void ControlList::set(unsigned int id, const ControlStorage &value)\n+{\n+\tControlStorage *val = find(id);\n+\tif (!val)\n+\t\treturn;\n+\n+\t*val = value;\n+}\n /**\n * \\fn ControlList::infoMap()\n * \\brief Retrieve the ControlInfoMap used to construct the ControlList\ndiff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\nindex 627aa69be294d89f796cfac148c315b29d6de633..a166b0bc4a51f6b81ccb7f0dd98dfe6a30b235e6 100644\n--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp\n@@ -721,7 +721,7 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,\n \t}\n \n \t/* Map the control info. */\n-\tconst std::vector<ControlStorage> &v4l2Values = v4l2Info.values();\n+\tconst std::vector<ControlValue> &v4l2Values = v4l2Info.values();\n \tint32_t min = v4l2Info.min().get<int32_t>();\n \tint32_t max = v4l2Info.max().get<int32_t>();\n \tint32_t def = v4l2Info.def().get<int32_t>();\n@@ -793,7 +793,7 @@ void UVCCameraData::addControl(uint32_t cid, const ControlInfo &v4l2Info,\n \t\t> exposureModes;\n \t\tstd::optional<controls::ExposureTimeModeEnum> lcDef;\n \n-\t\tfor (const ControlStorage &value : v4l2Values) {\n+\t\tfor (const ControlValue value : v4l2Values) {\n \t\t\tconst auto x = value.get<int32_t>();\n \n \t\t\tif (0 <= x && static_cast<std::size_t>(x) < exposureModes.size()) {\ndiff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp\nindex 366a66880ff0525b8198acccdaca946da538faad..f269b07eff51c48c2ac64b7a080eff3e7575c122 100644\n--- a/src/libcamera/sensor/camera_sensor_legacy.cpp\n+++ b/src/libcamera/sensor/camera_sensor_legacy.cpp\n@@ -538,7 +538,7 @@ void CameraSensorLegacy::initTestPatternModes()\n \tfor (const auto &it : testPatternModes)\n \t\tindexToTestPatternMode[it.second] = it.first;\n \n-\tfor (const ControlStorage &value : v4l2TestPattern->second.values()) {\n+\tfor (const ControlValue value : v4l2TestPattern->second.values()) {\n \t\tconst int32_t index = value.get<int32_t>();\n \n \t\tconst auto it = indexToTestPatternMode.find(index);\ndiff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp\nindex fc41ee1b71c360c7e1b2ac1aed15a44c277ad7a1..d7aefd0b198401c73a7b8bd5b5dc690acf725758 100644\n--- a/src/libcamera/sensor/camera_sensor_raw.cpp\n+++ b/src/libcamera/sensor/camera_sensor_raw.cpp\n@@ -720,7 +720,7 @@ void CameraSensorRaw::initTestPatternModes()\n \tfor (const auto &it : testPatternModes)\n \t\tindexToTestPatternMode[it.second] = it.first;\n \n-\tfor (const ControlStorage &value : v4l2TestPattern->second.values()) {\n+\tfor (const ControlValue value : v4l2TestPattern->second.values()) {\n \t\tconst int32_t index = value.get<int32_t>();\n \n \t\tconst auto it = indexToTestPatternMode.find(index);\ndiff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\nindex 9be9df78416d8a5a4c6891b2926fcea41f808233..3d187ba5eed293e43b0d532310f00c81acf5a952 100644\n--- a/src/libcamera/v4l2_device.cpp\n+++ b/src/libcamera/v4l2_device.cpp\n@@ -189,7 +189,7 @@ ControlList V4L2Device::getControls(const std::vector<uint32_t> &ids)\n \t\t\treturn {};\n \t\t}\n \n-\t\tctrls.set(id, {});\n+\t\tctrls.set(id, ControlStorage{});\n \t}\n \n \tstd::vector<v4l2_ext_control> v4l2Ctrls(ids.size());\ndiff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp\nindex 75283396b1dca7b5e16695e11630496cf1104e3a..bd269745a6dc41cc22d4ac0a8f79f1017e130bb2 100644\n--- a/src/py/libcamera/py_helpers.cpp\n+++ b/src/py/libcamera/py_helpers.cpp\n@@ -16,7 +16,7 @@ namespace py = pybind11;\n using namespace libcamera;\n \n template<typename T>\n-static py::object valueOrTuple(const ControlStorage &cv)\n+static py::object valueOrTuple(const ControlValue &cv)\n {\n \tif (cv.isArray()) {\n \t\tconst T *v = reinterpret_cast<const T *>(cv.data().data());\n@@ -31,7 +31,7 @@ static py::object valueOrTuple(const ControlStorage &cv)\n \treturn py::cast(cv.get<T>());\n }\n \n-py::object controlValueToPy(const ControlStorage &cv)\n+py::object controlValueToPy(const ControlValue &cv)\n {\n \tswitch (cv.type()) {\n \tcase ControlTypeNone:\ndiff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h\nindex 47a0ee462c3c3396504c22a99173d83b0d549366..a7dd565e9e64ca3a1fd7d008da96619fac8374fe 100644\n--- a/src/py/libcamera/py_helpers.h\n+++ b/src/py/libcamera/py_helpers.h\n@@ -9,5 +9,5 @@\n \n #include <pybind11/pybind11.h>\n \n-pybind11::object controlValueToPy(const libcamera::ControlStorage &cv);\n+pybind11::object controlValueToPy(const libcamera::ControlValue &cv);\n libcamera::ControlStorage pyToControlValue(const pybind11::object &ob, libcamera::ControlType type);\ndiff --git a/test/serialization/serialization_test.cpp b/test/serialization/serialization_test.cpp\nindex 4b5188972deed3f473f75527fb279148a1d52c40..9d2e282281db69d5188c4521d9127d951a45f3b6 100644\n--- a/test/serialization/serialization_test.cpp\n+++ b/test/serialization/serialization_test.cpp\n@@ -78,12 +78,12 @@ bool SerializationTest::equals(const ControlList &lhs, const ControlList &rhs)\n \tcerr << \"lhs:\" << endl;\n \tfor (const auto &value : rlhs)\n \t\tcerr << \"- \" << value.first << \": \"\n-\t\t << value.second.toString() << endl;\n+\t\t << value.second << endl;\n \n \tcerr << \"rhs:\" << endl;\n \tfor (const auto &value : rrhs)\n \t\tcerr << \"- \" << value.first << \": \"\n-\t\t << value.second.toString() << endl;\n+\t\t << value.second << endl;\n \n \treturn false;\n }\ndiff --git a/test/v4l2_videodevice/controls.cpp b/test/v4l2_videodevice/controls.cpp\nindex b0130295e47caddc4d9b85f61a89e1405694b89b..1f3d672b91cad2d14c04114cc6f971c8dc72ce34 100644\n--- a/test/v4l2_videodevice/controls.cpp\n+++ b/test/v4l2_videodevice/controls.cpp\n@@ -86,7 +86,7 @@ protected:\n \t\t * The VIVID_CID_INTEGER64 control can take any value, just test\n \t\t * that its value can be retrieved and has the right type.\n \t\t */\n-\t\tctrls.get(VIVID_CID_INTEGER64).get<int64_t>();\n+\t\t(void)ctrls.get(VIVID_CID_INTEGER64).get<int64_t>();\n \n \t\tuint8_t u8Min = u8.min().get<uint8_t>();\n \t\tuint8_t u8Max = u8.max().get<uint8_t>();\n@@ -129,7 +129,7 @@ protected:\n \n \t\tif (ctrls.get(V4L2_CID_BRIGHTNESS) != brightness.min() ||\n \t\t ctrls.get(V4L2_CID_CONTRAST) != contrast.max() ||\n-\t\t ctrls.get(V4L2_CID_SATURATION) != saturation.min().get<int32_t>() + 1) {\n+\t\t ctrls.get(V4L2_CID_SATURATION).get<int32_t>() != saturation.min().get<int32_t>() + 1) {\n \t\t\tcerr << \"Controls not updated when set\" << endl;\n \t\t\treturn TestFail;\n \t\t}\n", "prefixes": [ "3/3" ] }