From patchwork Mon Jul 1 20:14:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1560 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CF2206157D for ; Mon, 1 Jul 2019 22:15:28 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6D09F1200 for ; Mon, 1 Jul 2019 22:15:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012128; bh=iiCXQgE/DuJHRcxh/gxNdbNgqY6dmgSnDSoeoDugz1c=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Be9UUuWmGcPJIiUnRScfxp/Luy0CHe3Ii1SD0lY2YjdttDGkQLJp7GUTt8LMdR4N1 w/tlGSv8TuUT86cLpON7DebluYGKEpH3I5ywhW8dHZkcCVkKx3wOZO78tGIbQxvK0A hrjudmi4awC21/32Pj3vAc5PApcqL3kdokPn/U/w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:52 +0300 Message-Id: <20190701201504.28487-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/13] libcamera: v4l2_controls: Add min and max to V4L2ControlInfo X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:29 -0000 Add min() and max() methods to V4L2ControlInfo to report the control's minimum and maximum value respectively. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- src/libcamera/include/v4l2_controls.h | 6 ++++++ src/libcamera/v4l2_controls.cpp | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 2c8cb9003f25..0047efab11fa 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -28,11 +28,17 @@ public: size_t size() const { return size_; } const std::string &name() const { return name_; } + int64_t min() const { return min_; } + int64_t max() const { return max_; } + private: unsigned int id_; unsigned int type_; size_t size_; std::string name_; + + int64_t min_; + int64_t max_; }; class V4L2Control diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index 78888de29642..af017bce48ba 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -74,6 +74,8 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) type_ = ctrl.type; name_ = static_cast(ctrl.name); size_ = ctrl.elem_size * ctrl.elems; + min_ = ctrl.minimum; + max_ = ctrl.maximum; } /** @@ -100,6 +102,18 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) * \return The V4L2 control user readable name */ +/** + * \fn V4L2ControlInfo::min() + * \brief Retrieve the control minimum value + * \return The V4L2 control minimum value + */ + +/** + * \fn V4L2ControlInfo::max() + * \brief Retrieve the control maximum value + * \return The V4L2 control maximum value + */ + /** * \class V4L2Control * \brief A V4L2 control value From patchwork Mon Jul 1 20:14:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1561 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0EE236157D for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B2E8B120A for ; Mon, 1 Jul 2019 22:15:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012128; bh=r4GlBeFbCtEwZuFYOy++W3PzOUZo4tKOrRSt+OvtyX4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=BtCYWTZPMt9i1pIR8+OY7sI+6kWoK4y6KBFvwjZIgdwROAZpkIV+DKK/ayPRe5KmW 6D57b1HUso5kEfs3/HAuQYbyUgu4r64ZjNXW3tFU49OowiTSdaRT94TvSIw/qM/gWe 5+RvGTKoD/vTYzozxQyQ6I7T42Yd87GPJixNdAF8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:53 +0300 Message-Id: <20190701201504.28487-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/13] libcamera: v4l2_device: Add method to retrieve all supported controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:29 -0000 Add a new controls() method to the V4L2Device class to retrieve the map of all supported controls. This is needed in order to dynamically query the supported controls, for instance for drivers that support different sets of controls depending on the device model. To make the API easier to use, create a type alias for the control ID to ControlInfo and use it. Remove the getControlInfo() method that is not used externally, as it can now be replaced by accessing the full list of controls. Update the CameraSensor API accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- src/libcamera/camera_sensor.cpp | 10 ++++------ src/libcamera/include/camera_sensor.h | 5 ++--- src/libcamera/include/v4l2_controls.h | 6 ++++-- src/libcamera/include/v4l2_device.h | 9 ++++----- src/libcamera/v4l2_controls.cpp | 5 +++++ src/libcamera/v4l2_device.cpp | 25 +++++++++---------------- 6 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 471c3e2e6e47..a7670b449b31 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -248,14 +248,12 @@ int CameraSensor::setFormat(V4L2SubdeviceFormat *format) } /** - * \brief Retrieve information about a control - * \param[in] id The control ID - * \return A pointer to the V4L2ControlInfo for control \a id, or nullptr - * if the sensor doesn't have such a control + * \brief Retrieve the supported V4L2 controls and their information + * \return A map of the V4L2 controls supported by the sensor */ -const V4L2ControlInfo *CameraSensor::getControlInfo(unsigned int id) const +const V4L2ControlInfoMap &CameraSensor::controls() const { - return subdev_->getControlInfo(id); + return subdev_->controls(); } /** diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h index b42e7b8e1343..fe033fb374c1 100644 --- a/src/libcamera/include/camera_sensor.h +++ b/src/libcamera/include/camera_sensor.h @@ -13,12 +13,11 @@ #include #include "log.h" +#include "v4l2_controls.h" namespace libcamera { class MediaEntity; -class V4L2ControlInfo; -class V4L2ControlList; class V4L2Subdevice; struct V4L2SubdeviceFormat; @@ -43,7 +42,7 @@ public: const Size &size) const; int setFormat(V4L2SubdeviceFormat *format); - const V4L2ControlInfo *getControlInfo(unsigned int id) const; + const V4L2ControlInfoMap &controls() const; int getControls(V4L2ControlList *ctrls); int setControls(V4L2ControlList *ctrls); diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h index 0047efab11fa..10b726504951 100644 --- a/src/libcamera/include/v4l2_controls.h +++ b/src/libcamera/include/v4l2_controls.h @@ -8,11 +8,11 @@ #ifndef __LIBCAMERA_V4L2_CONTROLS_H__ #define __LIBCAMERA_V4L2_CONTROLS_H__ +#include +#include #include #include -#include - #include #include @@ -41,6 +41,8 @@ private: int64_t max_; }; +using V4L2ControlInfoMap = std::map; + class V4L2Control { public: diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 24a0134a2cba..e7e9829cb05f 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -13,19 +13,18 @@ #include #include "log.h" +#include "v4l2_controls.h" namespace libcamera { -class V4L2ControlInfo; -class V4L2ControlList; - class V4L2Device : protected Loggable { public: void close(); bool isOpen() const { return fd_ != -1; } - const V4L2ControlInfo *getControlInfo(unsigned int id) const; + const V4L2ControlInfoMap &controls() const { return controls_; } + int getControls(V4L2ControlList *ctrls); int setControls(V4L2ControlList *ctrls); @@ -48,7 +47,7 @@ private: const struct v4l2_ext_control *v4l2Ctrls, unsigned int count); - std::map controls_; + V4L2ControlInfoMap controls_; std::string deviceNode_; int fd_; }; diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp index af017bce48ba..84258d9954d0 100644 --- a/src/libcamera/v4l2_controls.cpp +++ b/src/libcamera/v4l2_controls.cpp @@ -114,6 +114,11 @@ V4L2ControlInfo::V4L2ControlInfo(const struct v4l2_query_ext_ctrl &ctrl) * \return The V4L2 control maximum value */ +/** + * \typedef V4L2ControlInfoMap + * \brief A map of control ID to V4L2ControlInfo + */ + /** * \class V4L2Control * \brief A V4L2 control value diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 06939dead705..e3ec44a7f156 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -111,19 +111,10 @@ void V4L2Device::close() */ /** - * \brief Retrieve information about a control - * \param[in] id The control ID - * \return A pointer to the V4L2ControlInfo for control \a id, or nullptr - * if the device doesn't have such a control + * \fn V4L2Device::controls() + * \brief Retrieve the supported V4L2 controls and their information + * \return A map of the V4L2 controls supported by the device */ -const V4L2ControlInfo *V4L2Device::getControlInfo(unsigned int id) const -{ - auto it = controls_.find(id); - if (it == controls_.end()) - return nullptr; - - return &it->second; -} /** * \brief Read controls from the device @@ -158,13 +149,14 @@ int V4L2Device::getControls(V4L2ControlList *ctrls) for (unsigned int i = 0; i < count; ++i) { const V4L2Control *ctrl = ctrls->getByIndex(i); - const V4L2ControlInfo *info = getControlInfo(ctrl->id()); - if (!info) { + const auto iter = controls_.find(ctrl->id()); + if (iter == controls_.end()) { LOG(V4L2, Error) << "Control '" << ctrl->id() << "' not found"; return -EINVAL; } + const V4L2ControlInfo *info = &iter->second; controlInfo[i] = info; v4l2Ctrls[i].id = info->id(); } @@ -232,13 +224,14 @@ int V4L2Device::setControls(V4L2ControlList *ctrls) for (unsigned int i = 0; i < count; ++i) { const V4L2Control *ctrl = ctrls->getByIndex(i); - const V4L2ControlInfo *info = getControlInfo(ctrl->id()); - if (!info) { + const auto iter = controls_.find(ctrl->id()); + if (iter == controls_.end()) { LOG(V4L2, Error) << "Control '" << ctrl->id() << "' not found"; return -EINVAL; } + const V4L2ControlInfo *info = &iter->second; controlInfo[i] = info; v4l2Ctrls[i].id = info->id(); From patchwork Mon Jul 1 20:14:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1562 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 59E436157D for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 050F2524 for ; Mon, 1 Jul 2019 22:15:28 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012129; bh=fePYzODQtkZ+kFnmU1Nd6sET7nbOKwIFlU1YHIYKYAs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XfcC+EZPFUdA8QuFwY2G7dyAN/Np2d8XPK8LYe50Rpf2znz+7AO6w7Cufmuyui7b1 CyU9HcFWFfPIY16ugcCVsEz71M6ebdrj+Jppl9Bven76pSbPxnLaf4lI8GcPqZOJuW 77z837CHuj4Yc3zmf7KP6tTFnnrhoju2K3yAJCdE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:54 +0300 Message-Id: <20190701201504.28487-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/13] libcamera: controls: Introduce control-related data types X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:29 -0000 From: Kieran Bingham Add a set of data types to support controls: - ControlValue stores a control type and value in a generic way - ControlId enumerates all the control identifiers - ControlIdentifier declares the types of a control and map their names - ControlInfo stores runtime information for controls - ControlList contains a set of control info and value pairs The control definitions map is generated from the controls documentation to ensure that the two will always be synchronised. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Niklas Söderlund --- Changes since v3: - Typo fixes - Optimized the contains() implementation - Various documentation updates Changes since v2: - Squashed "Provide ControlValue class" - Renamed Value to ControlValue - Removed operator<<() - Added control table generation - Moved control definitions to control_definitions.h - Renamed ControlTypes to controlTypes and make it const - Moved the initial controls list to a separate patch - Renamed control_definitions.h to control_ids.h and control_definitions.cpp to control_types.cpp to match the contained enum and variable name respectively - Indexed ControlList by ControlInfo pointer instead of value - Replaced ControlInfoHash with std::hash specialisation - Added automatic conversion between 32- and 64-bit integer values The automatic conversion between integer types was prompted by an assertion failure due to the use of getInt() on the min() and max() value of an Integer control. The min and max ControlValue instances are create as Integer64, due to the V4L2ControlInfo class returning the range as int64_t. This may need to be reworked. --- Documentation/Doxyfile.in | 3 +- include/libcamera/control_ids.h | 35 +++ include/libcamera/controls.h | 134 ++++++++++ include/libcamera/meson.build | 2 + src/libcamera/controls.cpp | 451 ++++++++++++++++++++++++++++++++ src/libcamera/gen-controls.awk | 106 ++++++++ src/libcamera/meson.build | 11 + 7 files changed, 741 insertions(+), 1 deletion(-) create mode 100644 include/libcamera/control_ids.h create mode 100644 include/libcamera/controls.h create mode 100644 src/libcamera/controls.cpp create mode 100755 src/libcamera/gen-controls.awk diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in index c58631200dd5..9ca32241b895 100644 --- a/Documentation/Doxyfile.in +++ b/Documentation/Doxyfile.in @@ -868,7 +868,8 @@ EXCLUDE_SYMBOLS = libcamera::SignalBase \ libcamera::SlotArgs \ libcamera::SlotBase \ libcamera::SlotMember \ - libcamera::SlotStatic + libcamera::SlotStatic \ + std::* # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include diff --git a/include/libcamera/control_ids.h b/include/libcamera/control_ids.h new file mode 100644 index 000000000000..d0e700da9844 --- /dev/null +++ b/include/libcamera/control_ids.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_ids.h : Control ID list + */ + +#ifndef __LIBCAMERA_CONTROL_IDS_H__ +#define __LIBCAMERA_CONTROL_IDS_H__ + +#include + +namespace libcamera { + +enum ControlId { +}; + +} /* namespace libcamera */ + +namespace std { + +template<> +struct hash { + using argument_type = libcamera::ControlId; + using result_type = std::size_t; + + result_type operator()(const argument_type &key) const noexcept + { + return std::hash::type>()(key); + } +}; + +} /* namespace std */ + +#endif // __LIBCAMERA_CONTROL_IDS_H__ diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h new file mode 100644 index 000000000000..2206155909ca --- /dev/null +++ b/include/libcamera/controls.h @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * controls.h - Control handling + */ + +#ifndef __LIBCAMERA_CONTROLS_H__ +#define __LIBCAMERA_CONTROLS_H__ + +#include +#include +#include + +#include + +namespace libcamera { + +class Camera; + +enum ControlValueType { + ControlValueNone, + ControlValueBool, + ControlValueInteger, + ControlValueInteger64, +}; + +class ControlValue +{ +public: + ControlValue(); + ControlValue(bool value); + ControlValue(int value); + ControlValue(int64_t value); + + ControlValueType type() const { return type_; }; + bool isNone() const { return type_ == ControlValueNone; }; + + void set(bool value); + void set(int value); + void set(int64_t value); + + bool getBool() const; + int getInt() const; + int64_t getInt64() const; + + std::string toString() const; + +private: + ControlValueType type_; + + union { + bool bool_; + int integer_; + int64_t integer64_; + }; +}; + +struct ControlIdentifier { + ControlId id; + const char *name; + ControlValueType type; +}; + +class ControlInfo +{ +public: + explicit ControlInfo(ControlId id, const ControlValue &min = 0, + const ControlValue &max = 0); + + ControlId id() const { return ident_->id; } + const char *name() const { return ident_->name; } + ControlValueType type() const { return ident_->type; } + + const ControlValue &min() const { return min_; } + const ControlValue &max() const { return max_; } + + std::string toString() const; + +private: + const struct ControlIdentifier *ident_; + ControlValue min_; + ControlValue max_; +}; + +bool operator==(const ControlInfo &lhs, const ControlInfo &rhs); +bool operator==(const ControlId &lhs, const ControlInfo &rhs); +bool operator==(const ControlInfo &lhs, const ControlId &rhs); +static inline bool operator!=(const ControlInfo &lhs, const ControlInfo &rhs) +{ + return !(lhs == rhs); +} +static inline bool operator!=(const ControlId &lhs, const ControlInfo &rhs) +{ + return !(lhs == rhs); +} +static inline bool operator!=(const ControlInfo &lhs, const ControlId &rhs) +{ + return !(lhs == rhs); +} + +class ControlList +{ +private: + using ControlListMap = std::unordered_map; + +public: + ControlList(Camera *camera); + + using iterator = ControlListMap::iterator; + using const_iterator = ControlListMap::const_iterator; + + iterator begin() { return controls_.begin(); } + iterator end() { return controls_.end(); } + const_iterator begin() const { return controls_.begin(); } + const_iterator end() const { return controls_.end(); } + + bool contains(const ControlInfo *info) const; + bool empty() const { return controls_.empty(); } + std::size_t size() const { return controls_.size(); } + void clear() { controls_.clear(); } + + ControlValue &operator[](const ControlInfo *info) { return controls_[info]; } + + void update(const ControlList &list); + +private: + Camera *camera_; + ControlListMap controls_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CONTROLS_H__ */ diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 15484724df01..3067120a1598 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -2,6 +2,8 @@ libcamera_api = files([ 'buffer.h', 'camera.h', 'camera_manager.h', + 'control_ids.h', + 'controls.h', 'event_dispatcher.h', 'event_notifier.h', 'geometry.h', diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp new file mode 100644 index 000000000000..7fac1169cbfd --- /dev/null +++ b/src/libcamera/controls.cpp @@ -0,0 +1,451 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * controls.cpp - Control handling + */ + +#include + +#include +#include + +#include "log.h" +#include "utils.h" + +/** + * \file controls.h + * \brief Describes control framework and controls supported by a camera + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(Controls) + +/** + * \enum ControlValueType + * \brief Define the data type of value represented by a ControlValue + * \var ControlValueNone + * Identifies an unset control value + * \var ControlValueBool + * Identifies controls storing a boolean value + * \var ControlValueInteger + * Identifies controls storing an integer value + * \var ControlValueInteger64 + * Identifies controls storing a 64-bit integer value + */ + +/** + * \class ControlValue + * \brief Abstract type representing the value of a control + */ + +/** + * \brief Construct an empty ControlValue. + */ +ControlValue::ControlValue() + : type_(ControlValueNone) +{ +} + +/** + * \brief Construct a Boolean ControlValue + * \param[in] value Boolean value to store + */ +ControlValue::ControlValue(bool value) + : type_(ControlValueBool), bool_(value) +{ +} + +/** + * \brief Construct an integer ControlValue + * \param[in] value Integer value to store + */ +ControlValue::ControlValue(int value) + : type_(ControlValueInteger), integer_(value) +{ +} + +/** + * \brief Construct a 64 bit integer ControlValue + * \param[in] value Integer value to store + */ +ControlValue::ControlValue(int64_t value) + : type_(ControlValueInteger64), integer64_(value) +{ +} + +/** + * \fn ControlValue::type() + * \brief Retrieve the data type of the value + * \return The value data type + */ + +/** + * \fn ControlValue::isNone() + * \brief Determine if the value is not initialised + * \return True if the value type is ControlValueNone, false otherwise + */ + +/** + * \brief Set the value with a boolean + * \param[in] value Boolean value to store + */ +void ControlValue::set(bool value) +{ + type_ = ControlValueBool; + bool_ = value; +} + +/** + * \brief Set the value with an integer + * \param[in] value Integer value to store + */ +void ControlValue::set(int value) +{ + type_ = ControlValueInteger; + integer_ = value; +} + +/** + * \brief Set the value with a 64 bit integer + * \param[in] value 64 bit integer value to store + */ +void ControlValue::set(int64_t value) +{ + type_ = ControlValueInteger64; + integer64_ = value; +} + +/** + * \brief Get the boolean value + * + * The value type must be Boolean. + * + * \return The boolean value + */ +bool ControlValue::getBool() const +{ + ASSERT(type_ == ControlValueBool); + + return bool_; +} + +/** + * \brief Get the integer value + * + * The value type must be Integer or Integer64. + * + * \return The integer value + */ +int ControlValue::getInt() const +{ + ASSERT(type_ == ControlValueInteger || type_ == ControlValueInteger64); + + return integer_; +} + +/** + * \brief Get the 64-bit integer value + * + * The value type must be Integer or Integer64. + * + * \return The 64-bit integer value + */ +int64_t ControlValue::getInt64() const +{ + ASSERT(type_ == ControlValueInteger || type_ == ControlValueInteger64); + + return integer64_; +} + +/** + * \brief Assemble and return a string describing the value + * \return A string describing the ControlValue + */ +std::string ControlValue::toString() const +{ + switch (type_) { + case ControlValueNone: + return ""; + case ControlValueBool: + return bool_ ? "True" : "False"; + case ControlValueInteger: + return std::to_string(integer_); + case ControlValueInteger64: + return std::to_string(integer64_); + } + + return ""; +} + +/** + * \enum ControlId + * \brief Numerical control ID + */ + +/** + * \struct ControlIdentifier + * \brief Describe a ControlId with control specific constant meta-data + * + * Defines a Control with a unique ID, a name, and a type. + * This structure is used as static part of the auto-generated control + * definitions, which are generated from the ControlId documentation. + * + * \var ControlIdentifier::id + * The unique ID for a control + * \var ControlIdentifier::name + * The string representation of the control + * \var ControlIdentifier::type + * The ValueType required to represent the control value + */ + +/* + * The controlTypes are automatically generated to produce a control_types.cpp + * output. This file is not for public use, and so no suitable header exists + * for this sole usage of the controlTypes reference. As such the extern is + * only defined here for use during the ControlInfo constructor and should not + * be referenced directly elsewhere. + */ +extern const std::unordered_map controlTypes; + +/** + * \class ControlInfo + * \brief Describe the information and capabilities of a Control + * + * The ControlInfo represents control specific meta-data which is constant on a + * per camera basis. ControlInfo classes are constructed by pipeline handlers + * to expose the controls they support and the metadata needed to utilise those + * controls. + */ + +/** + * \brief Construct a ControlInfo with minimum and maximum range parameters + * \param[in] id The control ID + * \param[in] min The control minimum value + * \param[in] max The control maximum value + */ +ControlInfo::ControlInfo(ControlId id, const ControlValue &min, + const ControlValue &max) + : min_(min), max_(max) +{ + auto iter = controlTypes.find(id); + if (iter == controlTypes.end()) { + LOG(Controls, Fatal) << "Attempt to create invalid ControlInfo"; + return; + } + + ident_ = &iter->second; +} + +/** + * \fn ControlInfo::id() + * \brief Retrieve the control ID + * \return The control ID + */ + +/** + * \fn ControlInfo::name() + * \brief Retrieve the control name string + * \return The control name string + */ + +/** + * \fn ControlInfo::type() + * \brief Retrieve the control data type + * \return The control data type + */ + +/** + * \fn ControlInfo::min() + * \brief Retrieve the minimum value of the control + * \return A ControlValue with the minimum value for the control + */ + +/** + * \fn ControlInfo::max() + * \brief Retrieve the maximum value of the control + * \return A ControlValue with the maximum value for the control + */ + +/** + * \brief Provide a string representation of the ControlInfo + */ +std::string ControlInfo::toString() const +{ + std::stringstream ss; + + ss << name() << "[" << min_.toString() << ".." << max_.toString() << "]"; + + return ss.str(); +} + +/** + * \brief Compare control information for equality + * \param[in] lhs Left-hand side control information + * \param[in] rhs Right-hand side control information + * + * Control information is compared based on the ID only, as a camera may not + * have two separate controls with the same ID. + * + * \return True if \a lhs and \a rhs are equal, false otherwise + */ +bool operator==(const ControlInfo &lhs, const ControlInfo &rhs) +{ + return lhs.id() == rhs.id(); +} + +/** + * \brief Compare control ID and information for equality + * \param[in] lhs Left-hand side control identifier + * \param[in] rhs Right-hand side control information + * + * Control information is compared based on the ID only, as a camera may not + * have two separate controls with the same ID. + * + * \return True if \a lhs and \a rhs are equal, false otherwise + */ +bool operator==(const ControlId &lhs, const ControlInfo &rhs) +{ + return lhs == rhs.id(); +} + +/** + * \brief Compare control information and ID for equality + * \param[in] lhs Left-hand side control information + * \param[in] rhs Right-hand side control identifier + * + * Control information is compared based on the ID only, as a camera may not + * have two separate controls with the same ID. + * + * \return True if \a lhs and \a rhs are equal, false otherwise + */ +bool operator==(const ControlInfo &lhs, const ControlId &rhs) +{ + return lhs.id() == rhs; +} + +/** + * \class ControlList + * \brief Associate a list of ControlId with their values for a camera + * + * A ControlList wraps a map of ControlId to ControlValue and provide + * additional validation against the control information exposed by a Camera. + * + * A list is only valid for as long as the camera it refers to is valid. After + * that calling any method of the ControlList class other than its destructor + * will cause undefined behaviour. + */ + +/** + * \brief Construct a ControlList with a reference to the Camera it applies on + * \param[in] camera The camera + */ +ControlList::ControlList(Camera *camera) + : camera_(camera) +{ +} + +/** + * \typedef ControlList::iterator + * \brief Iterator for the controls contained within the list + */ + +/** + * \typedef ControlList::const_iterator + * \brief Const iterator for the controls contained within the list + */ + +/** + * \fn iterator ControlList::begin() + * \brief Retrieve an iterator to the first Control in the list + * \return An iterator to the first Control in the list + */ + +/** + * \fn const_iterator ControlList::begin() const + * \brief Retrieve a const_iterator to the first Control in the list + * \return A const_iterator to the first Control in the list + */ + +/** + * \fn iterator ControlList::end() + * \brief Retrieve an iterator pointing to the past-the-end control in the list + * \return An iterator to the element following the last control in the list + */ + +/** + * \fn const_iterator ControlList::end() const + * \brief Retrieve a const iterator pointing to the past-the-end control in the + * list + * \return A const iterator to the element following the last control in the + * list + */ + +/** + * \brief Check if the list contains a control with the specified \a info + * \param[in] info The control info + * \return True if the list contains a matching control, false otherwise + */ +bool ControlList::contains(const ControlInfo *info) const +{ + return controls_.find(info) != controls_.end(); +} + +/** + * \fn ControlList::empty() + * \brief Identify if the list is empty + * \return True if the list does not contain any control, false otherwise + */ + +/** + * \fn ControlList::size() + * \brief Retrieve the number of controls in the list + * \return The number of Control entries stored in the list + */ + +/** + * \fn ControlList::clear() + * \brief Removes all controls from the list + */ + +/** + * \fn ControlList::operator[](const ControlInfo *info) + * \brief Access or insert the control specified by \a info + * \param[in] info The control info + * + * This method returns a reference to the control identified by \a info, + * inserting it in the list if the info is not already present. + * + * \return A reference to the value of the control identified by \a info + */ + +/** + * \brief Update the list with a union of itself and \a other + * \param other The other list + * + * Update the control list to include all values from the \a other list. + * Elements in the list whose control IDs are contained in \a other are updated + * with the value from \a other. Elements in the \a other list that have no + * corresponding element in the list are added to the list with their value. + * + * The behaviour is undefined if the two lists refer to different Camera + * instances. + */ +void ControlList::update(const ControlList &other) +{ + if (other.camera_ != camera_) { + LOG(Controls, Error) + << "Can't update ControlList from a different camera"; + return; + } + + for (auto it : other) { + const ControlInfo *info = it.first; + const ControlValue &value = it.second; + + controls_[info] = value; + } +} + +} /* namespace libcamera */ diff --git a/src/libcamera/gen-controls.awk b/src/libcamera/gen-controls.awk new file mode 100755 index 000000000000..f3d068123012 --- /dev/null +++ b/src/libcamera/gen-controls.awk @@ -0,0 +1,106 @@ +#!/usr/bin/awk -f + +# SPDX-License-Identifier: LGPL-2.1-or-later + +# Controls are documented using Doxygen in the main controls.cpp source. +# +# Generate control tables directly from the documentation, creating enumerations +# to support the IDs and static type information regarding each control. + +BEGIN { + id=0 + input=ARGV[1] + mode=ARGV[2] + output=ARGV[3] +} + +# Detect Doxygen style comment blocks and ignore other lines +/^\/\*\*$/ { in_doxygen=1; first_line=1; next } +// { if (!in_doxygen) next } + +# Entry point for the Control Documentation +/ * \\enum ControlId$/ { in_controls=1; first_line=0; next } +// { if (!in_controls) next } + +# Extract control information +/ \* \\var/ { names[++id]=$3; first_line=0; next } +/ \* ControlType:/ { types[id] = $3 } + +# End of comment blocks +/^ \*\// { in_doxygen=0 } + +# Identify the end of controls +/^ \* \\/ { if (first_line) exit } +// { first_line=0 } + +################################ +# Support output file generation + +function basename(file) { + sub(".*/", "", file) + return file +} + +function Header(file, description) { + print "/* SPDX-License-Identifier: LGPL-2.1-or-later */" > file + print "/*" > file + print " * Copyright (C) 2019, Google Inc." > file + print " *" > file + print " * " basename(file) " - " description > file + print " *" > file + print " * This file is auto-generated. Do not edit." > file + print " */" > file + print "" > file +} + +function EnterNameSpace(file) { + print "namespace libcamera {" > file + print "" > file +} + +function ExitNameSpace(file) { + print "" > file + print "} /* namespace libcamera */" > file +} + +function GenerateHeader(file) { + Header(file, "Control ID list") + + print "#ifndef __LIBCAMERA_CONTROL_IDS_H__" > file + print "#define __LIBCAMERA_CONTROL_IDS_H__" > file + print "" > file + + EnterNameSpace(file) + print "enum ControlId {" > file + for (i=1; i <= id; ++i) { + printf "\t%s,\n", names[i] > file + } + print "};" > file + ExitNameSpace(file) + + print "" > file + print "#endif // __LIBCAMERA_CONTROL_IDS_H__" > file +} + +function GenerateTable(file) { + Header(file, "Control types") + print "#include " > file + print "" > file + + EnterNameSpace(file) + + print "extern const std::unordered_map" > file + print "controlTypes {" > file + for (i=1; i <= id; ++i) { + printf "\t{ %s, { %s, \"%s\", ControlValue%s } },\n", names[i], names[i], names[i], types[i] > file + } + print "};" > file + ExitNameSpace(file) +} + +END { + if (mode == "--header") + GenerateHeader(output) + else + GenerateTable(output) +} diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 985aa7e8ab0e..b1ee92735e41 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -3,6 +3,7 @@ libcamera_sources = files([ 'camera.cpp', 'camera_manager.cpp', 'camera_sensor.cpp', + 'controls.cpp', 'device_enumerator.cpp', 'device_enumerator_sysfs.cpp', 'event_dispatcher.cpp', @@ -66,6 +67,16 @@ if libudev.found() ]) endif +gen_controls = files('gen-controls.awk') + +control_types_cpp = custom_target('control_types_cpp', + input : files('controls.cpp'), + output : 'control_types.cpp', + depend_files : gen_controls, + command : [gen_controls, '@INPUT@', '--code', '@OUTPUT@']) + +libcamera_sources += control_types_cpp + libcamera_deps = [ cc.find_library('dl'), libudev, From patchwork Mon Jul 1 20:14:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1563 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AEB386157D for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 59CD51200 for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012129; bh=SzGGUSuBzXMnb5DuPM1IX8QwlJlyjWsmnxEH5UUpnKo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bd0xx8FophDTEi98cmy000GWdIgEQV1SmeTHHqv/TJs82rc86+KR+SE/ILQiXPPp0 2h377Rrhizj4sUfNx+/w1gUTVKTJHQiAPc2ZMyXNYiKvbBicLnhhvLI1xx3DObZQiB BfXuQk730N1pibjrBfX7M3Ykz6JvsyLEagWhllfw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:55 +0300 Message-Id: <20190701201504.28487-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/13] libcamera: camera: Provide a list of ControlInfo X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:30 -0000 From: Kieran Bingham Extend the Camera class to expose the controls it supports. Each pipeline should generate a list of controls supported by each camera it creates. These are represented by a ControlInfoMap, and an associated ControlList of default values. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- include/libcamera/camera.h | 3 +++ include/libcamera/controls.h | 2 ++ src/libcamera/camera.cpp | 12 ++++++++++++ src/libcamera/controls.cpp | 5 +++++ src/libcamera/include/pipeline_handler.h | 4 ++++ src/libcamera/pipeline_handler.cpp | 19 +++++++++++++++++++ 6 files changed, 45 insertions(+) diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index fb2f7ba3423c..6d693d9a6c7a 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -83,6 +84,8 @@ public: int acquire(); int release(); + const ControlInfoMap &controls(); + const std::set &streams() const; std::unique_ptr generateConfiguration(const StreamRoles &roles); int configure(CameraConfiguration *config); diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 2206155909ca..18293c9462cf 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -99,6 +99,8 @@ static inline bool operator!=(const ControlInfo &lhs, const ControlId &rhs) return !(lhs == rhs); } +using ControlInfoMap = std::unordered_map; + class ControlList { private: diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 617ea99cdf71..592dfd39eacc 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -548,6 +548,18 @@ int Camera::release() return 0; } +/** + * \brief Retrieve the list of controls supported by the camera + * + * Camera controls remain constant through the lifetime of the camera. + * + * \return A ControlInfoMap listing the controls supported by the camera + */ +const ControlInfoMap &Camera::controls() +{ + return pipe_->controls(this); +} + /** * \brief Retrieve all the camera's stream information * diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index 7fac1169cbfd..cd2cf337b379 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -325,6 +325,11 @@ bool operator==(const ControlInfo &lhs, const ControlId &rhs) return lhs.id() == rhs; } +/** + * \typedef ControlInfoMap + * \brief A map of ControlId to ControlInfo + */ + /** * \class ControlList * \brief Associate a list of ControlId with their values for a camera diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index a4cbc593a179..f836d5d1a600 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -14,6 +14,7 @@ #include #include +#include #include namespace libcamera { @@ -41,6 +42,7 @@ public: Camera *camera_; PipelineHandler *pipe_; std::list queuedRequests_; + ControlInfoMap controlInfo_; private: CameraData(const CameraData &) = delete; @@ -60,6 +62,8 @@ public: bool lock(); void unlock(); + const ControlInfoMap &controls(Camera *camera); + virtual CameraConfiguration *generateConfiguration(Camera *camera, const StreamRoles &roles) = 0; virtual int configure(Camera *camera, CameraConfiguration *config) = 0; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index c91ef2f7d336..0283e4e5ad51 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -88,6 +88,14 @@ LOG_DEFINE_CATEGORY(Pipeline) * PipelineHandler::completeRequest() */ +/** + * \var CameraData::controlInfo_ + * \brief The set of controls supported by the camera + * + * The control information shall be initialised by the pipeline handler when + * creating the camera, and shall not be modified afterwards. + */ + /** * \class PipelineHandler * \brief Create and manage cameras based on a set of media devices @@ -217,6 +225,17 @@ void PipelineHandler::unlock() media->unlock(); } +/** + * \brief Retrieve the list of controls for a camera + * \param[in] camera The camera + * \return A ControlInfoMap listing the controls support by \a camera + */ +const ControlInfoMap &PipelineHandler::controls(Camera *camera) +{ + CameraData *data = cameraData(camera); + return data->controlInfo_; +} + /** * \fn PipelineHandler::generateConfiguration() * \brief Generate a camera configuration for a specified camera From patchwork Mon Jul 1 20:14:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1564 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0EFD461F5D for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A72F3524 for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012129; bh=gzY+WTMrt6THi+MJDLwq3yf0fYjtI98VzNuphVal/Oo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kNFvimjHJMy/fVE+PI0u6vXHKhO6bgVSmc+3wn4NuMe8b5eUXIB5bwSiQh1UggjeQ ohmtIsRI3jG1GlFl+Aec1pKj1WBkbrj8UR5419gbMIz2s2kX0XzhmzHEzPf76u+wYy 03AspPhc3R0kgAG8IHrCrI6sBGfjo8kFhD6Wo1Pw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:56 +0300 Message-Id: <20190701201504.28487-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/13] libcamera: controls: Extend ControlList to access controls by ID X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:31 -0000 The ControlList class implements a map from control specifier to control ID. To avoid constant lookups of ControlInfo when using the class in the libcamera core or in pipeline handlers, the map uses ControlInfo pointers instead of ControlId values. This is however not very convenient for applications or pipeline handlers, as they would be forced to first look up the ControlInfo pointers for the controls they want to access. Facilitate ease of use of ControlLists by implementing an internal lookup of the ControlInfo from the controls provided by the Camera. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi Reviewed-by: Niklas Söderlund --- Changes since v3: - Typo fixes --- include/libcamera/controls.h | 2 ++ src/libcamera/controls.cpp | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 18293c9462cf..fbb3a62274c6 100644 --- a/include/libcamera/controls.h +++ b/include/libcamera/controls.h @@ -117,11 +117,13 @@ public: const_iterator begin() const { return controls_.begin(); } const_iterator end() const { return controls_.end(); } + bool contains(ControlId id) const; bool contains(const ControlInfo *info) const; bool empty() const { return controls_.empty(); } std::size_t size() const { return controls_.size(); } void clear() { controls_.clear(); } + ControlValue &operator[](ControlId id); ControlValue &operator[](const ControlInfo *info) { return controls_[info]; } void update(const ControlList &list); diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index cd2cf337b379..42a2f8990bf6 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "log.h" #include "utils.h" @@ -387,6 +389,30 @@ ControlList::ControlList(Camera *camera) * list */ +/** + * \brief Check if the list contains a control with the specified \a id + * \param[in] id The control ID + * + * The behaviour is undefined if the control \a id is not supported by the + * camera that the ControlList refers to. + * + * \return True if the list contains a matching control, false otherwise + */ +bool ControlList::contains(ControlId id) const +{ + const ControlInfoMap &controls = camera_->controls(); + const auto iter = controls.find(id); + if (iter == controls.end()) { + LOG(Controls, Error) + << "Camera " << camera_->name() + << " does not support control " << id; + + return false; + } + + return controls_.find(&iter->second) != controls_.end(); +} + /** * \brief Check if the list contains a control with the specified \a info * \param[in] info The control info @@ -414,6 +440,34 @@ bool ControlList::contains(const ControlInfo *info) const * \brief Removes all controls from the list */ +/** + * \brief Access or insert the control specified by \a id + * \param[in] id The control ID + * + * This method returns a reference to the control identified by \a id, inserting + * it in the list if the ID is not already present. + * + * The behaviour is undefined if the control \a id is not supported by the + * camera that the ControlList refers to. + * + * \return A reference to the value of the control identified by \a id + */ +ControlValue &ControlList::operator[](ControlId id) +{ + const ControlInfoMap &controls = camera_->controls(); + const auto iter = controls.find(id); + if (iter == controls.end()) { + LOG(Controls, Error) + << "Camera " << camera_->name() + << " does not support control " << id; + + static ControlValue empty; + return empty; + } + + return controls_[&iter->second]; +} + /** * \fn ControlList::operator[](const ControlInfo *info) * \brief Access or insert the control specified by \a info From patchwork Mon Jul 1 20:14:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1565 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4A25C6157D for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EC8CB1200 for ; Mon, 1 Jul 2019 22:15:29 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012130; bh=97rotAarLcRh7B0x2D9xvvSQFwEyzgihulrD5ySrM20=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aB8W0TxzhXkxEVWcLBEohbsO7Bif4bC1fY4UNaER59VtMykwz93wuOMNvc7V/GIXw lI0tkMbspGFP+YOCSNrq+Ns0NZlxiQ8IgZP9bxfx7HXt56YkROGXIBkSs0b/D2h28l V08L3+LsgUf0SRky8sqQNcCIChxEcSbFGZflRNII= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:57 +0300 Message-Id: <20190701201504.28487-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/13] libcamera: request: Add a ControlList X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:31 -0000 From: Kieran Bingham Provide a ControlList on request objects to facilitate setting controls. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund --- Changes since v3: - Don't clear controls when the request completes - Fixed include ordering --- include/libcamera/request.h | 3 +++ src/libcamera/request.cpp | 12 +++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 58de6f00a554..a93468d7c8b7 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace libcamera { @@ -32,6 +33,7 @@ public: Request(const Request &) = delete; Request &operator=(const Request &) = delete; + ControlList &controls() { return controls_; } const std::map &buffers() const { return bufferMap_; } int setBuffers(const std::map &streamMap); Buffer *findBuffer(Stream *stream) const; @@ -50,6 +52,7 @@ private: bool completeBuffer(Buffer *buffer); Camera *camera_; + ControlList controls_; std::map bufferMap_; std::unordered_set pending_; diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp index fa3ee46da440..e749e41baa42 100644 --- a/src/libcamera/request.cpp +++ b/src/libcamera/request.cpp @@ -48,10 +48,20 @@ LOG_DEFINE_CATEGORY(Request) * \param[in] camera The camera that creates the request */ Request::Request(Camera *camera) - : camera_(camera), status_(RequestPending) + : camera_(camera), controls_(camera), status_(RequestPending) { } +/** + * \fn Request::controls() + * \brief Retrieve the request's ControlList + * + * Return a reference to the ControlList that stores all the controls relevant + * to this request. + * + * \return A reference to the ControlList in this request + */ + /** * \fn Request::buffers() * \brief Retrieve the request's streams to buffers map From patchwork Mon Jul 1 20:14:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1566 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 88CAC61E16 for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3FB1E524 for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012130; bh=vqiud2b6h+aZ++cnTpe5KXp0l7EK7Snlbie6MyK+imI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=TCfqQfdXTim3Nsqn1hsIMJ/L67EOcrTQkbXo1eUJk16fWbjAsaXLWxuA52FGLbl9c uLbEeLJOiR0bNZVtN1zPU6iBMYuAK26fDQZciP9JXrdBqPHMCHY+K3cVo2v48//ZoN AbRPfdBRN0oCfsKBGCvkK4o9uwVB+MFrpwCXDnz8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:58 +0300 Message-Id: <20190701201504.28487-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/13] libcamera: controls: Add a set of initial controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:31 -0000 Add an initial set of controls to demonstrate how controls are defined. Proper documentation for each control is missing. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Kieran Bingham --- include/libcamera/control_ids.h | 6 +++++ src/libcamera/controls.cpp | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/libcamera/control_ids.h b/include/libcamera/control_ids.h index d0e700da9844..75b6a2d5cafe 100644 --- a/include/libcamera/control_ids.h +++ b/include/libcamera/control_ids.h @@ -13,6 +13,12 @@ namespace libcamera { enum ControlId { + AwbEnable, + Brightness, + Contrast, + Saturation, + ManualExposure, + ManualGain, }; } /* namespace libcamera */ diff --git a/src/libcamera/controls.cpp b/src/libcamera/controls.cpp index 42a2f8990bf6..d9fbd46d81c9 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -186,6 +186,48 @@ std::string ControlValue::toString() const * \brief Numerical control ID */ +/** + * \var AwbEnable + * ControlType: Bool + * + * Enables or disables the AWB. See also \a libcamera::ControlId::ManualGain + */ + +/** + * \var Brightness + * ControlType: Integer + * + * Specify a fixed brightness parameter. + */ + +/** + * \var Contrast + * ControlType: Integer + * + * Specify a fixed constrast parameter. + */ + +/** + * \var Saturation + * ControlType: Integer + * + * Specify a fixed saturation parameter. + */ + +/** + * \var ManualExposure + * ControlType: Integer + * + * Specify a fixed exposure time in milli-seconds + */ + +/** + * \var ManualGain + * ControlType: Integer + * + * Specify a fixed gain parameter + */ + /** * \struct ControlIdentifier * \brief Describe a ControlId with control specific constant meta-data From patchwork Mon Jul 1 20:14:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1567 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D48FB6157C for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 85F61120A for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012130; bh=gnNyFf9fr4k5EzjFRlCoBTokKL0/EqCb1DMlcs9KmZ0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=P58Zr370/CPJc65Zw5GQdwH88tOtBPG0slS9mc28Lqy/LlHJRRImCaStG2md0dMP4 ifnsRBwYBYgsLcUMet2J+j8nFkyAMCB13sXIiwRX+hFkSVyre1gAaXbJYpCXRQAPTl 10VV5AxzLNmkHegysINs66+cgwmhAdEmU3lIBrmw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:14:59 +0300 Message-Id: <20190701201504.28487-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/13] libcamera: pipeline: uvcvideo: Add controls support X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:31 -0000 From: Kieran Bingham Implement control support in the UVC pipeline handler by dynamically querying the V4L2 device for the supported V4L2 controls and populating the list of camera controls accordingly. Not-signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- Changes since v3: - Fixed error checking when setting controls - Fixed handling of the failure to find a default video device --- src/libcamera/pipeline/uvcvideo.cpp | 124 +++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 2e22523d7cb1..b2f5b2eeed80 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -6,8 +6,11 @@ */ #include +#include +#include #include +#include #include #include @@ -16,6 +19,7 @@ #include "media_device.h" #include "pipeline_handler.h" #include "utils.h" +#include "v4l2_controls.h" #include "v4l2_videodevice.h" namespace libcamera { @@ -35,6 +39,7 @@ public: delete video_; } + int init(MediaEntity *entity); void bufferReady(Buffer *buffer); V4L2VideoDevice *video_; @@ -71,6 +76,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + int processControls(UVCCameraData *data, Request *request); + UVCCameraData *cameraData(const Camera *camera) { return static_cast( @@ -216,6 +223,56 @@ void PipelineHandlerUVC::stop(Camera *camera) PipelineHandler::stop(camera); } +int PipelineHandlerUVC::processControls(UVCCameraData *data, Request *request) +{ + V4L2ControlList controls; + + for (auto it : request->controls()) { + const ControlInfo *ci = it.first; + ControlValue &value = it.second; + + switch (ci->id()) { + case Brightness: + controls.add(V4L2_CID_BRIGHTNESS, value.getInt()); + break; + + case Contrast: + controls.add(V4L2_CID_CONTRAST, value.getInt()); + break; + + case Saturation: + controls.add(V4L2_CID_SATURATION, value.getInt()); + break; + + case ManualExposure: + controls.add(V4L2_CID_EXPOSURE_AUTO, 1); + controls.add(V4L2_CID_EXPOSURE_ABSOLUTE, value.getInt()); + break; + + case ManualGain: + controls.add(V4L2_CID_GAIN, value.getInt()); + break; + + default: + break; + } + } + + for (const V4L2Control &ctrl : controls) + LOG(UVC, Debug) + << "Setting control 0x" + << std::hex << std::setw(8) << ctrl.id() << std::dec + << " to " << ctrl.value(); + + int ret = data->video_->setControls(&controls); + if (ret) { + LOG(UVC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + int PipelineHandlerUVC::queueRequest(Camera *camera, Request *request) { UVCCameraData *data = cameraData(camera); @@ -227,7 +284,11 @@ int PipelineHandlerUVC::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = data->video_->queueBuffer(buffer); + int ret = processControls(data, request); + if (ret < 0) + return ret; + + ret = data->video_->queueBuffer(buffer); if (ret < 0) return ret; @@ -247,24 +308,20 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) std::unique_ptr data = utils::make_unique(this); - /* Locate and open the default video node. */ + /* Locate and initialise the camera data with the default video node. */ for (MediaEntity *entity : media->entities()) { if (entity->flags() & MEDIA_ENT_FL_DEFAULT) { - data->video_ = new V4L2VideoDevice(entity); + if (data->init(entity)) + return false; break; } } - if (!data->video_) { + if (!data) { LOG(UVC, Error) << "Could not find a default video device"; - return false; + return -ENODEV; } - if (data->video_->open()) - return false; - - data->video_->bufferReady.connect(data.get(), &UVCCameraData::bufferReady); - /* Create and register the camera. */ std::set streams{ &data->stream_ }; std::shared_ptr camera = Camera::create(this, media->model(), streams); @@ -276,6 +333,53 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) return true; } +int UVCCameraData::init(MediaEntity *entity) +{ + int ret; + + /* Create and open the video device. */ + video_ = new V4L2VideoDevice(entity); + ret = video_->open(); + if (ret) + return ret; + + video_->bufferReady.connect(this, &UVCCameraData::bufferReady); + + /* Initialise the supported controls. */ + const V4L2ControlInfoMap &controls = video_->controls(); + for (const auto &ctrl : controls) { + unsigned int v4l2Id = ctrl.first; + const V4L2ControlInfo &info = ctrl.second; + ControlId id; + + switch (v4l2Id) { + case V4L2_CID_BRIGHTNESS: + id = Brightness; + break; + case V4L2_CID_CONTRAST: + id = Contrast; + break; + case V4L2_CID_SATURATION: + id = Saturation; + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + id = ManualExposure; + break; + case V4L2_CID_GAIN: + id = ManualGain; + break; + default: + continue; + } + + controlInfo_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(id, info.min(), info.max())); + } + + return 0; +} + void UVCCameraData::bufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); From patchwork Mon Jul 1 20:15:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1568 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 281F561F51 for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CB6B6524 for ; Mon, 1 Jul 2019 22:15:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012130; bh=Qa7AX4MJcxSsLSKsShHQuX8rpQboFf/UV4jQb1ZJ7KA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=WwHV8eDz/du+DBeg19Wc26Fvg9CjQOuUEvbI5VgyUOfJph82ZfH2bVLECrwEoPjoV h6ZI/Hw6TVLRwl7em4dbkwofTBJiLFhikZLNn4O0AO0iPRzIx/a2KkOctY7AyjvrDN bZdX/9Zpj7j3+oBh7L/QxLPw/xmPSLSErNTKaBLM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:15:00 +0300 Message-Id: <20190701201504.28487-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/13] libcamera: pipeline: vimc: Add controls support X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:32 -0000 Implement control support in the VIMC pipeline handler by dynamically querying the V4L2 device for the supported V4L2 controls and populating the list of camera controls accordingly. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- Changes since v3: - Fixed error checking when setting controls --- src/libcamera/pipeline/vimc.cpp | 107 ++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 6833213650dc..f8a58be060bb 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -7,19 +7,24 @@ #include #include +#include +#include #include +#include #include #include #include #include +#include "camera_sensor.h" #include "device_enumerator.h" #include "ipa_manager.h" #include "log.h" #include "media_device.h" #include "pipeline_handler.h" #include "utils.h" +#include "v4l2_controls.h" #include "v4l2_videodevice.h" namespace libcamera { @@ -36,12 +41,15 @@ public: ~VimcCameraData() { + delete sensor_; delete video_; } + int init(MediaDevice *media); void bufferReady(Buffer *buffer); V4L2VideoDevice *video_; + CameraSensor *sensor_; Stream stream_; }; @@ -75,6 +83,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + int processControls(VimcCameraData *data, Request *request); + VimcCameraData *cameraData(const Camera *camera) { return static_cast( @@ -215,6 +225,47 @@ void PipelineHandlerVimc::stop(Camera *camera) PipelineHandler::stop(camera); } +int PipelineHandlerVimc::processControls(VimcCameraData *data, Request *request) +{ + V4L2ControlList controls; + + for (auto it : request->controls()) { + const ControlInfo *ci = it.first; + ControlValue &value = it.second; + + switch (ci->id()) { + case Brightness: + controls.add(V4L2_CID_BRIGHTNESS, value.getInt()); + break; + + case Contrast: + controls.add(V4L2_CID_CONTRAST, value.getInt()); + break; + + case Saturation: + controls.add(V4L2_CID_SATURATION, value.getInt()); + break; + + default: + break; + } + } + + for (const V4L2Control &ctrl : controls) + LOG(VIMC, Debug) + << "Setting control 0x" + << std::hex << std::setw(8) << ctrl.id() << std::dec + << " to " << ctrl.value(); + + int ret = data->sensor_->setControls(&controls); + if (ret) { + LOG(VIMC, Error) << "Failed to set controls: " << ret; + return ret < 0 ? ret : -EINVAL; + } + + return ret; +} + int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request) { VimcCameraData *data = cameraData(camera); @@ -226,7 +277,11 @@ int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request) return -ENOENT; } - int ret = data->video_->queueBuffer(buffer); + int ret = processControls(data, request); + if (ret < 0) + return ret; + + ret = data->video_->queueBuffer(buffer); if (ret < 0) return ret; @@ -262,12 +317,9 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) std::unique_ptr data = utils::make_unique(this); /* Locate and open the capture video node. */ - data->video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1")); - if (data->video_->open()) + if (data->init(media)) return false; - data->video_->bufferReady.connect(data.get(), &VimcCameraData::bufferReady); - /* Create and register the camera. */ std::set streams{ &data->stream_ }; std::shared_ptr camera = Camera::create(this, "VIMC Sensor B", @@ -277,6 +329,51 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) return true; } +int VimcCameraData::init(MediaDevice *media) +{ + int ret; + + /* Create and open the video device and the camera sensor. */ + video_ = new V4L2VideoDevice(media->getEntityByName("Raw Capture 1")); + if (video_->open()) + return -ENODEV; + + video_->bufferReady.connect(this, &VimcCameraData::bufferReady); + + sensor_ = new CameraSensor(media->getEntityByName("Sensor B")); + ret = sensor_->init(); + if (ret) + return ret; + + /* Initialise the supported controls. */ + const V4L2ControlInfoMap &controls = sensor_->controls(); + for (const auto &ctrl : controls) { + unsigned int v4l2Id = ctrl.first; + const V4L2ControlInfo &info = ctrl.second; + ControlId id; + + switch (v4l2Id) { + case V4L2_CID_BRIGHTNESS: + id = Brightness; + break; + case V4L2_CID_CONTRAST: + id = Contrast; + break; + case V4L2_CID_SATURATION: + id = Saturation; + break; + default: + continue; + } + + controlInfo_.emplace(std::piecewise_construct, + std::forward_as_tuple(id), + std::forward_as_tuple(id, info.min(), info.max())); + } + + return 0; +} + void VimcCameraData::bufferReady(Buffer *buffer) { Request *request = queuedRequests_.front(); From patchwork Mon Jul 1 20:15:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1569 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 74F3E61F5D for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 202081217 for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012131; bh=GHlMySBi5xqeUwYJNAOLGl2fTK8C15O+d7MdvuQ3lss=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Llp3hE+ZNi0mN/ilGOzqoHjVuWf8kJ+Z8XJkXFtOKNzMbAUhMhohYMtshBgMJR2Xg mHzJ1JyacA8xWnOeZK7YXUuNSoINCp3zyL8wH8nljySMeCqoPPBtAJLkgzz9cCrjXK XIHC7PbSZjn5xAYSIRnUN5PYMmGsXnvhkY5a4iZU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:15:01 +0300 Message-Id: <20190701201504.28487-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/13] libcamera: test: Add ControlValue test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:32 -0000 From: Kieran Bingham Add initial basic testing for the new ControlValue class. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund --- test/controls/control_value.cpp | 69 +++++++++++++++++++++++++++++++++ test/controls/meson.build | 11 ++++++ test/meson.build | 1 + 3 files changed, 81 insertions(+) create mode 100644 test/controls/control_value.cpp create mode 100644 test/controls/meson.build diff --git a/test/controls/control_value.cpp b/test/controls/control_value.cpp new file mode 100644 index 000000000000..778efe5c115f --- /dev/null +++ b/test/controls/control_value.cpp @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_value.cpp - ControlValue tests + */ + +#include + +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class ControlValueTest : public Test +{ +protected: + int run() + { + ControlValue integer(1234); + ControlValue boolean(true); + + /* Just a string conversion output test... no validation */ + cout << "Int: " << integer.toString() + << " Bool: " << boolean.toString() + << endl; + + if (integer.getInt() != 1234) { + cerr << "Failed to get Integer" << endl; + return TestFail; + } + + if (boolean.getBool() != true) { + cerr << "Failed to get Boolean" << endl; + return TestFail; + } + + /* Test an uninitialised value, and updating it. */ + + ControlValue value; + if (!value.isNone()) { + cerr << "Empty value is non-null" << endl; + return TestFail; + } + + value.set(true); + if (value.isNone()) { + cerr << "Failed to set an empty object" << endl; + return TestFail; + } + + if (value.getBool() != true) { + cerr << "Failed to get Booleans" << endl; + return TestFail; + } + + value.set(10); + if (value.getInt() != 10) { + cerr << "Failed to get Integer" << endl; + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(ControlValueTest) diff --git a/test/controls/meson.build b/test/controls/meson.build new file mode 100644 index 000000000000..1161864d9949 --- /dev/null +++ b/test/controls/meson.build @@ -0,0 +1,11 @@ +control_tests = [ + [ 'control_value', 'control_value.cpp' ], +] + +foreach t : control_tests + exe = executable(t[0], t[1], + dependencies : libcamera_dep, + link_with : test_libraries, + include_directories : test_includes_internal) + test(t[0], exe, suite : 'controls', is_parallel : false) +endforeach diff --git a/test/meson.build b/test/meson.build index c36ac2479636..fea2485cbb34 100644 --- a/test/meson.build +++ b/test/meson.build @@ -1,6 +1,7 @@ subdir('libtest') subdir('camera') +subdir('controls') subdir('ipa') subdir('media_device') subdir('pipeline') From patchwork Mon Jul 1 20:15:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1570 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B360661F4A for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6A838524 for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012131; bh=PXVWkAZU9N/gTgufqV4/MXpcO3dQqPOekospj4fc+yU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=syM6/ainhsn8lT3eFDbb0qLmq+DvjQjG6TK5ldk+4l+pxd1wtNdH5+Tv7N1MGh7// 3BS3i3vWW9ll0xQcS7jkKXknnGOooS9OxvMPL4axXaiCSYRt6Ev1U0WyfTfnomgO7I aLSmzpBa4r+3g5hEtBAEkVfG7acL1bXMltXcGX8w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:15:02 +0300 Message-Id: <20190701201504.28487-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/13] libcamera: test: Add ControlInfo test X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:32 -0000 From: Kieran Bingham Provide an initial test coverage for the ControlInfo class. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v2: - Renamed to control_info.cpp --- test/controls/control_info.cpp | 62 ++++++++++++++++++++++++++++++++++ test/controls/meson.build | 1 + 2 files changed, 63 insertions(+) create mode 100644 test/controls/control_info.cpp diff --git a/test/controls/control_info.cpp b/test/controls/control_info.cpp new file mode 100644 index 000000000000..aa3a65b1e5ef --- /dev/null +++ b/test/controls/control_info.cpp @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_info.cpp - ControlInfo tests + */ + +#include + +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class ControlInfoTest : public Test +{ +protected: + int run() + { + /* + * Test information retrieval from a control with no minimum + * and maximum. + */ + ControlInfo info(Brightness); + + if (info.id() != Brightness || + info.type() != ControlValueInteger || + info.name() != std::string("Brightness")) { + cout << "Invalid control identification for Brightness" << endl; + return TestFail; + } + + if (info.min().getInt() != 0 || info.max().getInt() != 0) { + cout << "Invalid control range for Brightness" << endl; + return TestFail; + } + + /* + * Test information retrieval from a control with a minimum and + * a maximum value. + */ + info = ControlInfo(Contrast, 10, 200); + + if (info.id() != Contrast || + info.type() != ControlValueInteger || + info.name() != std::string("Contrast")) { + cout << "Invalid control identification for Contrast" << endl; + return TestFail; + } + + if (info.min().getInt() != 10 || info.max().getInt() != 200) { + cout << "Invalid control range for Contrast" << endl; + return TestFail; + } + + return TestPass; + } +}; + +TEST_REGISTER(ControlInfoTest) diff --git a/test/controls/meson.build b/test/controls/meson.build index 1161864d9949..f8cda2877e73 100644 --- a/test/controls/meson.build +++ b/test/controls/meson.build @@ -1,4 +1,5 @@ control_tests = [ + [ 'control_info', 'control_info.cpp' ], [ 'control_value', 'control_value.cpp' ], ] From patchwork Mon Jul 1 20:15:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1571 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1984861FAE for ; Mon, 1 Jul 2019 22:15:32 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B0F27120A for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012131; bh=GpI0w1AfwKmT2AQKF+PZAkjbN548YkhJCCn67q3xugM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bS3Iyp0vevErMpLlh9a5UNI5rXUnUjV3edVrJTK0WpoDpdgbm1qSeAradAcN4BEai 92+sjUWGbQeWY8l18Rvz+nqWG0u1QcLaz5vCuOpZ786+Wvjy0G3zlE7cqC9uH3+KMs dSp9yE83E3K6y3VOcn8w2mH5pHsrG8RVPOPlpxIU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:15:03 +0300 Message-Id: <20190701201504.28487-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 12/13] libcamera: test: Add ControlList tests X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:33 -0000 From: Kieran Bingham Add tests of the ControlList infrastructure and public API. Signed-off-by: Kieran Bingham Reviewed-by: Niklas Söderlund --- test/controls/control_list.cpp | 213 +++++++++++++++++++++++++++++++++ test/controls/meson.build | 1 + 2 files changed, 214 insertions(+) create mode 100644 test/controls/control_list.cpp diff --git a/test/controls/control_list.cpp b/test/controls/control_list.cpp new file mode 100644 index 000000000000..c834edc352f5 --- /dev/null +++ b/test/controls/control_list.cpp @@ -0,0 +1,213 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * control_list.cpp - ControlList tests + */ + +#include + +#include +#include +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class ControlListTest : public Test +{ +protected: + int init() + { + cm_ = CameraManager::instance(); + + if (cm_->start()) { + cout << "Failed to start camera manager" << endl; + return TestFail; + } + + camera_ = cm_->get("VIMC Sensor B"); + if (!camera_) { + cout << "Can not find VIMC camera" << endl; + return TestSkip; + } + + return TestPass; + } + + int run() + { + ControlList list(camera_.get()); + + /* Test that the list is initially empty. */ + if (!list.empty()) { + cout << "List should to be empty" << endl; + return TestFail; + } + + if (list.size() != 0) { + cout << "List should contain zero items" << endl; + return TestFail; + } + + if (list.contains(Brightness)) { + cout << "List should not contain Brightness control" << endl; + return TestFail; + } + + unsigned int count = 0; + for (auto iter = list.begin(); iter != list.end(); ++iter) + count++; + + if (count != 0) { + cout << "List iteration should not produce any item" << endl; + return TestFail; + } + + /* + * Set a control, and verify that the list now contains it, and + * nothing else. + */ + list[Brightness] = 255; + + if (list.empty()) { + cout << "List should not be empty" << endl; + return TestFail; + } + + if (list.size() != 1) { + cout << "List should contain one item" << endl; + return TestFail; + } + + if (!list.contains(Brightness)) { + cout << "List should contain Brightness control" << endl; + return TestFail; + } + + count = 0; + for (auto iter = list.begin(); iter != list.end(); ++iter) + count++; + + if (count != 1) { + cout << "List iteration should produce one item" << endl; + return TestFail; + } + + if (list[Brightness].getInt() != 255) { + cout << "Incorrest Brightness control value" << endl; + return TestFail; + } + + if (list.contains(Contrast)) { + cout << "List should not contain Contract control" << endl; + return TestFail; + } + + /* + * Set a second control through ControlInfo and retrieve it + * through both controlId and ControlInfo. + */ + const ControlInfoMap &controls = camera_->controls(); + const ControlInfo *brightness = &controls.find(Brightness)->second; + const ControlInfo *contrast = &controls.find(Contrast)->second; + + list[brightness] = 64; + list[contrast] = 128; + + if (!list.contains(Contrast) || !list.contains(contrast)) { + cout << "List should contain Contrast control" << endl; + return TestFail; + } + + /* + * Test control value retrieval and update through ControlInfo. + */ + if (list[brightness].getInt() != 64 || + list[contrast].getInt() != 128) { + cout << "Failed to retrieve control value" << endl; + return TestFail; + } + + list[brightness] = 10; + list[contrast] = 20; + + if (list[brightness].getInt() != 10 || + list[contrast].getInt() != 20) { + cout << "Failed to update control value" << endl; + return TestFail; + } + + /* + * Assert that the container has not grown with the control + * updated. + */ + if (list.size() != 2) { + cout << "List should contain two elements" << endl; + return TestFail; + } + + /* + * Test list merging. Create a new list, add two controls with + * one overlapping the existing list, merge the lists and clear + * the old list. Verify that the new list is empty and that the + * new list contains the expected items and values. + */ + ControlList newList(camera_.get()); + + newList[Brightness] = 128; + newList[Saturation] = 255; + newList.update(list); + + list.clear(); + + if (list.size() != 0) { + cout << "Old List should contain zero items" << endl; + return TestFail; + } + + if (!list.empty()) { + cout << "Old List should be empty" << endl; + return TestFail; + } + + if (newList.size() != 3) { + cout << "New list has incorrect size" << endl; + return TestFail; + } + + if (!newList.contains(Brightness) || + !newList.contains(Contrast) || + !newList.contains(Saturation)) { + cout << "New list contains incorrect items" << endl; + return TestFail; + } + + if (newList[Brightness].getInt() != 10 || + newList[Contrast].getInt() != 20 || + newList[Saturation].getInt() != 255) { + cout << "New list contains incorrect values" << endl; + return TestFail; + } + + return TestPass; + } + + void cleanup() + { + if (camera_) { + camera_->release(); + camera_.reset(); + } + + cm_->stop(); + } + +private: + CameraManager *cm_; + std::shared_ptr camera_; +}; + +TEST_REGISTER(ControlListTest) diff --git a/test/controls/meson.build b/test/controls/meson.build index f8cda2877e73..f4fc7b947dd9 100644 --- a/test/controls/meson.build +++ b/test/controls/meson.build @@ -1,5 +1,6 @@ control_tests = [ [ 'control_info', 'control_info.cpp' ], + [ 'control_list', 'control_list.cpp' ], [ 'control_value', 'control_value.cpp' ], ] From patchwork Mon Jul 1 20:15:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1572 X-Patchwork-Delegate: laurent.pinchart@ideasonboard.com Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 62B76619E5 for ; Mon, 1 Jul 2019 22:15:33 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0522F524 for ; Mon, 1 Jul 2019 22:15:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1562012132; bh=PIlqXsOiLQbKLx2Pi8tqvo7q5gEcHawdRl3WYeCSX6M=; h=From:To:Subject:Date:In-Reply-To:References:From; b=GOidttDp7gDmV+gxp9C4TVsmDYKe8efoYMnyVgt0hkDg0fRWwJgAAOs/It9ufJHLD wXCMScazgtnDu/h8J18AyNojcWa7ononZ9F8bmG1A48A2YbZzHtZ19IS8s3B6VO2xT i1Vy9l13rxcq5KoaqqOf02IjiubnhUlMCWfNBOZE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 23:15:04 +0300 Message-Id: <20190701201504.28487-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> References: <20190701201504.28487-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 13/13] [PoC] QCam: Control demo: A SineWave Brightness X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 01 Jul 2019 20:15:33 -0000 From: Kieran Bingham As an example of how to add a control to each request, set the Brightness value with a changing value against the buffer time stamps. The Brightness will go up and down following a sine wave to visualise the control effect on the video stream. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart --- Changes since v2: - Take controls min/max values into account --- src/qcam/main_window.cpp | 29 ++++++++++++++++++++++++++++- src/qcam/main_window.h | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 16b123132dd9..bfd3af1e4b92 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -5,6 +5,7 @@ * main_window.cpp - qcam - Main application window */ +#include #include #include #include @@ -21,7 +22,8 @@ using namespace libcamera; MainWindow::MainWindow(const OptionsParser::Options &options) - : options_(options), isCapturing_(false) + : options_(options), isCapturing_(false), + brightness_(nullptr), gain_(nullptr) { int ret; @@ -88,6 +90,14 @@ int MainWindow::openCamera() std::cout << "Using camera " << camera_->name() << std::endl; + const ControlInfoMap &controls = camera_->controls(); + auto iter = controls.find(Brightness); + if (iter != controls.end()) + brightness_ = &iter->second; + iter = controls.find(ManualGain); + if (iter != controls.end()) + gain_ = &iter->second; + camera_->requestCompleted.connect(this, &MainWindow::requestComplete); return 0; @@ -184,6 +194,14 @@ void MainWindow::stopCapture() config_.reset(); } +static int sineWaveValue(Buffer *buffer, const ControlInfo *info) +{ + unsigned int millisec = buffer->timestamp() / 1000000; + constexpr float rads = 2 * M_PI / 180; + return (sin(0.036 * rads * millisec) + 1) / 2 * + (info->max().getInt() - info->min().getInt()); +} + void MainWindow::requestComplete(Request *request, const std::map &buffers) { @@ -213,6 +231,15 @@ void MainWindow::requestComplete(Request *request, return; } + /* + * A demonstration control, which has a distinct visual effect. + * Scale the brightness up and down with a sine wave. + */ + if (brightness_) + request->controls()[Brightness] = sineWaveValue(buffer, brightness_); + if (gain_) + request->controls()[ManualGain] = sineWaveValue(buffer, gain_); + request->setBuffers(buffers); camera_->queueRequest(request); } diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index fe565cbcb460..0a52399edc74 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -48,6 +48,9 @@ private: bool isCapturing_; std::unique_ptr config_; + const ControlInfo *brightness_; + const ControlInfo *gain_; + ViewFinder *viewfinder_; };