From patchwork Sun Jun 30 23:38: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: 1543 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 0124960BC0 for ; Mon, 1 Jul 2019 01:38:43 +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 8DD8B2F0 for ; Mon, 1 Jul 2019 01:38:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937922; bh=7+6nGXwxH/jnowHcoM6rpKbfJywr9N141Ol4FkU0CGs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=cMmr9kWI3jy6EMNLkchpb7WXkaec4+rTRCNpOmOtTE1A0CTxzNFfN0OUagqi0mkFJ oqf3/tvvkPWbiBZ0HG5RG4w1+bBJRVz/hj8UdEhr6iNdHOFj0vt6GdNWZpQDxLrJVf mJD48q6/uYzo1Z7VNNweXJpY/9nieQyTNQIYzSwU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:04 +0300 Message-Id: <20190630233817.10130-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 01/14] libcamera: Use 'files()' function to specify gen-header.sh 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: Sun, 30 Jun 2019 23:38:43 -0000 From: Kieran Bingham The files() function generates a variable with the location of the referenced files. This is shorter than joining the current_source_dir() of which use is somewhat frowned upon. Fixes: 90de3690c456 ("libcamera: Auto-generate libcamera.h") Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- include/libcamera/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 1b86fdc7fca4..15484724df01 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -14,7 +14,7 @@ libcamera_api = files([ 'timer.h', ]) -gen_header = join_paths(meson.current_source_dir(), 'gen-header.sh') +gen_header = files('gen-header.sh') libcamera_h = custom_target('gen-header', input : 'meson.build', From patchwork Sun Jun 30 23:38:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1544 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 2822A61EB4 for ; Mon, 1 Jul 2019 01:38:43 +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 D60E8255 for ; Mon, 1 Jul 2019 01:38:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937923; bh=kQl9YMkR6s3+VJwLhfNpS/6dh2JbNj8gXmx4h01+jVo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=skTiPm5bzZ9+TKSN3Fi51x855pVjMCEVPMRfn5gqQt9PEIBhNWLd/d1jBgYuuKKgK OkLpc9YhF+4gbDMsB4bNqlEOBsaA6/OdkBn9jhDghtNkkeImdaG9fGaEegmgs/g694 tePkxr77s6/Y54XDMxkaRlHz/GGB3jxZlqS0KH3w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:05 +0300 Message-Id: <20190630233817.10130-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 02/14] 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: Sun, 30 Jun 2019 23:38:43 -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 --- 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 Sun Jun 30 23:38:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1545 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 77DFC61E16 for ; Mon, 1 Jul 2019 01:38:43 +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 25D362F0 for ; Mon, 1 Jul 2019 01:38:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937923; bh=vj+T49ysYA1HwEPVQDmwtRPg3ZsFXfXS4CfKcv2ne+4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bkye0E497V3UR2IGCz7PmpTCXvqglzKN071mtNLmuPs2nGHLJME/Po0h747tERsn7 IFD524Jl6xZStLtTWwT7tDYyQXnj4UGO9rEW1Rd0c89y2r3WbQeK51e3ptu0F8nYui obNr9d4mbto3JxiQkedg68ZBJrYqvunczv+Qm38U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:06 +0300 Message-Id: <20190630233817.10130-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 03/14] 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: Sun, 30 Jun 2019 23:38:43 -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 --- 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..14f631e8ecf7 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 + * \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..59fc98cefd4e 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 + * \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 Sun Jun 30 23:38:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1546 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 DA99161E16 for ; Mon, 1 Jul 2019 01:38:43 +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 6C21E255 for ; Mon, 1 Jul 2019 01:38:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937923; bh=UytlxKPf/z4l6FpOS9kG7e0+YnoIwOqNDYmxAqnvVZk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=M4zjZSxuZFDxDzFpKigzWlVWz4ziNwk2RRCN2cUX72D7ioKCZSjLQLuOam0TL+0Eq SJ+KNdA3QOWbFMn2Ea+1r2LNsJPVdQ5ynCyBuh5uauayytlonLaeESje4ECiQpHlFR 37XRFFvT1yE3bnAcYZHqloiYExrg+GopjYNyfVtI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:07 +0300 Message-Id: <20190630233817.10130-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 04/14] 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: Sun, 30 Jun 2019 23:38:44 -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 identifies - ControlIdentier 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 --- 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 controlsTypes 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 | 428 ++++++++++++++++++++++++++++++++ src/libcamera/gen-controls.awk | 106 ++++++++ src/libcamera/meson.build | 11 + 7 files changed, 718 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..ad2d49d522c5 --- /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 { return controls_.count(info); }; + 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..22db2b93eff2 --- /dev/null +++ b/src/libcamera/controls.cpp @@ -0,0 +1,428 @@ +/* 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 + * Determines the 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 for values in 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 String representation to store + */ +ControlValue::ControlValue(int64_t value) + : type_(ControlValueInteger64), integer64_(value) +{ +} + +/** + * \fn ControlValue::type + * \brief Return the type of value represented by the object + */ + +/** + * \fn ControlValue::isNone + * \brief Determine if the value is 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. + */ +bool ControlValue::getBool() const +{ + ASSERT(type_ == ControlValueBool); + + return bool_; +} + +/** + * \brief Get the integer value. + * + * The value type must be Integer or Integer64 + */ +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 + */ +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 + * Control Identifiers + */ + +/** + * \struct ControlIdentifier + * \brief Describes 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 autogenerated 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. + */ +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 ID of the control information descriptor + * \return the ControlId + */ + +/** + * \fn ControlInfo::name() + * \brief Retrieve the string name of the control information descriptor + * \return A string name for the Control + */ + +/** + * \fn ControlInfo::type() + * \brief Retrieve the ValueType of the control information descriptor + * \return The control type + */ + +/** + * \fn ControlInfo::min() + * \brief Reports the minimum value of the control + * \return a COntrolValue with the minimum setting for the control + */ + +/** + * \fn ControlInfo::max() + * \brief Reports the maximum value of the control + * \return a ControlValue with the maximum setting 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 are compared based on their 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 are compared based on their 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 are compared based on their 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 Associates a list of ControlIds with their values for a Camera. + * + * A ControlList specifies a map of ControlIds and Values and associated + * validation against the ControlInfo for the related Camera device. + */ + +/** + * \brief Construct a ControlList with a reference to the Camera it applies on + */ +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 iterator ControlList::end() + * \brief Retrieve an iterator to the next element after the last controls in + * the instance. + * \return An iterator to the element following the last control in the instance + */ + +/** + * \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 const_iterator ControlList::end() const + * \brief Retrieve a constant iterator pointing to an empty element after the + * \return A const iterator to the element following the last control in the + * instance + */ + +/** + * \fn ControlList::contains(const ControlInfo *info) const + * \brief Check if the ist 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 + */ + +/** + * \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 all Control values with the value from the given \a list + * \param list The list of controls to update or append to this list + * + * Update all controls in the ControlList, by the values given by \a list + * If the list already contains a control of this ID then it will be overwritten + */ +void ControlList::update(const ControlList &list) +{ + if (list.camera_ != camera_) { + LOG(Controls, Error) + << "ControlLists can not be translated between cameras"; + return; + } + + for (auto it : list) { + 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..a91529b575db --- /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 control.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 autogenerated. 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 Sun Jun 30 23:38:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1547 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 44A6961F3A for ; Mon, 1 Jul 2019 01:38:44 +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 E5AB4255 for ; Mon, 1 Jul 2019 01:38:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937924; bh=yxJZTBRxCfBHP2nhsXl7xFteIyrhQl2XKqPevUtBHfo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=N/isg78xEbAcTAsagcT3qyRFgx0Z7Z5VMnzqRtAsaC1O/vIvcQhJUr0BzzLfXmQ7b arGtCCpVmxcmVFJUQrpwTp3RYFJ8kYRztHDpA8Jj/r153XEBBgClnj+Wl4Lz7B9p9d YSrblj9rp54ebPdx+ubEnNF1FQZCc0r4tVTiybqE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:08 +0300 Message-Id: <20190630233817.10130-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 05/14] 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: Sun, 30 Jun 2019 23:38:45 -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 --- 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 ad2d49d522c5..9b37dfb16b89 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 22db2b93eff2..e4c41b97a354 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -315,6 +315,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 Associates a list of ControlIds 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 Sun Jun 30 23:38:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1548 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8C8EF61F61 for ; Mon, 1 Jul 2019 01:38:44 +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 37DBB2F0 for ; Mon, 1 Jul 2019 01:38:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937924; bh=BVBYFu6vhfXllwt0xV1LM/j7sKp//ptRiAWJEu60Rlo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=U0lnhRxaeYY/wl62pwxSVbzDRSxGOGZ1kN/NGwGBhTfiRfh23iLCMkSs8kOSckXrl mLCCeo3hFgG7PZFfl+sAJ/Ddmm6/zfBREziiASjR55/Eos5pvjKZ1s9nDSPV0lm0gJ C2j19FfL06vBPDErbPbJaDtyPl7/qFCPznTBk7Lo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:09 +0300 Message-Id: <20190630233817.10130-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 06/14] 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: Sun, 30 Jun 2019 23:38:45 -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. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Jacopo Mondi --- include/libcamera/controls.h | 2 ++ src/libcamera/controls.cpp | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/include/libcamera/controls.h b/include/libcamera/controls.h index 9b37dfb16b89..d827318ee0fa 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 { return controls_.count(info); }; 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 e4c41b97a354..17e09fc7f153 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -10,6 +10,8 @@ #include #include +#include + #include "log.h" #include "utils.h" @@ -372,6 +374,30 @@ ControlList::ControlList(Camera *camera) * instance */ +/** + * \brief Check if the ist 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(); +} + /** * \fn ControlList::contains(const ControlInfo *info) const * \brief Check if the ist contains a control with the specified \a info @@ -396,6 +422,34 @@ ControlList::ControlList(Camera *camera) * \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 @@ -413,6 +467,9 @@ ControlList::ControlList(Camera *camera) * * Update all controls in the ControlList, by the values given by \a list * If the list already contains a control of this ID then it will be overwritten + * + * The behaviour is undefined if the two lists refer to different Camera + * instances. */ void ControlList::update(const ControlList &list) { From patchwork Sun Jun 30 23:38:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1549 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 D2B5961F46 for ; Mon, 1 Jul 2019 01:38:44 +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 819DF255 for ; Mon, 1 Jul 2019 01:38:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937924; bh=CsQMXeHj7pDQVn7vHWJ5yIaOzWLdc/egGpQtVEelLkw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XAZ2uZzbSuNpa/gGsB0Y07Sbk87YH8mb488emx2Ty64l8kvcfOxv5mXIGrubbA74p 8giUmLoY+gZ2lgrrRm5SY/yWw0V42dDNZfpuIJyZv/dvfhyvE//NOptpGEkYtBbghc M3zYUzQfrJkwaQu5HzrvoBorOSdRy5vskqWNruQU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:10 +0300 Message-Id: <20190630233817.10130-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 07/14] 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: Sun, 30 Jun 2019 23:38:46 -0000 From: Kieran Bingham Provide a ControlList on request objects to facilitate setting controls. Signed-off-by: Kieran Bingham --- include/libcamera/request.h | 3 +++ src/libcamera/request.cpp | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/libcamera/request.h b/include/libcamera/request.h index 58de6f00a554..8075270a9a12 100644 --- a/include/libcamera/request.h +++ b/include/libcamera/request.h @@ -11,6 +11,7 @@ #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..7d91e7f900fe 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 @@ -158,6 +168,9 @@ void Request::complete(Status status) { ASSERT(!hasPendingBuffers()); status_ = status; + + /* Controls are 'per-frame' and not re-usable */ + controls_.clear(); } /** From patchwork Sun Jun 30 23:38:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1550 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 24E1B61F67 for ; Mon, 1 Jul 2019 01:38:45 +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 C7AE22F0 for ; Mon, 1 Jul 2019 01:38:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937924; bh=C3UVZ+R+516fmXeF4hJxjytX027zeUq8ZgF+wnKrQ18=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vephlv2yznk01Bpzy5O/OhmLDpj8l8/g4prD/Ex94sfvwNUYXsLT/h1YorYiCzmna pu8/vDpl9Me46E5bhQimkeeoWbtZXpTe8d3DNbvJ7Vap3VfB0Pg7W8KbVh7kFORe10 QZfEljNnE4YEte/yFCGUgiZzAY+IerRG532HiyXQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:11 +0300 Message-Id: <20190630233817.10130-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 08/14] 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: Sun, 30 Jun 2019 23:38:46 -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 --- 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 17e09fc7f153..0fac6f69d2b7 100644 --- a/src/libcamera/controls.cpp +++ b/src/libcamera/controls.cpp @@ -179,6 +179,48 @@ std::string ControlValue::toString() const * Control Identifiers */ +/** + * \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 Describes a ControlId with control specific constant meta-data. From patchwork Sun Jun 30 23:38:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1551 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7846A61F3A for ; Mon, 1 Jul 2019 01:38:45 +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 1B232BC5 for ; Mon, 1 Jul 2019 01:38:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937925; bh=uoC0+3e4gZCQL+TPsJ3lWagINWmWETTe6AMv9Hh8+Tc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=dfgfXwXM28vRYvhtvodcAfDFvLDZKZlH7d8rGxd7IJFB2pzWpsVQ6yikMGDBHC7Bv nRgtgINY8pyYQRS82g0XZXk9Mhr/i5Q7h9wbmqZSb4Zzlg9vDX+OYMvSHQ6IbPqhRv QGCWDuzyQnyv4wxteKTi5XaGSuOdJSpaMxDV9+QE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:12 +0300 Message-Id: <20190630233817.10130-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 09/14] 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: Sun, 30 Jun 2019 23:38:47 -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 --- src/libcamera/pipeline/uvcvideo.cpp | 129 +++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 14 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 2e22523d7cb1..f68dc5bd6f74 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,54 @@ 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"; + + return ret; +} + int PipelineHandlerUVC::queueRequest(Camera *camera, Request *request) { UVCCameraData *data = cameraData(camera); @@ -227,7 +282,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 +306,14 @@ 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); - break; + if (data->init(entity)) + return false; } } - if (!data->video_) { - LOG(UVC, Error) << "Could not find a default video device"; - return false; - } - - 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 +325,58 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) return true; } +int UVCCameraData::init(MediaEntity *entity) +{ + int ret; + + /* Create and open the video device. */ + video_ = new V4L2VideoDevice(entity); + if (!video_) { + LOG(UVC, Error) << "Could not find a default video device"; + return -ENODEV; + } + + 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 Sun Jun 30 23:38:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1552 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BBCA561F74 for ; Mon, 1 Jul 2019 01:38:45 +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 62C702F0 for ; Mon, 1 Jul 2019 01:38:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937925; bh=VhOtoNNCSjMgydO5HMbTNoaRYEggWyxCXcNgLdgFwyk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=wKy4mAfX6tM2iTcUBzaEwihc9LjygOWsfD0bN8vJDcIiTzURv6WdboPwhjoCVaXxi FEifQ+lEf3q4f457Q8CcUI99PjBmWLqhsyVLOl/ioQf3NG9QfNWF2GDewVwzJCAALh GlKguCSw86CmB3+xhTrsShbLd5wlV3DtnOrzQXvs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:13 +0300 Message-Id: <20190630233817.10130-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 10/14] 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: Sun, 30 Jun 2019 23:38:47 -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 --- src/libcamera/pipeline/vimc.cpp | 105 ++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 5 deletions(-) diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 6833213650dc..fb073f2d078e 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,45 @@ 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"; + + return ret; +} + int PipelineHandlerVimc::queueRequest(Camera *camera, Request *request) { VimcCameraData *data = cameraData(camera); @@ -226,7 +275,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 +315,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 +327,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 Sun Jun 30 23:38:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1553 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 073D761F70 for ; Mon, 1 Jul 2019 01:38:46 +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 A7156BC5 for ; Mon, 1 Jul 2019 01:38:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937925; bh=GHlMySBi5xqeUwYJNAOLGl2fTK8C15O+d7MdvuQ3lss=; h=From:To:Subject:Date:In-Reply-To:References:From; b=deVADEiPfJvi3xSXUP1QZveIrJWiBwaZInDOSDejvfOMiwbyWFNy99YFRIIN1CZNU zVvSoMUIpYNzPSZ8T+ebeHak8CQ5U8V3EE5K/H1jSXu443kSfGmLX15V4mXa7RuJGI hZxE3wA6Vi77gPXgmRJnVctvE9vGPOUyZHEdbBSM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:14 +0300 Message-Id: <20190630233817.10130-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 11/14] 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: Sun, 30 Jun 2019 23:38:47 -0000 From: Kieran Bingham Add initial basic testing for the new ControlValue class. Signed-off-by: Kieran Bingham --- 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 Sun Jun 30 23:38:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1554 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 41BD161F7C for ; Mon, 1 Jul 2019 01:38:46 +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 EDF8B2F0 for ; Mon, 1 Jul 2019 01:38:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937926; bh=PXVWkAZU9N/gTgufqV4/MXpcO3dQqPOekospj4fc+yU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=t92+GHIlRO38qWeWUk4vsbajTcstrvyOE14v02gU3rHgeqcNthTuVK4K2lZJUpjVM RWqOYkiFRSqBsYus3nHf/7nufb2yLPZqZExurWm1synWV+0y6GVYtxlsnNSRmd4KkL Wv0cBwnbAGz7XhkeX+g13KrrY1ZwnQGEqb25TRP4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:15 +0300 Message-Id: <20190630233817.10130-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 12/14] 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: Sun, 30 Jun 2019 23:38:47 -0000 From: Kieran Bingham Provide an initial test coverage for the ControlInfo class. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart --- 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 Sun Jun 30 23:38:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1555 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A179461F41 for ; Mon, 1 Jul 2019 01:38:46 +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 411731214 for ; Mon, 1 Jul 2019 01:38:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937926; bh=GpI0w1AfwKmT2AQKF+PZAkjbN548YkhJCCn67q3xugM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=IAcEZ0oVj9wwmdjYJ/XEPtkanhWpi1HIy7R7DBfppswh1tqnJPpzlkZNpsah4ZyXc 8j3QEE9ovQr3d914K1t0hFyn36W7xc78gpfT+ubWofw7TKDngEl+mBr/PNpYjy3YrR nFPDCH1isZzGxe/F9iVgdqeedQRBPBZf4bEZlPAc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:16 +0300 Message-Id: <20190630233817.10130-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 13/14] 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: Sun, 30 Jun 2019 23:38:47 -0000 From: Kieran Bingham Add tests of the ControlList infrastructure and public API. Signed-off-by: Kieran Bingham --- 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 Sun Jun 30 23:38:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1556 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 D282161F46 for ; Mon, 1 Jul 2019 01:38:46 +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 895BB1200 for ; Mon, 1 Jul 2019 01:38:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1561937926; bh=PIlqXsOiLQbKLx2Pi8tqvo7q5gEcHawdRl3WYeCSX6M=; h=From:To:Subject:Date:In-Reply-To:References:From; b=reEWDUW0LplV9U/+f8NOGJPJmm6h4vlBAPcI25hCEppQm9dnd1mtH5c78vawSjnha NRE+RprmfBTM1Gbb9N9m3hyqmAqWyL5zgwrBZ0lFfxxhNg/CDOv6eb2AnUTGwNLX28 qg5edINi775zL2JxJHZ0onQ5Ll8p1ZBJcq0/aP4M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 1 Jul 2019 02:38:17 +0300 Message-Id: <20190630233817.10130-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> References: <20190630233817.10130-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 14/14] [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: Sun, 30 Jun 2019 23:38:47 -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_; };