From patchwork Mon Jun 10 16:40:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1382 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 24C51635DC for ; Mon, 10 Jun 2019 18:39:46 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id B4ADD240007; Mon, 10 Jun 2019 16:39:45 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:47 +0200 Message-Id: <20190610164052.30741-2-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 1/6] libcamera: camera_sensor: Add dev() operation 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, 10 Jun 2019 16:39:46 -0000 Add dev() operation to the CameraSensor class to access the V4L2Subdevice backing the camera sensor. Signed-off-by: Jacopo Mondi --- src/libcamera/camera_sensor.cpp | 6 ++++++ src/libcamera/include/camera_sensor.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 2b9d8fa593c1..8cbef8bccbef 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -130,6 +130,12 @@ int CameraSensor::init() * \return The sensor media entity */ +/** + * \fn CameraSensor::dev() + * \brief Retrieve the sensor V4L2 subdevice + * \return The sensor V4L2 subdevice + */ + /** * \fn CameraSensor::mbusCodes() * \brief Retrieve the media bus codes supported by the camera sensor diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h index b823480241a7..6cdf833a27bf 100644 --- a/src/libcamera/include/camera_sensor.h +++ b/src/libcamera/include/camera_sensor.h @@ -33,6 +33,7 @@ public: int init(); const MediaEntity *entity() const { return entity_; } + V4L2Subdevice *dev() const { return subdev_; } const std::vector &mbusCodes() const { return mbusCodes_; } const std::vector &sizes() const { return sizes_; } const Size &resolution() const; From patchwork Mon Jun 10 16:40:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1383 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B3AAF635DC for ; Mon, 10 Jun 2019 18:39:46 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 4D8AA240007; Mon, 10 Jun 2019 16:39:46 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:48 +0200 Message-Id: <20190610164052.30741-3-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/6] libcamera: Provide a V4L2Base class 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, 10 Jun 2019 16:39:47 -0000 Provide a base class for V4L2 Devices and Subdevices to group common methods and fields. At the moment the code shared between V4L2Device and V4L2Subdevice is quite limited, but with the forthcoming introduction of control it will grow consistently. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_base.h | 31 +++++++++++++ src/libcamera/include/v4l2_device.h | 9 ++-- src/libcamera/include/v4l2_subdevice.h | 9 ++-- src/libcamera/meson.build | 2 + src/libcamera/v4l2_base.cpp | 64 ++++++++++++++++++++++++++ src/libcamera/v4l2_device.cpp | 13 ++---- src/libcamera/v4l2_subdevice.cpp | 12 +---- 7 files changed, 110 insertions(+), 30 deletions(-) create mode 100644 src/libcamera/include/v4l2_base.h create mode 100644 src/libcamera/v4l2_base.cpp diff --git a/src/libcamera/include/v4l2_base.h b/src/libcamera/include/v4l2_base.h new file mode 100644 index 000000000000..2fda81a960d2 --- /dev/null +++ b/src/libcamera/include/v4l2_base.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_base.h - Common base for V4L2 devices and subdevices + */ +#ifndef __LIBCAMERA_V4L2_BASE__ +#define __LIBCAMERA_V4L2_BASE__ + +#include + +namespace libcamera { + +class V4L2Base +{ +public: + virtual ~V4L2Base() + { + } + + virtual int open() = 0; + virtual void close() = 0; + bool isOpen() const; + +protected: + int fd_; +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_BASE__ */ diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index bdecc087fe5a..d9bcdb921b8c 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -17,6 +17,7 @@ #include #include "log.h" +#include "v4l2_base.h" namespace libcamera { @@ -111,7 +112,7 @@ public: const std::string toString() const; }; -class V4L2Device : protected Loggable +class V4L2Device : public V4L2Base, protected Loggable { public: explicit V4L2Device(const std::string &deviceNode); @@ -121,9 +122,8 @@ public: V4L2Device &operator=(const V4L2Device &) = delete; - int open(); - bool isOpen() const; - void close(); + int open() override; + void close() override; const char *driverName() const { return caps_.driver(); } const char *deviceName() const { return caps_.card(); } @@ -167,7 +167,6 @@ private: void bufferAvailable(EventNotifier *notifier); std::string deviceNode_; - int fd_; V4L2Capability caps_; enum v4l2_buf_type bufferType_; diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 3e4e5107aebe..bdef3e69dd8c 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -16,6 +16,7 @@ #include "formats.h" #include "log.h" #include "media_object.h" +#include "v4l2_base.h" namespace libcamera { @@ -28,7 +29,7 @@ struct V4L2SubdeviceFormat { const std::string toString() const; }; -class V4L2Subdevice : protected Loggable +class V4L2Subdevice : public V4L2Base, protected Loggable { public: explicit V4L2Subdevice(const MediaEntity *entity); @@ -36,9 +37,8 @@ public: V4L2Subdevice &operator=(const V4L2Subdevice &) = delete; ~V4L2Subdevice(); - int open(); - bool isOpen() const; - void close(); + int open() override; + void close() override; const MediaEntity *entity() const { return entity_; } @@ -64,7 +64,6 @@ private: Rectangle *rect); const MediaEntity *entity_; - int fd_; }; } /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6a73580d71f5..6d858a22531e 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -21,6 +21,7 @@ libcamera_sources = files([ 'stream.cpp', 'timer.cpp', 'utils.cpp', + 'v4l2_base.cpp', 'v4l2_device.cpp', 'v4l2_subdevice.cpp', ]) @@ -38,6 +39,7 @@ libcamera_headers = files([ 'include/media_object.h', 'include/pipeline_handler.h', 'include/utils.h', + 'include/v4l2_base.h', 'include/v4l2_device.h', 'include/v4l2_subdevice.h', ]) diff --git a/src/libcamera/v4l2_base.cpp b/src/libcamera/v4l2_base.cpp new file mode 100644 index 000000000000..7d05a3c82e4d --- /dev/null +++ b/src/libcamera/v4l2_base.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_base.cpp - Common base for V4L2 devices and subdevices + */ + +#include "v4l2_base.h" + +/** + * \file v4l2_base.h + * \brief Common base for V4L2 devices and subdevices + */ + +namespace libcamera { + +/** + * \class V4L2Base + * \brief Base class for V4L2Device and V4L2Subdevice + * + * The V4L2Base class groups together the methods and fields common to + * both V4L2Device and V4L2Subdevice, and provide a base abstract class which + * defines a streamlined interface that both the derived class have to implement. + * + * The interface defined by V4L2Base only requires derived classes to implement + * methods that modifies the status of the file descriptor associated with + * the video device or subdevice, such as \a open() and \a close(). + * + * Methods common to V4L2Device and V4L2Subdevice, such as V4L2 controls + * support are implemented in the base class to maximize code re-use. + */ + +/** + * \brief Open a V4L2 device or subdevice + * + * Pure virtual method to be implemented by the derived classes. + * + * \return 0 on success or a negative error code otherwise + */ + +/** + * \brief Close the device or subdevice + * + * Pure virtual method to be implemented by the derived classes. + */ + +/** + * \brief Check if the V4L2 device or subdevice is open + * \return True if the V4L2 device or subdevice is open, false otherwise + */ +bool V4L2Base::isOpen() const +{ + return fd_ != -1; +} + +/** + * \var V4L2Base::fd_ + * \brief The V4L2 device or subdevice device node file descriptor + * + * The file descriptor is initialized to -1 and reset to this value once + * the device or subdevice gets closed. + */ + +}; /* namespace libcamera */ diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 0821bd75fb42..64533e88a512 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -270,9 +270,11 @@ const std::string V4L2DeviceFormat::toString() const * \param[in] deviceNode The file-system path to the video device node */ V4L2Device::V4L2Device(const std::string &deviceNode) - : deviceNode_(deviceNode), fd_(-1), bufferPool_(nullptr), + : deviceNode_(deviceNode), bufferPool_(nullptr), queuedBuffersCount_(0), fdEvent_(nullptr) { + fd_ = -1; + /* * We default to an MMAP based CAPTURE device, however this will be * updated based upon the device capabilities. @@ -368,15 +370,6 @@ int V4L2Device::open() return 0; } -/** - * \brief Check if device is successfully opened - * \return True if the device is open, false otherwise - */ -bool V4L2Device::isOpen() const -{ - return fd_ != -1; -} - /** * \brief Close the device, releasing any resources acquired by open() */ diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index fceee33156e9..3a053fadb3f6 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -102,8 +102,9 @@ const std::string V4L2SubdeviceFormat::toString() const * path */ V4L2Subdevice::V4L2Subdevice(const MediaEntity *entity) - : entity_(entity), fd_(-1) + : entity_(entity) { + fd_ = -1; } V4L2Subdevice::~V4L2Subdevice() @@ -137,15 +138,6 @@ int V4L2Subdevice::open() return 0; } -/** - * \brief Check if the subdevice is open - * \return True if the subdevice is open, false otherwise - */ -bool V4L2Subdevice::isOpen() const -{ - return fd_ != -1; -} - /** * \brief Close the subdevice, releasing any resources acquired by open() */ From patchwork Mon Jun 10 16:40:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1384 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7F35D635E9 for ; Mon, 10 Jun 2019 18:39:47 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id DE2DA24000B; Mon, 10 Jun 2019 16:39:46 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:49 +0200 Message-Id: <20190610164052.30741-4-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 3/6] libcamera: Add V4L2Controls 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, 10 Jun 2019 16:39:48 -0000 Add Libcamera V4L2 control support, implemented using the V4L2 Extended Control APIs. This patch defines the types used to define and manage controls. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_controls.h | 210 +++++++++ src/libcamera/meson.build | 1 + src/libcamera/v4l2_controls.cpp | 632 ++++++++++++++++++++++++++ 3 files changed, 843 insertions(+) create mode 100644 src/libcamera/include/v4l2_controls.h create mode 100644 src/libcamera/v4l2_controls.cpp diff --git a/src/libcamera/include/v4l2_controls.h b/src/libcamera/include/v4l2_controls.h new file mode 100644 index 000000000000..bca5ccc29de3 --- /dev/null +++ b/src/libcamera/include/v4l2_controls.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_controls.h - V4L2 Extended Control Support + */ + +#ifndef __LIBCAMERA_V4L2_CONTROLS_H__ +#define __LIBCAMERA_V4L2_CONTROLS_H__ + +#include +#include +#include + +#include + +#include +#include + +namespace libcamera { + +class V4L2Control +{ +public: + virtual ~V4L2Control() + { + } + + unsigned int id() { return id_; } + unsigned int size() { return size_; } + enum v4l2_ctrl_type type() const { return type_; } + +protected: + V4L2Control(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type) + : id_(id), size_(size), type_(type) + { + } + +private: + unsigned int id_; + unsigned int size_; + enum v4l2_ctrl_type type_; +}; + +template +class V4L2ControlValue : public V4L2Control +{ +public: + T value() const { return value_; } + T *mem() const { return mem_; } + +protected: + V4L2ControlValue(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type, T value) + : V4L2Control(id, size, type) + { + value_ = value; + mem_ = nullptr; + } + + V4L2ControlValue(unsigned int id, unsigned int size, + enum v4l2_ctrl_type type, T *value) + : V4L2Control(id, size, type) + { + value_ = 0; + mem_ = static_cast(new T[size]); + memcpy(mem_, value, size); + } + + ~V4L2ControlValue() + { + delete[] mem_; + } + +private: + T value_; + T *mem_; +}; + +class V4L2IntControl : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2IntControl(unsigned int id, int32_t value) + : V4L2ControlValue(id, sizeof(int32_t), + V4L2_CTRL_TYPE_INTEGER, value) + { + } +}; + +class V4L2Int64Control : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2Int64Control(unsigned int id, int64_t value) + : V4L2ControlValue(id, sizeof(int64_t), + V4L2_CTRL_TYPE_INTEGER64, value) + { + } +}; + +class V4L2BoolControl : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2BoolControl(unsigned int id, bool value) + : V4L2ControlValue(id, sizeof(bool), + V4L2_CTRL_TYPE_BOOLEAN, value) + { + } +}; + +class V4L2StringControl : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2StringControl(unsigned int id, std::string value) + : V4L2ControlValue(id, value.length(), + V4L2_CTRL_TYPE_STRING, value) + { + } +}; + +class V4L2U8Control : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2U8Control(unsigned int id, unsigned int size, uint8_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U8, mem) + { + } +}; + +class V4L2U16Control : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U16, mem) + { + } +}; + +class V4L2U32Control : public V4L2ControlValue +{ +private: + friend class V4L2Controls; + + V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem) + : V4L2ControlValue(id, size, V4L2_CTRL_TYPE_U32, mem) + { + } +}; + +class V4L2Controls { +public: + ~V4L2Controls() + { + clear(); + } + + using iterator = std::vector::iterator; + using const_iterator = std::vector::const_iterator; + + iterator begin() { return controls_.begin(); } + const_iterator begin() const { return controls_.begin(); } + iterator end() { return controls_.end(); } + const_iterator end() const { return controls_.end(); } + + size_t size() { return controls_.size(); } + void clear(); + + V4L2Control *operator[](unsigned int index) const + { + return controls_[index]; + } + + bool empty() const { return controls_.size() == 0; } + + void set(unsigned int id, unsigned int value); + void set(unsigned int id, int32_t value); + void set(unsigned int id, int64_t value); + void set(unsigned int id, bool value); + void set(unsigned int id, std::string value); + void set(unsigned int id, size_t size, uint8_t *value); + void set(unsigned int id, size_t size, uint16_t *value); + void set(unsigned int id, size_t size, uint32_t *value); + + int32_t getInt(unsigned int id); + int64_t getInt64(unsigned int id); + bool getBool(unsigned int id); + std::string getString(unsigned int id); + uint8_t *getU8(unsigned int id); + uint16_t *getU16(unsigned int id); + uint32_t *getU32(unsigned int id); + +private: + std::vector controls_; +}; + +}; /* namespace libcamera */ + +#endif /* __LIBCAMERA_V4L2_CONTROLS_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 6d858a22531e..fa1fbcb5faf5 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -22,6 +22,7 @@ libcamera_sources = files([ 'timer.cpp', 'utils.cpp', 'v4l2_base.cpp', + 'v4l2_controls.cpp', 'v4l2_device.cpp', 'v4l2_subdevice.cpp', ]) diff --git a/src/libcamera/v4l2_controls.cpp b/src/libcamera/v4l2_controls.cpp new file mode 100644 index 000000000000..bd68d07f37bf --- /dev/null +++ b/src/libcamera/v4l2_controls.cpp @@ -0,0 +1,632 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * v4l2_controls.cpp - V4L2 Extended Control Support + */ + +#include "v4l2_controls.h" + +/** + * \file v4l2_controls.h + * \brief Support for V4L2 Controls using the V4L2 Extended Controls APIs. + * + * The V4L2 defined "Control API" allows application to inspect and modify set + * of configurable parameters on the video device or subdevice of interest. The + * nature of the parameters an application could modify using the control + * framework depends on what the driver implements support for, and on the + * characteristics of the underlying hardware platform. Generally controls are + * used to modify user visible settings, such as the image brightness and + * exposure time, or non-standard parameters which cannot be controlled through + * the V4L2 format negotiation API. + * + * Controls are identified by a numerical id, defined by the V4L2 kernel headers + * and have an associated type and class. Each control has a 'value', which is + * the data that can be modified with a 'V4L2Base::setControl()' operation call + * or retrieved with a 'V4L2Base::getControl()' one. + * + * A control class defines the control purpose while its type (along with the + * control's flags) defines the type of the control's value content. Controls + * might transport a single data value stored in variable inside the control, or + * they might as well deal with more complex data types, such as arrays of + * matrices, stored in a contiguous memory locations associated with the control + * and called 'the payload'. The content have to be opportunely copied into the + * application memory when retrieving a control's value and provided to the V4L2 + * device when setting it. + * + * Libcamera supports control using the V4L2 'Extended Control' framework, which + * allows easier handling of controls with payloads of arbitrary sizes. + * + * The Libcamera V4L2 Controls framework operates on lists of controls, wrapped + * by the V4L2Controls class, to match the V4L2 extended controls framework. + * The interface to set and get control is implemented by the V4L2Base class, + * while this file only provides the data type definitions. + * + * The Libcamera V4L2 control framework define a base class + * V4L2Control that contains the fields common to all controls, regardless of + * their type, such as the control's id, its type and the expected control's + * value data size. The V4L2Control class is not meant to be instantiated + * directly, but is instead used as placeholder to store controls inside the + * publicly constructible V4L2Controls class. + * + * A parametric derived class V4L2ControlValue stores the control's value and + * provide accessors to the data values for controls with no payload, or to the + * memory area that contains the control's data payload. These classes are not + * intended to be directly used and cannot be constructed, but are used instead + * to define specialized derived classes which provide accessors to the + * control's data values. + * + * In order to set and get controls, user of the Libcamera V4L2 control + * framework should operate on instances of the V4L2Controls class, iterating + * on the V4L2Controls it contains, and use the V4L2Controls::set() and + * V4L2Controls::get() methods to set or access the control's data + * content. + * + * \todo Support setting controls with data payload. + */ + +namespace libcamera { + +/** + * \class V4L2Control + * \brief Base class for V4L2 Controls + * + * The V4L2Control base class is the base class that contains the fields common + * to all controls (id, type and size). + * + * This class is not meant to be instantiated directly, but is instead used as a + * place holder to store controls in arrays or other containers. User of the + * libcamera V4L2 control framework should access the controls content by + * using accessors provided by the V4L2Controls class. + */ + +/** + * \fn V4L2Control::V4L2Control + * \brief Construct a V4L2Control instance + * \param id The control's id + * \param size The control's data size + * \param type The control's type + */ + +/** + * \fn V4L2Control::id() + * \brief Retrieve the control's id + * + * Retrieve the control's numerical id value as defined by the V4L2 + * specification. + * + * \return The control's id + */ + +/** + * \fn V4L2Control::size() + * \brief Retrieve the control's data value size in bytes + * + * \todo Better define the value of size() for controls with payload data. + * + * \return The control's size + */ + +/** + * \fn V4L2Control::type() + * \brief Retrieve the control's type + * + * Retrieve the control's type as defined by the V4L2 specification. + * + * \return The control's type + */ + +/** + * \class V4L2ControlValue + * \brief Template base class that represent values of a V4L2 control + * + * The V4L2ControlValue template base class represents a V4L2 control with + * its different value types. + * + * It provides two operations to access the control's value or the pointer + * to the memory location that contains to the control's value data payload. + */ + +/** + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T value) + * \brief Contruct a V4L2ControlValue with a parametric value + * \param id The control's id + * \param size The control's size + * \param type The control's type + * \param value The control's value + */ + +/** + * \fn V4L2ControlValue::V4L2ControlValue(unsigned int id, unsigned int size, enum v4l2_ctrl_type type, T* value) + * \brief Contruct a V4L2ControlValue with a pointer to a data payload + * \param id The control's id + * \param size The control's size + * \param type The control's type + * \param value The pointer to the control's data payload + */ + +/** + * \fn V4L2ControlValue::~V4L2ControlValue + * \brief Release the memory reserved for the control's data payload, if any + */ + +/** + * \fn V4L2ControlValue::value() + * \brief Retrieve the control's value + * + * Retrieve the control's value. Valid only for controls with no payload. + */ + +/** + * \fn V4L2ControlValue::mem() + * \brief Retrieve a pointer to the memory location of the control's data + * + * Retrieve a pointer to the memory location that contains the control's data + * payload. Valid only for controls with data payload. + */ + +/** + * \class V4L2IntControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_INTEGER type. + * + * Access to the control's data value by using the value() operation is + * restricted to the proxy V4L2Controls class. + */ + +/** + * \fn V4L2IntControl::V4L2IntControl() + * \brief Construct a V4L2Control that contains an int value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2Int64Control + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_INTEGER64 type. + * + * Access to the control's data value by using the value() operation is + * restricted to the proxy V4L2Controls class. + */ + +/** + * \fn V4L2Int64Control::V4L2Int64Control() + * \brief Construct a V4L2Control that contains an int64 value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2BoolControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_BOOLEAN type. + * + * + * Access to the control's data value by using the value() operation is + * restricted to the proxy V4L2Controls class. + */ + +/** + * \fn V4L2BoolControl::V4L2BoolControl() + * \brief Construct a V4L2Control that contains a boolean value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2StringControl + * \brief Specialized V4L2Control class that handles controls of + * V4L2_CTRL_TYPE_STRING type. + * + * Access to the control's data value by using the value() operation is + * restricted to the proxy V4L2Controls class. + */ + +/** + * \fn V4L2StringControl::V4L2StringControl() + * \brief Construct a V4L2Control that contains a string value + * \param id The control's id + * \param value The control's value + */ + +/** + * \class V4L2U8Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U8 type. + * + * Access to the control's mem() operation is reserved to the V4L2Controls + * proxy class. The size of the payload data can be retrieved with the size() + * operation. + */ + +/** + * \fn V4L2U8Control::V4L2U8Control() + * \brief Construct a V4L2Control with payload of uin8_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +/** + * \class V4L2U16Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U16 type. + * + * Access to the control's mem() operation is reserved to the V4L2Controls + * proxy class. The size of the payload data can be retrieved with the size() + * operation. + */ + +/** + * \fn V4L2U16Control::V4L2U16Control(unsigned int id, unsigned int size, uint16_t *mem) + * \brief Construct a V4L2Control with payload of uin16_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +/** + * \class V4L2U32Control + * \brief Specialized V4L2Control class that handles controls with payload of + * V4L2_CTRL_TYPE_U32 type. + * + * Access to the control's mem() operation is reserved to the V4L2Controls + * proxy class. The size of the payload data can be retrieved with the size() + * operation. + */ + +/** + * \fn V4L2U32Control::V4L2U32Control(unsigned int id, unsigned int size, uint32_t *mem) + * \brief Construct a V4L2Control with payload of uin32_t data + * \param id The control's id + * \param size The size in bytes of the payload content + * \param mem Pointer to the memory location of the payload content + * + * Memory is reserved in the newly created instance to hold the data payload + * and the data content is copied there. The reserved memory is then freed when + * the Control is destroyed. The memory where the control's payload was copied + * from should be released by the caller. + */ + +/** + * \class V4L2Controls + * \brief Wraps a list of V4L2Control and provide accessors to each control's + * data + * + * The V4L2Controls class works as a wrapper for a list of V4L2Control + * instances. The class provides operations to add a new control (set()) and + * to get back it's content. + * + * User of the Libcamera V4L2 control framework which want to set controls on + * a video device or subdevice should create instances of the V4L2Controls + * class and start filling it with control values. Once ready the instance + * should be passed to the V4L2Base::setControls() operation, that applies the + * control values to the underlying hardware. + * + * When reading control, a V4L2Controls instance is passed to the + * V4L2Base::getControls() operation, along with a list of control IDs, and it + * filled by the V4L2Base operation with V4L2Control instances, the user can + * access by ID using on the provided V4L2Controls::get() operations. + */ + +/** + * \fn V4L2Controls::~V4L2Controls() + * \brief Destroy all V4L2Control stored in the instance + * + * \sa V4L2Controls::clear() + */ + +/** + * \typedef V4L2Controls::iterator + * \brief Iterator on the V4L2 controls contained in the V4L2Controls + */ + +/** + * \typedef CameraConfiguration::const_iterator + * \brief Const iterator on the V4L2 controls contained in the V4L2Controls + */ + +/** + * \fn V4L2Controls::begin + * \brief Retrieve an iterator to the first V4L2Control in the sequence + * \return An iterator to the first V4L2 control + */ + +/** + * \fn iterator V4L2Controls::begin() + * \brief Retrieve an iterator to the first V4L2Control in the sequence + * \return An iterator to the first V4L2 control + */ + +/** + * \fn const_iterator V4L2Controls::begin() const + * \brief Retrieve a constant iterator to the first V4L2Control in the sequence + * \return A constant iterator to the first V4L2 control + */ + +/** + * \fn iterator V4L2Controls::end() + * \brief Retrieve an iterator pointing to the past-the-end V4L2Control in the + * sequence + * \return An iterator to the element following the last V4L2 control in the + * sequence + */ + +/** + * \fn const_iterator V4L2Controls::end() const + * \brief Retrieve a constant iterator pointing to the past-the-end V4L2Control + * in the sequence + * \return A constant iterator to the element following the last V4L2 control + * in the sequence + */ + +/** + * \fn V4L2Controls::size() + * \brief Retrieve the number on stored controls + * \return The number of V4L2Control stored in the instance + */ + +/** + * \brief Destroy each control stored in the instance + * + * Destroy all the V4L2Control instances stored in this V4L2Controls instance. + * Reset the instance size to 0, and release all memory reserved by each + * control. + */ +void V4L2Controls::clear() +{ + for (unsigned int i = 0; i < controls_.size(); ++i) + delete controls_[i]; + + controls_.clear(); +} + +/** + * \fn V4L2Controls::operator[] + * \brief Access the control at index \a index + * \param index The index to access + */ + +/** + * \fn V4L2Controls::empty() + * \brief Retrieve if the instance is empty + * \return True if the instance does not contain any control, false otherwise + */ + +/** + * \brief Store a new control with integer value + * \param id The control's id + * \param value The control's value + */ +void V4L2Controls::set(unsigned int id, unsigned int value) +{ + set(id, static_cast(value)); +} + +/** + * \brief Store a new control with integer value + * \param id The control's id + * \param value The control's value + */ +void V4L2Controls::set(unsigned int id, int32_t value) +{ + V4L2IntControl *c = new V4L2IntControl(id, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with 64-bit integer value + * \param id The control's id + * \param value The control's value + */ +void V4L2Controls::set(unsigned int id, int64_t value) +{ + V4L2Int64Control *c = new V4L2Int64Control(id, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with boolean value + * \param id The control's id + * \param value The control's value + */ +void V4L2Controls::set(unsigned int id, bool value) +{ + V4L2BoolControl *c = new V4L2BoolControl(id, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with string value + * \param id The control's id + * \param value The control's value + */ +void V4L2Controls::set(unsigned int id, std::string value) +{ + V4L2StringControl *c = new V4L2StringControl(id, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with pointer to payload + * \param id The control's id + * \param size The payload size + * \param value The pointer to the data payload + */ +void V4L2Controls::set(unsigned int id, size_t size, uint8_t *value) +{ + V4L2U8Control *c = new V4L2U8Control(id, size, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with pointer to payload + * \param id The control's id + * \param size The payload size + * \param value The pointer to the data payload + */ +void V4L2Controls::set(unsigned int id, size_t size, uint16_t *value) +{ + V4L2U16Control *c = new V4L2U16Control(id, size, value); + controls_.push_back(c); +} + +/** + * \brief Store a new control with pointer to payload + * \param id The control's id + * \param size The payload size + * \param value The pointer to the data payload + */ +void V4L2Controls::set(unsigned int id, size_t size, uint32_t *value) +{ + V4L2U32Control *c = new V4L2U32Control(id, size, value); + controls_.push_back(c); + +} + +/** + * \brief Retrieve the control's integer value + * \param id The control's id + * \return The value of control with \a id, a negative error code if the control + * does not exist in the instance + */ +int32_t V4L2Controls::getInt(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2IntControl *ic = static_cast(c); + return ic->value(); + } + + return -EINVAL; +} + +/** + * \brief Retrieve the control's 64-bit integer value + * \param id The control's id + * \return The value of control with \a id, a negative error code if the control + * does not exist in the instance + */ +int64_t V4L2Controls::getInt64(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2Int64Control *ic = static_cast(c); + return ic->value(); + } + + return -EINVAL; +} + +/** + * \brief Retrieve the control's boolean value + * \param id The control's id + * \return The value of control with \a id, false if the control does not exist + * in the instance + */ +bool V4L2Controls::getBool(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2BoolControl *ic = static_cast(c); + return ic->value(); + } + + return false; +} + +/** + * \brief Retrieve the control's string value + * \param id The control's id + * \return The value of control with \a id, an empty string if the control + * does not exist in the instance + */ +std::string V4L2Controls::getString(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2StringControl *ic = static_cast(c); + return ic->value(); + } + + return ""; +} + +/** + * \brief Retrieve a pointer to the control's payload + * \param id The control's id + * \return A pointer to the control's payload, nullptr if the control + * does not exist in the instance + */ +uint8_t *V4L2Controls::getU8(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2U8Control *ic = static_cast(c); + return ic->mem(); + } + + return nullptr; + +} + +/** + * \brief Retrieve a pointer to the control's payload + * \param id The control's id + * \return A pointer to the control's payload, nullptr if the control + * does not exist in the instance + */ +uint16_t *V4L2Controls::getU16(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2U16Control *ic = static_cast(c); + return ic->mem(); + } + + return nullptr; +} + +/** + * \brief Retrieve a pointer to the control's payload + * \param id The control's id + * \return A pointer to the control's payload, nullptr if the control + * does not exist in the instance + */ +uint32_t *V4L2Controls::getU32(unsigned int id) +{ + for (V4L2Control *c : controls_) { + if (c->id() != id) + continue; + + V4L2U32Control *ic = static_cast(c); + return ic->mem(); + } + + return nullptr; +} + +}; /* namespace libcamera */ From patchwork Mon Jun 10 16:40:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1385 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1F158635E7 for ; Mon, 10 Jun 2019 18:39:48 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id A204A240008; Mon, 10 Jun 2019 16:39:47 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:50 +0200 Message-Id: <20190610164052.30741-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 4/6] libcamera: v4l2_base: Add V4L2 control 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, 10 Jun 2019 16:39:49 -0000 Implement operations to set and get V4L2 controls in the V4L2Base class. The operations allow to set and get a single or a list of controls. Signed-off-by: Jacopo Mondi --- src/libcamera/include/v4l2_base.h | 11 ++ src/libcamera/v4l2_base.cpp | 238 ++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/src/libcamera/include/v4l2_base.h b/src/libcamera/include/v4l2_base.h index 2fda81a960d2..17ea734c8f49 100644 --- a/src/libcamera/include/v4l2_base.h +++ b/src/libcamera/include/v4l2_base.h @@ -9,6 +9,8 @@ #include +#include + namespace libcamera { class V4L2Base @@ -22,8 +24,17 @@ public: virtual void close() = 0; bool isOpen() const; + int getControls(std::vector &ctrl_ids, + V4L2Controls *ctrls); + int setControls(V4L2Controls &ctrls); + protected: int fd_; + +private: + int queryControl(unsigned int ctrl_id, + struct v4l2_query_ext_ctrl *qext_ctrl); + }; }; /* namespace libcamera */ diff --git a/src/libcamera/v4l2_base.cpp b/src/libcamera/v4l2_base.cpp index 7d05a3c82e4d..cbd7a551130f 100644 --- a/src/libcamera/v4l2_base.cpp +++ b/src/libcamera/v4l2_base.cpp @@ -5,7 +5,13 @@ * v4l2_base.cpp - Common base for V4L2 devices and subdevices */ +#include +#include +#include + +#include "log.h" #include "v4l2_base.h" +#include "v4l2_controls.h" /** * \file v4l2_base.h @@ -14,6 +20,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(V4L2Base) + /** * \class V4L2Base * \brief Base class for V4L2Device and V4L2Subdevice @@ -31,6 +39,7 @@ namespace libcamera { */ /** + * \fn V4L2Base::open() * \brief Open a V4L2 device or subdevice * * Pure virtual method to be implemented by the derived classes. @@ -39,6 +48,7 @@ namespace libcamera { */ /** + * \fn V4L2Base::close() * \brief Close the device or subdevice * * Pure virtual method to be implemented by the derived classes. @@ -53,6 +63,234 @@ bool V4L2Base::isOpen() const return fd_ != -1; } +int V4L2Base::queryControl(unsigned int id, + struct v4l2_query_ext_ctrl *qext_ctrl) +{ + qext_ctrl->id = id; + + int ret = ioctl(fd_, VIDIOC_QUERY_EXT_CTRL, qext_ctrl); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to query extended control 0x" + << std::hex << qext_ctrl->id + << ": " << strerror(-ret); + return ret; + } + + if (qext_ctrl->flags & V4L2_CTRL_FLAG_DISABLED) { + LOG(V4L2Base, Error) + << "Extended control 0x" << std::hex + << qext_ctrl->id << " is disabled"; + return -EINVAL; + } + + return 0; +} + +/** + * \brief Get values of a list of control IDs + * \param ctrl_ids The list of control IDs to retrieve value of + * \return A list of V4L2Control on success or a empty list otherwise + */ +int V4L2Base::getControls(std::vector &ctrl_ids, + V4L2Controls *controls) +{ + unsigned int count = ctrl_ids.size(); + if (!count) + return -EINVAL; + + controls->clear(); + + struct v4l2_ext_control *v4l2_ctrls = new struct v4l2_ext_control[count]; + + /* + * Query each control in the vector to get back its type and expected + * size in order to get its current value. + */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + unsigned int ctrl_id = ctrl_ids[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + + int ret = queryControl(ctrl_id, &qext_ctrl); + if (ret) + return ret; + + v4l2_ctrl->id = ctrl_id; + v4l2_ctrl->size = qext_ctrl.elem_size * qext_ctrl.elems; + + /* Reserve memory for controls with payload. */ + if (!(qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD)) + continue; + + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_U8: + v4l2_ctrl->p_u8 = static_cast + (new uint8_t[v4l2_ctrl->size]); + break; + case V4L2_CTRL_TYPE_U16: + v4l2_ctrl->p_u16 = static_cast + (new uint16_t[v4l2_ctrl->size]); + break; + case V4L2_CTRL_TYPE_U32: + v4l2_ctrl->p_u32 = static_cast + (new uint32_t[v4l2_ctrl->size]); + break; + } + } + + struct v4l2_ext_controls v4l2_ext_ctrls = {}; + v4l2_ext_ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2_ext_ctrls.count = count; + v4l2_ext_ctrls.controls = v4l2_ctrls; + + int ret = ioctl(fd_, VIDIOC_G_EXT_CTRLS, &v4l2_ext_ctrls); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to get extended controls: " << strerror(-ret); + return ret; + } + + /* + * For each requested control, create a V4L2Control which contains + * the current value and store it in the vector returned to the caller. + */ + LOG(Error) << __func__; + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + + int ret = queryControl(v4l2_ctrl->id, &qext_ctrl); + if (ret) + return ret; + + unsigned int size = qext_ctrl.elem_size * qext_ctrl.elem_size; + if (qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { + /* Control types with payload */ + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_U8: + controls->set(v4l2_ctrl->id, size, + v4l2_ctrl->p_u8); + break; + case V4L2_CTRL_TYPE_U16: + controls->set(v4l2_ctrl->id, size, + v4l2_ctrl->p_u16); + break; + case V4L2_CTRL_TYPE_U32: + controls->set(v4l2_ctrl->id, size, + v4l2_ctrl->p_u32); + break; + default: + LOG(V4L2Base, Error) + << "Compound control types not supported: " + << std::hex << qext_ctrl.type; + return -EINVAL; + } + } else { + /* Control types without payload. */ + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_INTEGER64: + controls->set(v4l2_ctrl->id, static_cast + (v4l2_ctrl->value64)); + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BUTTON: + controls->set(v4l2_ctrl->id, v4l2_ctrl->value); + break; + default: + LOG(V4L2Base, Error) + << "Invalid non-compound control type :" + << std::hex << qext_ctrl.type; + return -EINVAL; + } + } + } + + return 0; +} + +/** + * \brief Apply a list of controls to the device + * \param ctrls The list of controls to apply + * \return 0 on success or a negative error code otherwise + */ +int V4L2Base::setControls(V4L2Controls &ctrls) +{ + unsigned int count = ctrls.size(); + if (!count) + return -EINVAL; + + struct v4l2_ext_control *v4l2_ctrls = new struct v4l2_ext_control[count]; + + /* + * Query each control in the vector to get back its type and expected + * size and set the new desired value in each v4l2_ext_control member. + */ + for (unsigned int i = 0; i < count; ++i) { + struct v4l2_ext_control *v4l2_ctrl = &v4l2_ctrls[i]; + struct v4l2_query_ext_ctrl qext_ctrl = {}; + V4L2Control *ctrl = ctrls[i]; + + int ret = queryControl(ctrl->id(), &qext_ctrl); + if (ret) + return ret; + + v4l2_ctrl->id = ctrl->id(); + v4l2_ctrl->size = qext_ctrl.elem_size * qext_ctrl.elems; + + if (qext_ctrl.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD) { + /** \todo: Support set controls with payload. */ + LOG(V4L2Base, Error) + << "Controls with payload not supported"; + return -EINVAL; + } else { + switch (qext_ctrl.type) { + case V4L2_CTRL_TYPE_INTEGER64: + { + V4L2Int64Control *c = + static_cast(ctrl); + v4l2_ctrl->value64 = c->value(); + } + break; + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + case V4L2_CTRL_TYPE_MENU: + case V4L2_CTRL_TYPE_BUTTON: + { + V4L2IntControl *c = + static_cast(ctrl); + v4l2_ctrl->value = c->value(); + } + break; + default: + LOG(V4L2Base, Error) + << "Invalid non-compound control type :" + << qext_ctrl.type; + return -EINVAL; + } + } + } + + struct v4l2_ext_controls v4l2_ext_ctrls = {}; + v4l2_ext_ctrls.which = V4L2_CTRL_WHICH_CUR_VAL; + v4l2_ext_ctrls.count = count; + v4l2_ext_ctrls.controls = v4l2_ctrls; + + int ret = ioctl(fd_, VIDIOC_S_EXT_CTRLS, &v4l2_ext_ctrls); + if (ret) { + ret = -errno; + LOG(V4L2Base, Error) + << "Unable to set controls: " << strerror(-ret); + return ret; + } + + return 0; +} + /** * \var V4L2Base::fd_ * \brief The V4L2 device or subdevice device node file descriptor From patchwork Mon Jun 10 16:40:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1386 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AF198635E2 for ; Mon, 10 Jun 2019 18:39:48 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id 47BBF240008; Mon, 10 Jun 2019 16:39:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:51 +0200 Message-Id: <20190610164052.30741-6-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 5/6] libcamera: ipu3: Set pipe_mode based on stream configuration 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, 10 Jun 2019 16:39:49 -0000 Set the ImgU pipe_mode control based on the active stream configuration. Use 'Video' pipe mode unless the viewfinder stream is not active. Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 05005c42106b..b3e7fb0e9c64 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -22,6 +22,7 @@ #include "media_device.h" #include "pipeline_handler.h" #include "utils.h" +#include "v4l2_controls.h" #include "v4l2_device.h" #include "v4l2_subdevice.h" @@ -29,6 +30,8 @@ namespace libcamera { LOG_DEFINE_CATEGORY(IPU3) +#define IPU3_PIPE_MODE_CTRL 0x009819c1 + class ImgUDevice { public: @@ -536,6 +539,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) * the configuration of the active one for that purpose (there should * be at least one active stream in the configuration request). */ + unsigned int pipeMode = 0; if (!outStream->active_) { ret = imgu->configureOutput(outStream->device_, config->at(0)); if (ret) @@ -546,6 +550,12 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) ret = imgu->configureOutput(vfStream->device_, config->at(0)); if (ret) return ret; + + /* + * \todo: This works as long as only two concurrent streams + * per pipe are supported. + */ + pipeMode = 1; } /* @@ -559,6 +569,25 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c) if (ret) return ret; + /* Apply the "pipe_mode" control to the ImgU subdevice. */ + V4L2Controls ctrls; + ctrls.set(IPU3_PIPE_MODE_CTRL, pipeMode); + ret = imgu->imgu_->setControls(ctrls); + if (ret) { + LOG(IPU3, Error) << "Unable to set pipe_mode control"; + return ret; + } + + std::vector ctrlId = { IPU3_PIPE_MODE_CTRL, }; + ret = imgu->imgu_->getControls(ctrlId, &ctrls); + if (ret) { + LOG(IPU3, Error) << "Unable to get pipe_mode control value"; + return ret; + } + + pipeMode = ctrls.getInt(IPU3_PIPE_MODE_CTRL); + LOG(IPU3, Debug) << "ImgU pipe mode set to: " + << (pipeMode ? "'Still Capture'" : "'Video'"); return 0; } From patchwork Mon Jun 10 16:40:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 1387 Return-Path: Received: from relay10.mail.gandi.net (relay10.mail.gandi.net [217.70.178.230]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 45ACE635E2 for ; Mon, 10 Jun 2019 18:39:49 +0200 (CEST) Received: from uno.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay10.mail.gandi.net (Postfix) with ESMTPSA id D79DB240007; Mon, 10 Jun 2019 16:39:48 +0000 (UTC) From: Jacopo Mondi To: libcamera-devel@lists.libcamera.org Date: Mon, 10 Jun 2019 18:40:52 +0200 Message-Id: <20190610164052.30741-7-jacopo@jmondi.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190610164052.30741-1-jacopo@jmondi.org> References: <20190610164052.30741-1-jacopo@jmondi.org> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 6/6] [HACK] ipu3: Set and get a few sensor 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, 10 Jun 2019 16:39:49 -0000 Not to merge patch to demonstrate how to set controls on the image sensor device. Not-Signed-off-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index b3e7fb0e9c64..59c1fe3c56fd 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -688,6 +688,86 @@ int PipelineHandlerIPU3::start(Camera *camera) ImgUDevice *imgu = data->imgu_; int ret; + /* --- Get control values --- */ + std::vector controlIds = { + V4L2_CID_EXPOSURE, V4L2_CID_ANALOGUE_GAIN, + }; + V4L2Controls controls; + ret = cio2->sensor_->dev()->getControls(controlIds, &controls); + if (ret) { + LOG(Error) << "Failed to get control values"; + return -EINVAL; + } + + for (V4L2Control *ctrl : controls) { + unsigned int id = ctrl->id(); + + switch(ctrl->type()) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + { + uint32_t val = controls.getInt(id); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + case V4L2_CTRL_TYPE_INTEGER64: + { + uint64_t val = controls.getInt64(id); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + default: + LOG(Error) << "Unsupported type: " << ctrl->type(); + return -EINVAL; + } + } + + /* --- Set control values --- */ + V4L2Controls setControls; + setControls.set(V4L2_CID_EXPOSURE, 2046); + setControls.set(V4L2_CID_ANALOGUE_GAIN, 1024); + + ret = cio2->sensor_->dev()->setControls(setControls); + if (ret) { + LOG(IPU3, Error) << "Failed to set controls"; + return ret; + } + + /* --- Get control values back again and verify they have changed --- */ + V4L2Controls newcontrols; + ret = cio2->sensor_->dev()->getControls(controlIds, &newcontrols); + if (ret) { + LOG(Error) << "Failed to get control values"; + return -EINVAL; + } + + for (V4L2Control *ctrl : newcontrols) { + unsigned int id = ctrl->id(); + + switch(ctrl->type()) { + case V4L2_CTRL_TYPE_INTEGER: + case V4L2_CTRL_TYPE_BOOLEAN: + { + uint32_t val = newcontrols.getInt(id); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + case V4L2_CTRL_TYPE_INTEGER64: + { + uint64_t val = newcontrols.getInt64(id); + LOG(Error) << "Control : " << id + << " - value: " << val; + } + break; + default: + LOG(Error) << "Unsupported type: " << ctrl->type(); + return -EINVAL; + } + } + /* * Start the ImgU video devices, buffers will be queued to the * ImgU output and viewfinder when requests will be queued.