From patchwork Mon May 27 00:15:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1294 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2FE75618F5 for ; Mon, 27 May 2019 02:16:07 +0200 (CEST) X-Halon-ID: 9c98fd1f-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9c98fd1f-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:02 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:27 +0200 Message-Id: <20190527001543.13593-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/17] meson: Allow partially initializing objects 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, 27 May 2019 00:16:08 -0000 There are valid use-cases where one might wish to partially initialize a structure when creating it without needing to initialize all members. This is especially common when working with V4L2. struct foo { int bar; int baz; }; struct foo f = { .bar = 1; }; Without -Wno-missing-field-initializers fails to compile with the error, error: missing initializer for member ‘foo::baz’ [-Werror=missing-field-initializers] Signed-off-by: Niklas Söderlund Acked-by: Jacopo Mondi Acked-by: Kieran Bingham --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 4d3e99d3e58f71d5..90ad58328f9a2bd5 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,7 @@ endif common_arguments = [ '-Wno-unused-parameter', + '-Wno-missing-field-initializers', '-include', 'config.h', ] From patchwork Mon May 27 00:15:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1293 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D83460E47 for ; Mon, 27 May 2019 02:16:07 +0200 (CEST) X-Halon-ID: 9cd46ea9-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9cd46ea9-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:03 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:28 +0200 Message-Id: <20190527001543.13593-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/17] libcamera: geometry: SizeRange: Add constructor for a single size 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, 27 May 2019 00:16:08 -0000 The SizeRange can describe a single size where min == max. Add a constructor to help create such a description. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/geometry.h | 5 +++++ src/libcamera/geometry.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index a87d65d3ed7951c2..ec5ed2bee196c82d 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -72,6 +72,11 @@ struct SizeRange { { } + SizeRange(unsigned int width, unsigned int height) + : min(width, height), max(width, height) + { + } + SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) : min(minW, minH), max(maxW, maxH) diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 97c367bcb454b517..cc25b816e6796ba1 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -196,6 +196,13 @@ bool operator<(const Size &lhs, const Size &rhs) * \brief Construct a size range initialized to 0 */ +/** + * \fn SizeRange::SizeRange(unsigned int width, unsigned int height) + * \brief Construct size range with a single size + * \param[in] width Single width + * \param[in] height Single height + */ + /** * \fn SizeRange::SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) * \brief Construct an initialized size range From patchwork Mon May 27 00:15:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1296 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3B61B618F7 for ; Mon, 27 May 2019 02:16:07 +0200 (CEST) X-Halon-ID: 9d133a73-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9d133a73-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:03 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:29 +0200 Message-Id: <20190527001543.13593-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/17] libcamera: geometry: SizeRange: Extend with stepping information 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, 27 May 2019 00:16:08 -0000 The size range described might be subject to certain stepping limitations. Make it possible to record this information. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- include/libcamera/geometry.h | 13 +++++++++++-- src/libcamera/geometry.cpp | 37 ++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index ec5ed2bee196c82d..1c9267b14274cb5d 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -73,18 +73,27 @@ struct SizeRange { } SizeRange(unsigned int width, unsigned int height) - : min(width, height), max(width, height) + : min(width, height), max(width, height), hStep(0), vStep(0) { } SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) - : min(minW, minH), max(maxW, maxH) + : min(minW, minH), max(maxW, maxH), hStep(1), vStep(1) + { + } + + SizeRange(unsigned int minW, unsigned int minH, + unsigned int maxW, unsigned int maxH, + unsigned int hstep, unsigned int vstep) + : min(minW, minH), max(maxW, maxH), hStep(hstep), vStep(vstep) { } Size min; Size max; + unsigned int hStep; + unsigned int vStep; }; bool operator==(const SizeRange &lhs, const SizeRange &rhs); diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index cc25b816e6796ba1..e7f1bafd40e944f5 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -189,6 +189,20 @@ bool operator<(const Size &lhs, const Size &rhs) * SizeRange describes a range of sizes included in the [min, max] * interval for both the width and the height. If the minimum and * maximum sizes are identical it represents a single size. + * + * The SizeRange may also contain a vertical and horizontal stepping. + * The stepping values add additional constrains to the width and height + * values described by the range. + * + * width = min.width + min.hStep * x + * height = min.height + min.vStep * y + * + * Where: + * + * width <= max.width + * height < max.height + * + * For SizeRanges describing a single size the step values have no effect. */ /** @@ -212,6 +226,19 @@ bool operator<(const Size &lhs, const Size &rhs) * \param[in] maxH The maximum height */ +/** + * \fn SizeRange::SizeRange(unsigned int minW, unsigned int minH, + * unsigned int maxW, unsigned int maxH, + * unsigned int hstep, unsigned int vstep) + * \brief Construct an initialized size range + * \param[in] minW The minimum width + * \param[in] minH The minimum height + * \param[in] maxW The maximum width + * \param[in] maxH The maximum height + * \param[in] hstep The horizontal step + * \param[in] vstep The vertical step + */ + /** * \var SizeRange::min * \brief The minimum size @@ -222,6 +249,16 @@ bool operator<(const Size &lhs, const Size &rhs) * \brief The maximum size */ +/** + * \var SizeRange::hStep + * \brief The horizontal step + */ + +/** + * \var SizeRange::vStep + * \brief The vertical step + */ + /** * \brief Compare size ranges for equality * \return True if the two size ranges are equal, false otherwise From patchwork Mon May 27 00:15:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1297 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AECE7618F8 for ; Mon, 27 May 2019 02:16:07 +0200 (CEST) X-Halon-ID: 9d5be10c-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9d5be10c-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:04 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:30 +0200 Message-Id: <20190527001543.13593-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/17] libcamera: geometry: SizeRange: Add toString() 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, 27 May 2019 00:16:08 -0000 It's useful to be able to print a string representation of a SizeRange to the log or console, add a toString() method. While at it turn the structure into a class as it contains functions as well as data. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- include/libcamera/geometry.h | 6 +++++- src/libcamera/geometry.cpp | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 1c9267b14274cb5d..ca920a1e16817860 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -67,7 +67,9 @@ static inline bool operator>=(const Size &lhs, const Size &rhs) return !(lhs < rhs); } -struct SizeRange { +class SizeRange +{ +public: SizeRange() { } @@ -90,6 +92,8 @@ struct SizeRange { { } + const std::string toString() const; + Size min; Size max; unsigned int hStep; diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index e7f1bafd40e944f5..337f2efa828ba996 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -259,6 +259,28 @@ bool operator<(const Size &lhs, const Size &rhs) * \brief The vertical step */ +/** + * \brief Assemble and return a string describing the size range + * \return A string describing the SizeRange + */ +const std::string SizeRange::toString() const +{ + std::stringstream ss; + + if (min == max) + ss << "Width: " << min.width + << " Height: " << min.height + << " hStep: " << hStep + << " vStep: " << vStep; + else + ss << "Width: " << min.width << "-" << max.width + << " Height: " << min.height << "-" << max.height + << " hStep: " << hStep + << " vStep: " << vStep; + + return ss.str(); +} + /** * \brief Compare size ranges for equality * \return True if the two size ranges are equal, false otherwise From patchwork Mon May 27 00:15:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1298 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 45CC9618F5 for ; Mon, 27 May 2019 02:16:08 +0200 (CEST) X-Halon-ID: 9d973116-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9d973116-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:04 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:31 +0200 Message-Id: <20190527001543.13593-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/17] libcamera: formats: Add V4L2DeviceFormats and V4L2DeviceFormats 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, 27 May 2019 00:16:08 -0000 Add two new objects to hold v4l2 format information for v4l2 devices and subdevices. There is much code which can be shared between the two so have both of them inherit from a base class to reduce code duplication. Signed-off-by: Niklas Söderlund --- src/libcamera/formats.cpp | 158 ++++++++++++++++++++++++++++++++ src/libcamera/include/formats.h | 35 +++++++ 2 files changed, 193 insertions(+) diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index 56f4ddb51ffad4d3..f5841b38cea5686c 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -24,4 +24,162 @@ namespace libcamera { * resolutions represented by SizeRange items. */ + +/** + * \class DeviceFormats + * \brief Base class for V4L2Device and V4L2SubDevice Formats + * + * The base class holds common functionallity between V4L2DeviceFormats and + * V4L2SubDeviceForamts. + * + * \sa V4L2DeviceFormats + * \sa V4L2SubDeviceForamts + */ + +/** + * \brief Create an empty DeviceFormats + */ +DeviceFormats::DeviceFormats() +{ +} + +/** + * \brief Create a DeviceFormats with data + */ +DeviceFormats::DeviceFormats(const std::map> &data) + : data_(data) +{ +} + +DeviceFormats::~DeviceFormats() +{ +} + +/** + * \brief Retrieve all sizes for a specific format + * \param[in] format A pixelformat or mbus code + * + * Retrieves all SizeRanges for a specific format. For V4L2Device \a format is a + * pixelformoat while for a V4L2Subdevice \a format is a media bus code. + * + * \return List of SizeRanges for \a format, empty list if format is not valid + */ +std::vector DeviceFormats::sizes(unsigned int format) const +{ + auto const &it = data_.find(format); + if (it == data_.end()) + return {}; + + return it->second; +} + +/** + * \brief Check if the device formats is empty + * \return True if the formats are empty + */ +bool DeviceFormats::empty() const +{ + return data_.empty(); +} + +/** + * \brief Retrieve the raw dataA + * \return Raw map containgin formats to SizeRanges + */ +const std::map> &DeviceFormats::data() +{ + return data_; +} + +/** + * \brief Retrieve a list all contained formats + * + * This is a helper function intended to be used by V4L2DeviceFormats and + * V4L2SubdeviceFormats. + * + * \return A list of formats contained + */ +std::vector DeviceFormats::formats() const +{ + std::vector formats; + + for (auto const &it : data_) + formats.push_back(it.first); + + return formats; +} + +/** + * \var DeviceFormats::data_ + * \brief The map holding format and SizeRange information + */ + +/** + * \class V4L2SubdeviceFormats + * \brief Holds media bus codes to frame sizes information for a v4l2 subdevice + * + * Hold media bus codes and frame sizes which describes a v4l2 subdevice. The + * intended user of this object is pipeline handlers which can create it + * from a V4L2Subdevice and use it to describe and validate formats. + */ + +/** + * \brief Create an empty V4L2SubdeviceFormats + */ +V4L2SubdeviceFormats::V4L2SubdeviceFormats() + : DeviceFormats() +{ +} + +/** + * \brief Create an V4L2SubdeviceFormats with data + */ +V4L2SubdeviceFormats::V4L2SubdeviceFormats(const std::map> &data) + : DeviceFormats(data) +{ +} + +/** + * \brief Retrieve media bus codes which are described + * \return List of media bus codes + */ +std::vector V4L2SubdeviceFormats::codes() const +{ + return formats(); +} + +/** + * \class V4L2DeviceFormats + * \brief Holds pixelformats to frame sizes information for a v4l2 device + * + * Hold pixelformats and frame sizes which describes a v4l2 device. The + * intended user of this object is pipeline handlers which can create it + * from a V4L2Device and use it to describe and validate formats. + */ + +/** + * \brief Create an empty V4L2DeviceFormats + */ +V4L2DeviceFormats::V4L2DeviceFormats() + : DeviceFormats() +{ +} + +/** + * \brief Create an V4L2DeviceFormats with data + */ +V4L2DeviceFormats::V4L2DeviceFormats(const std::map> &data) + : DeviceFormats(data) +{ +} + +/** + * \brief Retrieve pixelformats which are described + * \return List of pixelformats + */ +std::vector V4L2DeviceFormats::pixelformats() const +{ + return formats(); +} + } /* namespace libcamera */ diff --git a/src/libcamera/include/formats.h b/src/libcamera/include/formats.h index a73772b1eda068b4..372f6e6d71b236dd 100644 --- a/src/libcamera/include/formats.h +++ b/src/libcamera/include/formats.h @@ -17,6 +17,41 @@ namespace libcamera { typedef std::map> FormatEnum; +class DeviceFormats +{ +public: + virtual ~DeviceFormats(); + + std::vector sizes(unsigned int format) const; + bool empty() const; + const std::map> &data(); + +protected: + DeviceFormats(); + DeviceFormats(const std::map> &data); + std::vector formats() const; + + std::map> data_; +}; + +class V4L2SubdeviceFormats : public DeviceFormats +{ +public: + V4L2SubdeviceFormats(); + V4L2SubdeviceFormats(const std::map> &data); + + std::vector codes() const; +}; + +class V4L2DeviceFormats : public DeviceFormats +{ +public: + V4L2DeviceFormats(); + V4L2DeviceFormats(const std::map> &data); + + std::vector pixelformats() const; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_FORMATS_H__ */ From patchwork Mon May 27 00:15:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1299 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C44E8618F5 for ; Mon, 27 May 2019 02:16:08 +0200 (CEST) X-Halon-ID: 9df75dd5-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9df75dd5-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:05 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:32 +0200 Message-Id: <20190527001543.13593-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/17] libcamera: v4l2_subdevice: Breakout mbus code enumeration 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, 27 May 2019 00:16:09 -0000 Simplify frame size enumeration by breaking out mbus code enumeration in a helper. Making the code easier to read while also preparing for enhancing the frame size enumeration. There is no functional change. Signed-off-by: Niklas Söderlund --- src/libcamera/include/v4l2_subdevice.h | 1 + src/libcamera/v4l2_subdevice.cpp | 60 +++++++++++++++----------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index 3e4e5107aebeee06..e714e2575022c04d 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -57,6 +57,7 @@ protected: std::string logPrefix() const; private: + std::vector enumPadCodes(unsigned int pad); int enumPadSizes(unsigned int pad, unsigned int code, std::vector *size); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index fceee33156e94212..51b0ffaafb3e668e 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -203,37 +203,15 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect) FormatEnum V4L2Subdevice::formats(unsigned int pad) { FormatEnum formatMap = {}; - struct v4l2_subdev_mbus_code_enum mbusEnum = {}; - int ret; if (pad >= entity_->pads().size()) { LOG(V4L2Subdev, Error) << "Invalid pad: " << pad; - return formatMap; + return {}; } - mbusEnum.pad = pad; - mbusEnum.index = 0; - mbusEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE; - while (true) { - ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum); - if (ret) - break; - - ret = enumPadSizes(pad, mbusEnum.code, - &formatMap[mbusEnum.code]); - if (ret) - break; - - mbusEnum.index++; - } - - if (ret && (errno != EINVAL && errno != ENOTTY)) { - ret = -errno; - LOG(V4L2Subdev, Error) - << "Unable to enumerate formats on pad " << pad - << ": " << strerror(-ret); - formatMap.clear(); - } + for (unsigned int code : enumPadCodes(pad)) + if (enumPadSizes(pad, code, &formatMap[code])) + return {}; return formatMap; } @@ -328,6 +306,36 @@ std::string V4L2Subdevice::logPrefix() const return "'" + entity_->name() + "'"; } +std::vector V4L2Subdevice::enumPadCodes(unsigned int pad) +{ + std::vector codes; + int ret; + + for (unsigned int index = 0;; index++) { + struct v4l2_subdev_mbus_code_enum mbusEnum = { + .pad = pad, + .index = index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbusEnum); + if (ret) + break; + + codes.push_back(mbusEnum.code); + } + + if (ret && errno != EINVAL) { + ret = errno; + LOG(V4L2Subdev, Error) + << "Unable to enumerate formats on pad " << pad + << ": " << strerror(ret); + return {}; + } + + return codes; +} + int V4L2Subdevice::enumPadSizes(unsigned int pad,unsigned int code, std::vector *sizes) { From patchwork Mon May 27 00:15:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1300 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0E029618F8 for ; Mon, 27 May 2019 02:16:09 +0200 (CEST) X-Halon-ID: 9e47ae80-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9e47ae80-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:05 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:33 +0200 Message-Id: <20190527001543.13593-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/17] libcamera: v4l2_subdevice: Rework enumPadSizes() 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, 27 May 2019 00:16:09 -0000 Align the enumPadSizes() interface and implementation with that of enumPadCodes(). There is no functional change. Signed-off-by: Niklas Söderlund --- src/libcamera/include/v4l2_subdevice.h | 4 +-- src/libcamera/v4l2_subdevice.cpp | 36 ++++++++++++-------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index e714e2575022c04d..c6fdf417b43c0423 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -58,8 +58,8 @@ protected: private: std::vector enumPadCodes(unsigned int pad); - int enumPadSizes(unsigned int pad, unsigned int code, - std::vector *size); + std::vector enumPadSizes(unsigned int pad, + unsigned int code); int setSelection(unsigned int pad, unsigned int target, Rectangle *rect); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 51b0ffaafb3e668e..8720013600ddb95f 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -210,8 +210,7 @@ FormatEnum V4L2Subdevice::formats(unsigned int pad) } for (unsigned int code : enumPadCodes(pad)) - if (enumPadSizes(pad, code, &formatMap[code])) - return {}; + formatMap[code] = enumPadSizes(pad, code); return formatMap; } @@ -336,38 +335,37 @@ std::vector V4L2Subdevice::enumPadCodes(unsigned int pad) return codes; } -int V4L2Subdevice::enumPadSizes(unsigned int pad,unsigned int code, - std::vector *sizes) +std::vector V4L2Subdevice::enumPadSizes(unsigned int pad, + unsigned int code) { - struct v4l2_subdev_frame_size_enum sizeEnum = {}; + std::vector sizes; int ret; - sizeEnum.index = 0; - sizeEnum.pad = pad; - sizeEnum.code = code; - sizeEnum.which = V4L2_SUBDEV_FORMAT_ACTIVE; - while (true) { + for (unsigned int index = 0;; index++) { + struct v4l2_subdev_frame_size_enum sizeEnum = { + .index = index, + .pad = pad, + .code = code, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + ret = ioctl(fd_, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &sizeEnum); if (ret) break; - sizes->emplace_back(sizeEnum.min_width, sizeEnum.min_height, + sizes.emplace_back(sizeEnum.min_width, sizeEnum.min_height, sizeEnum.max_width, sizeEnum.max_height); - - sizeEnum.index++; } if (ret && (errno != EINVAL && errno != ENOTTY)) { - ret = -errno; + ret = errno; LOG(V4L2Subdev, Error) << "Unable to enumerate sizes on pad " << pad - << ": " << strerror(-ret); - sizes->clear(); - - return ret; + << ": " << strerror(ret); + return {}; } - return 0; + return sizes; } int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, From patchwork Mon May 27 00:15:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1302 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9700E6191B for ; Mon, 27 May 2019 02:16:10 +0200 (CEST) X-Halon-ID: 9e8d1e9d-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9e8d1e9d-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:06 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:34 +0200 Message-Id: <20190527001543.13593-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/17] libcamera: v4l2_subdevice: Replace FormatEnum with V4L2SubdeviceFormats 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, 27 May 2019 00:16:13 -0000 Replace all usage of FormatEnum with V4L2SubdeviceFormats and completely remove FormatEnum which is no longer needed. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/camera_sensor.cpp | 12 +++++------- src/libcamera/formats.cpp | 11 ----------- src/libcamera/include/formats.h | 2 -- src/libcamera/include/v4l2_subdevice.h | 2 +- src/libcamera/v4l2_subdevice.cpp | 6 +++--- test/v4l2_subdevice/list_formats.cpp | 10 +++++----- 6 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 2b9d8fa593c13177..e46bc28c7ac4a8e1 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -90,27 +90,25 @@ int CameraSensor::init() return ret; /* Enumerate and cache media bus codes and sizes. */ - const FormatEnum formats = subdev_->formats(0); + const V4L2SubdeviceFormats formats = subdev_->formats(0); if (formats.empty()) { LOG(CameraSensor, Error) << "No image format found"; return -EINVAL; } - std::transform(formats.begin(), formats.end(), - std::back_inserter(mbusCodes_), - [](decltype(*formats.begin()) f) { return f.first; }); + mbusCodes_ = formats.codes(); /* * Extract the supported sizes from the first format as we only support * sensors that offer the same frame sizes for all media bus codes. * Verify this assumption and reject the sensor if it isn't true. */ - const std::vector &sizes = formats.begin()->second; + const std::vector &sizes = formats.sizes(mbusCodes_[0]); std::transform(sizes.begin(), sizes.end(), std::back_inserter(sizes_), [](const SizeRange &range) { return range.max; }); - for (auto it = ++formats.begin(); it != formats.end(); ++it) { - if (it->second != sizes) { + for (unsigned int code : mbusCodes_) { + if (formats.sizes(code) != sizes) { LOG(CameraSensor, Error) << "Frame sizes differ between media bus codes"; return -EINVAL; diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index f5841b38cea5686c..7b2097413c3b7378 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -14,17 +14,6 @@ namespace libcamera { -/** - * \typedef FormatEnum - * \brief Type definition for the map of image formats and sizes - * - * Type definition used to enumerate the supported pixel formats and image - * frame sizes. The type associates in a map a pixel format (for memory - * formats) or a media bus code (for bus formats), to a vector of image - * resolutions represented by SizeRange items. - */ - - /** * \class DeviceFormats * \brief Base class for V4L2Device and V4L2SubDevice Formats diff --git a/src/libcamera/include/formats.h b/src/libcamera/include/formats.h index 372f6e6d71b236dd..2e849e70c4a88aeb 100644 --- a/src/libcamera/include/formats.h +++ b/src/libcamera/include/formats.h @@ -15,8 +15,6 @@ namespace libcamera { -typedef std::map> FormatEnum; - class DeviceFormats { public: diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index c6fdf417b43c0423..a6d691ea540a4e5e 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -45,7 +45,7 @@ public: int setCrop(unsigned int pad, Rectangle *rect); int setCompose(unsigned int pad, Rectangle *rect); - FormatEnum formats(unsigned int pad); + V4L2SubdeviceFormats formats(unsigned int pad); int getFormat(unsigned int pad, V4L2SubdeviceFormat *format); int setFormat(unsigned int pad, V4L2SubdeviceFormat *format); diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index 8720013600ddb95f..fe393c66729e8511 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -200,9 +200,9 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect) * \return A map of image formats associated with a list of image sizes, or * an empty map on error or if the pad does not exist */ -FormatEnum V4L2Subdevice::formats(unsigned int pad) +V4L2SubdeviceFormats V4L2Subdevice::formats(unsigned int pad) { - FormatEnum formatMap = {}; + std::map> formatMap = {}; if (pad >= entity_->pads().size()) { LOG(V4L2Subdev, Error) << "Invalid pad: " << pad; @@ -212,7 +212,7 @@ FormatEnum V4L2Subdevice::formats(unsigned int pad) for (unsigned int code : enumPadCodes(pad)) formatMap[code] = enumPadSizes(pad, code); - return formatMap; + return V4L2SubdeviceFormats(formatMap); } /** diff --git a/test/v4l2_subdevice/list_formats.cpp b/test/v4l2_subdevice/list_formats.cpp index 3f0edafcdcd72d6b..1c044a969961d172 100644 --- a/test/v4l2_subdevice/list_formats.cpp +++ b/test/v4l2_subdevice/list_formats.cpp @@ -47,7 +47,7 @@ void ListFormatsTest::printFormats(unsigned int pad, int ListFormatsTest::run() { /* List all formats available on existing "Scaler" pads. */ - std::map> formats; + V4L2SubdeviceFormats formats; formats = scaler_->formats(0); if (formats.empty()) { @@ -55,8 +55,8 @@ int ListFormatsTest::run() << scaler_->entity()->name() << endl; return TestFail; } - for (auto it = formats.begin(); it != formats.end(); ++it) - printFormats(0, it->first, it->second); + for (unsigned int code : formats.codes()) + printFormats(0, code, formats.sizes(code)); formats = scaler_->formats(1); if (formats.empty()) { @@ -64,8 +64,8 @@ int ListFormatsTest::run() << scaler_->entity()->name() << endl; return TestFail; } - for (auto it = formats.begin(); it != formats.end(); ++it) - printFormats(1, it->first, it->second); + for (unsigned int code : formats.codes()) + printFormats(1, code, formats.sizes(code)); /* List format on a non-existing pad, format vector shall be empty. */ formats = scaler_->formats(2); From patchwork Mon May 27 00:15:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1301 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 988EC61903 for ; Mon, 27 May 2019 02:16:10 +0200 (CEST) X-Halon-ID: 9ee85045-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9ee85045-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:06 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:35 +0200 Message-Id: <20190527001543.13593-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/17] libcamera: v4l2_device: Add enumeration of pixelformats and frame sizes 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, 27 May 2019 00:16:13 -0000 Add methods to enumerate pixelformats and frame sizes from a v4l2 device. The interface is similar to how V4L2Subdevice enumerates mbus codes and frame sizes. Signed-off-by: Niklas Söderlund --- src/libcamera/include/v4l2_device.h | 5 ++ src/libcamera/v4l2_device.cpp | 104 ++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index 2e7bd1e7f4cce276..db2d12757c6f564a 100644 --- a/src/libcamera/include/v4l2_device.h +++ b/src/libcamera/include/v4l2_device.h @@ -16,6 +16,7 @@ #include #include +#include "formats.h" #include "log.h" namespace libcamera { @@ -126,6 +127,7 @@ public: int getFormat(V4L2DeviceFormat *format); int setFormat(V4L2DeviceFormat *format); + V4L2DeviceFormats formats(); int exportBuffers(BufferPool *pool); int importBuffers(BufferPool *pool); @@ -154,6 +156,9 @@ private: int createPlane(Buffer *buffer, unsigned int plane, unsigned int length); + std::vector enumPixelformats(); + std::vector enumSizes(unsigned int pixelformat); + Buffer *dequeueBuffer(); void bufferAvailable(EventNotifier *notifier); diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 8366ffc4db559520..a9667092a20505d9 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -564,6 +564,23 @@ int V4L2Device::setFormatMultiplane(V4L2DeviceFormat *format) return 0; } +/** + * \brief Enumerate all pixelformats and frame sizes + * + * Enumerate all pixelformats and frame sizes reported by the video device. + * + * \return All pixelformats and frame sizes + */ +V4L2DeviceFormats V4L2Device::formats() +{ + std::map> formatMap = {}; + + for (unsigned int pixelformat : enumPixelformats()) + formatMap[pixelformat] = enumSizes(pixelformat); + + return V4L2DeviceFormats(formatMap); +} + int V4L2Device::requestBuffers(unsigned int count) { struct v4l2_requestbuffers rb = {}; @@ -692,6 +709,93 @@ int V4L2Device::createPlane(Buffer *buffer, unsigned int planeIndex, return 0; } +std::vector V4L2Device::enumPixelformats() +{ + std::vector pixelformats; + int ret; + + for (unsigned int index = 0;; index++) { + struct v4l2_fmtdesc pixelformatEnum = { + .index = index, + .type = bufferType_, + }; + + ret = ioctl(fd_, VIDIOC_ENUM_FMT, &pixelformatEnum); + if (ret) + break; + + pixelformats.push_back(pixelformatEnum.pixelformat); + } + + if (ret && errno != EINVAL) { + ret = errno; + LOG(V4L2, Error) + << "Unable to enumerate pixelformats: " + << strerror(ret); + return {}; + } + + return pixelformats; +} + +std::vector V4L2Device::enumSizes(unsigned int pixelformat) +{ + std::vector sizes; + int ret; + + for (unsigned int index = 0;; index++) { + struct v4l2_frmsizeenum frameSize = { + .index = index, + .pixel_format = pixelformat, + }; + + ret = ioctl(fd_, VIDIOC_ENUM_FRAMESIZES, &frameSize); + if (ret) + break; + + if (index != 0 && + frameSize.type != V4L2_FRMSIZE_TYPE_DISCRETE) { + LOG(V4L2, Error) + << "None 0 index for none discrete type"; + return {}; + } + + switch (frameSize.type) { + case V4L2_FRMSIZE_TYPE_DISCRETE: + sizes.emplace_back(frameSize.discrete.width, + frameSize.discrete.height); + break; + case V4L2_FRMSIZE_TYPE_CONTINUOUS: + sizes.emplace_back(frameSize.stepwise.min_width, + frameSize.stepwise.min_height, + frameSize.stepwise.max_width, + frameSize.stepwise.max_height); + break; + case V4L2_FRMSIZE_TYPE_STEPWISE: + sizes.emplace_back(frameSize.stepwise.min_width, + frameSize.stepwise.min_height, + frameSize.stepwise.max_width, + frameSize.stepwise.max_height, + frameSize.stepwise.step_width, + frameSize.stepwise.step_height); + break; + default: + LOG(V4L2, Error) + << "Unkown VIDIOC_ENUM_FRAMESIZES type " + << frameSize.type; + return {}; + } + } + + if (ret && errno != EINVAL) { + ret = errno; + LOG(V4L2, Error) + << "Unable to enumerate frame sizes: " << strerror(ret); + return {}; + } + + return sizes; +} /** * \brief Import the externally allocated \a pool of buffers From patchwork Mon May 27 00:15:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1303 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 98A316191C for ; Mon, 27 May 2019 02:16:10 +0200 (CEST) X-Halon-ID: 9f3ccd37-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9f3ccd37-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:07 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:36 +0200 Message-Id: <20190527001543.13593-11-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/17] libcamera: stream: Define log object 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, 27 May 2019 00:16:13 -0000 Define a LOG object to prepare for adding code which needs to write to the log. Signed-off-by: Niklas Söderlund Reviewed-by: Kieran Bingham --- src/libcamera/stream.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index 0c59a31a3a0501d3..eecd37160150d55c 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -10,6 +10,8 @@ #include #include +#include "log.h" + /** * \file stream.h * \brief Video stream for a Camera @@ -32,6 +34,8 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Stream) + /** * \struct StreamConfiguration * \brief Configuration parameters for a stream From patchwork Mon May 27 00:15:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1305 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 28FFA618F9 for ; Mon, 27 May 2019 02:16:12 +0200 (CEST) X-Halon-ID: 9f6e729b-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9f6e729b-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:07 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:37 +0200 Message-Id: <20190527001543.13593-12-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/17] libcamera: stream: Add StreamFormats 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, 27 May 2019 00:16:14 -0000 Add a StreamFormats which describes all the formats a stream can support. The object does not collect any formation itself but can simplify users interaction with formats as it's able to translate a stream format range into discrete list and a discrete list to a range. Signed-off-by: Niklas Söderlund --- include/libcamera/stream.h | 16 +++ src/libcamera/stream.cpp | 216 +++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index e38c0e7e827d5888..48daf5ac23f55d85 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -7,6 +7,7 @@ #ifndef __LIBCAMERA_STREAM_H__ #define __LIBCAMERA_STREAM_H__ +#include #include #include @@ -18,6 +19,21 @@ namespace libcamera { class Camera; class Stream; +class StreamFormats +{ +public: + StreamFormats(); + StreamFormats(const std::map> &formats); + + std::vector pixelformats() const; + std::vector sizes(unsigned int pixelformat) const; + + SizeRange range(unsigned int pixelformat) const; + +private: + std::map> formats_; +}; + struct StreamConfiguration { StreamConfiguration() : stream_(nullptr) diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index eecd37160150d55c..a2931902fda2baa5 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -7,6 +7,7 @@ #include +#include #include #include @@ -36,6 +37,221 @@ namespace libcamera { LOG_DEFINE_CATEGORY(Stream) +/** + * \class StreamFormats + * \brief Hold information about supported stream formats + * + * The StreamFormats class holds information about pixel formats and frame + * sizes a stream supports. The class groups size information by the pixel + * format which can produce it. There are two ways to examine the size + * information, as a range or as a list of discrete sizes. + * + * When sizes are viewed as a range it describes the minimum and maximum width + * and height values. There is a possibility to supplement the range description + * with a horizontal och vertical stepping size. The stepping size describes the + * step size in pixel from the minimum with/height. + * + * When sizes is viewed as a list of discrete sizes it describes exact dimensions + * which can be selected and used. + * + * Pipeline handlers can create StreamFormats describing each pixel format using + * either a range or a list of discrete sizes. The StreamFormats class attempts + * to translates between the two different ways to view them. The translations + * are performed as: + * + * - If a pixel format is described as a list of discrete sizes a range is + * created by taking the minim and maximum width/height in the list. + * The stepping information is not recreated and set to 1. + * + * - If a pixel format is described as a range a list of discrete sizes which + * fits inside that range are selected from a list of common sizes. The + * stepping information is taken into consideration when generating the + * sizes. + * + * Applications examining sizes as a range with stepping values of 1 should be + * aware that the range could be generated form a list of discrete sizes and + * there could be big gaps in the range to what the stream can support. + * + * All sizes retrieved from StreamFormats should be treated as advisory and no + * size should be considered to be supported until its been verified using + * CameraConfiguration::validate(). + */ + +/** + * \brief Construct a empty StreamFormats object + */ +StreamFormats::StreamFormats() +{ +} + +/** + * \brief Construct a StreamFormats object + * \param[in] formats A map of pixel formats to a sizes description + */ +StreamFormats::StreamFormats(const std::map> &formats) + : formats_(formats) +{ +} + +/** + * \brief Retrieve the list of pixel formats supported + * \returns List of pixel formats + */ +std::vector StreamFormats::pixelformats() const +{ + std::vector formats; + + for (auto const &it : formats_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve the list of frame sizes + * \param[in] pixelformat Pixel format to retrieve sizes for + * \returns List description of frame sizes + */ +std::vector StreamFormats::sizes(unsigned int pixelformat) const +{ + /* + * Sizes to try and extract from ranges. + * \todo Verify list of resolutions are good, current list compiled + * from v4l2 documentation and source code as well as lists of + * common frame sizes. + */ + static const std::vector rangeDiscreteSizes = { + Size(160, 120), + Size(240, 160), + Size(320, 240), + Size(400, 240), + Size(480, 320), + Size(640, 360), + Size(640, 480), + Size(720, 480), + Size(720, 576), + Size(768, 480), + Size(800, 600), + Size(854, 480), + Size(960, 540), + Size(960, 640), + Size(1024, 576), + Size(1024, 600), + Size(1024, 768), + Size(1152, 864), + Size(1280, 1024), + Size(1280, 1080), + Size(1280, 720), + Size(1280, 800), + Size(1360, 768), + Size(1366, 768), + Size(1400, 1050), + Size(1440, 900), + Size(1536, 864), + Size(1600, 1200), + Size(1600, 900), + Size(1680, 1050), + Size(1920, 1080), + Size(1920, 1200), + Size(2048, 1080), + Size(2048, 1152), + Size(2048, 1536), + Size(2160, 1080), + Size(2560, 1080), + Size(2560, 1440), + Size(2560, 1600), + Size(2560, 2048), + Size(2960, 1440), + Size(3200, 1800), + Size(3200, 2048), + Size(3200, 2400), + Size(3440, 1440), + Size(3840, 1080), + Size(3840, 1600), + Size(3840, 2160), + Size(3840, 2400), + Size(4096, 2160), + Size(5120, 2160), + Size(5120, 2880), + Size(7680, 4320), + }; + std::vector sizes; + + /* Make sure pixel format exists. */ + auto const &it = formats_.find(pixelformat); + if (it == formats_.end()) + return {}; + + /* Try create list of discrete sizes. */ + const std::vector &ranges = it->second; + bool discrete = true; + for (const SizeRange &range : ranges) { + if (range.min != range.max) { + discrete = false; + break; + } + sizes.emplace_back(range.min.width, range.min.height); + } + + /* If discrete not possible generate from range. */ + if (!discrete) { + if (ranges.size() != 1) { + LOG(Stream, Error) << "Range format is ambiguous"; + return {}; + } + + const SizeRange &limit = ranges.front(); + sizes.clear(); + + for (const Size &size : rangeDiscreteSizes) { + if (size.width < limit.min.width || + size.width > limit.max.width || + size.height < limit.min.height || + size.height > limit.max.height || + (size.width - limit.min.width) % limit.vStep || + (size.height - limit.min.height) % limit.hStep) + continue; + + sizes.push_back(size); + } + } + + std::sort(sizes.begin(), sizes.end()); + + return sizes; +} + +/** + * \brief Retrieve a frame size range + * \param[in] pixelformat Pixel format to retrieve range for + * \returns Range description of frame size + */ +SizeRange StreamFormats::range(unsigned int pixelformat) const +{ + auto const it = formats_.find(pixelformat); + if (it == formats_.end()) + return {}; + + const SizeRange &first = it->second.front(); + if (it->second.size() == 1) + return first; + + LOG(Stream, Debug) << "Building range from discret"; + + SizeRange range(first.min.width, first.min.height, + first.max.width, first.max.height); + + for (const SizeRange &limit : it->second) { + if (limit.min < range.min) + range.min = limit.min; + + if (limit.max > range.max) + range.max = limit.max; + } + + return range; +} + /** * \struct StreamConfiguration * \brief Configuration parameters for a stream From patchwork Mon May 27 00:15:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1304 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2880C618F5 for ; Mon, 27 May 2019 02:16:12 +0200 (CEST) X-Halon-ID: 9fdee253-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9fdee253-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:08 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:38 +0200 Message-Id: <20190527001543.13593-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/17] libcamera: stream: StreamConfiguration: Add StreamFormats information 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, 27 May 2019 00:16:14 -0000 Allow StreamFormats to be associated to a StreamConfiguration. The intention is that pipeline handlers should associate formats to a StreamConfiguration when it's created in generateConfiguration(). Signed-off-by: Niklas Söderlund --- include/libcamera/stream.h | 8 ++++---- src/libcamera/stream.cpp | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/libcamera/stream.h b/include/libcamera/stream.h index 48daf5ac23f55d85..5b4fea324ce449b1 100644 --- a/include/libcamera/stream.h +++ b/include/libcamera/stream.h @@ -35,10 +35,8 @@ private: }; struct StreamConfiguration { - StreamConfiguration() - : stream_(nullptr) - { - } + StreamConfiguration(); + StreamConfiguration(const StreamFormats &formats); unsigned int pixelFormat; Size size; @@ -47,11 +45,13 @@ struct StreamConfiguration { Stream *stream() const { return stream_; } void setStream(Stream *stream) { stream_ = stream; } + const StreamFormats &formats() const { return formats_; } std::string toString() const; private: Stream *stream_; + StreamFormats formats_; }; enum StreamRole { diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp index a2931902fda2baa5..4452b6ff010cfbdf 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -260,6 +260,19 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * configured for a single video stream. */ +StreamConfiguration::StreamConfiguration() + : stream_(nullptr) +{ +} + +/** + * \brief Create with stream format description + */ +StreamConfiguration::StreamConfiguration(const StreamFormats &formats) + : stream_(nullptr), formats_(formats) +{ +} + /** * \var StreamConfiguration::size * \brief Stream size in pixels @@ -300,6 +313,12 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * \param[in] stream The stream */ +/** + * \fn StreamConfiguration::formats() + * \brief Retrieve the advisory stream formats description + * \return A stream formats description + */ + /** * \brief Assemble and return a string describing the configuration * From patchwork Mon May 27 00:15:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1306 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A707E618FA for ; Mon, 27 May 2019 02:16:12 +0200 (CEST) X-Halon-ID: a02b7618-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a02b7618-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:08 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:39 +0200 Message-Id: <20190527001543.13593-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/17] test: stream: Add test for StreamFormat 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, 27 May 2019 00:16:14 -0000 Test that both discrete and range based stream format descriptions result in good discrete frame sizes. The range based stream formats needs to be fitted with a table of resolutions inside libcamera so if that table is update this test might need to be updated. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- test/meson.build | 1 + test/stream/meson.build | 11 ++++ test/stream/stream_formats.cpp | 102 +++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 test/stream/meson.build create mode 100644 test/stream/stream_formats.cpp diff --git a/test/meson.build b/test/meson.build index 609aeab80e7d0f4f..5370f3028a4fe39d 100644 --- a/test/meson.build +++ b/test/meson.build @@ -4,6 +4,7 @@ subdir('camera') subdir('ipa') subdir('media_device') subdir('pipeline') +subdir('stream') subdir('v4l2_device') subdir('v4l2_subdevice') diff --git a/test/stream/meson.build b/test/stream/meson.build new file mode 100644 index 0000000000000000..5b42fe32b341970f --- /dev/null +++ b/test/stream/meson.build @@ -0,0 +1,11 @@ +stream_tests = [ + [ 'stream_formats', 'stream_formats.cpp' ], +] + +foreach t : stream_tests + exe = executable(t[0], t[1], + dependencies : libcamera_dep, + link_with : test_libraries, + include_directories : test_includes_internal) + test(t[0], exe, suite: 'stream', is_parallel: false) +endforeach diff --git a/test/stream/stream_formats.cpp b/test/stream/stream_formats.cpp new file mode 100644 index 0000000000000000..42a596cc69893b20 --- /dev/null +++ b/test/stream/stream_formats.cpp @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * stream_formats.cpp - StreamFormats test + */ + +#include + +#include +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class StreamFormatsTest : public Test +{ +protected: + int testSizes(std::string name, std::vector test, std::vector valid) + { + bool pass = false; + + for (Size &size : test) { + pass = false; + + for (Size &validSize : valid) { + if (size == validSize) { + pass = true; + break; + } + } + + if (!pass) + break; + } + + if (!pass) { + cout << "Failed " << name << endl; + cout << "Sizes to test:" << endl; + for (Size &size : test) + cout << size.toString() << endl; + cout << "Valid sizes:" << endl; + for (Size &size : valid) + cout << size.toString() << endl; + + return TestFail; + } + + return TestPass; + } + + int run() + { + /* Test discrete sizes */ + StreamFormats discrete({ + { 1, { SizeRange(100, 100), SizeRange(200, 200) } }, + { 2, { SizeRange(300, 300), SizeRange(400, 400) } }, + }); + + if (testSizes("discrete 1", discrete.sizes(1), + { Size(100, 100), Size(200, 200) })) + return TestFail; + if (testSizes("discrete 2", discrete.sizes(2), + { Size(300, 300), Size(400, 400) })) + return TestFail; + + /* Test range sizes */ + StreamFormats range({ + { 1, { SizeRange(640, 480, 640, 480) } }, + { 2, { SizeRange(640, 480, 800, 600, 8, 8) } }, + { 3, { SizeRange(640, 480, 800, 600, 16, 16) } }, + { 4, { SizeRange(128, 128, 4096, 4096, 128, 128) } }, + }); + + if (testSizes("range 1", range.sizes(1), { Size(640, 480) })) + return TestFail; + + if (testSizes("range 2", range.sizes(2), { + Size(640, 480), Size(720, 480), + Size(720, 576), Size(768, 480), + Size(800, 600) })) + return TestFail; + + + if (testSizes("range 3", range.sizes(3), { + Size(640, 480), Size(720, 480), + Size(720, 576), Size(768, 480) })) + return TestFail; + + if (testSizes("range 4", range.sizes(4), { + Size(1024, 768), Size(1280, 1024), + Size(2048, 1152), Size(2048, 1536), + Size(2560, 2048), Size(3200, 2048), })) + return TestFail; + + return TestPass; + } +}; + +TEST_REGISTER(StreamFormatsTest) From patchwork Mon May 27 00:15:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1308 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 35B6D61909 for ; Mon, 27 May 2019 02:16:14 +0200 (CEST) X-Halon-ID: a0b8a676-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a0b8a676-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:09 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:40 +0200 Message-Id: <20190527001543.13593-15-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 14/17] cam: Move camera configuration preparation to CamApp 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, 27 May 2019 00:16:15 -0000 Most of the camera configuration preparation which is done in the Capture module is not specific to capturing and could be useful for other modules. Extract the generic parts to CamApp and do basic preparation of the configuration before passing it to modules. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/cam/capture.cpp | 84 ++++----------------------------------------- src/cam/capture.h | 7 ++-- src/cam/main.cpp | 75 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp index a4aa44af25828f23..e455612b36238157 100644 --- a/src/cam/capture.cpp +++ b/src/cam/capture.cpp @@ -15,8 +15,8 @@ using namespace libcamera; -Capture::Capture(Camera *camera) - : camera_(camera), writer_(nullptr), last_(0) +Capture::Capture(Camera *camera, CameraConfiguration *config) + : camera_(camera), config_(config), writer_(nullptr), last_(0) { } @@ -29,13 +29,13 @@ int Capture::run(EventLoop *loop, const OptionsParser::Options &options) return -ENODEV; } - ret = prepareConfig(options); - if (ret) { - std::cout << "Failed to prepare camera configuration" << std::endl; - return -EINVAL; + streamName_.clear(); + for (unsigned int index = 0; index < config_->size(); ++index) { + StreamConfiguration &cfg = config_->at(index); + streamName_[cfg.stream()] = "stream" + std::to_string(index); } - ret = camera_->configure(config_.get()); + ret = camera_->configure(config_); if (ret < 0) { std::cout << "Failed to configure camera" << std::endl; return ret; @@ -64,80 +64,10 @@ int Capture::run(EventLoop *loop, const OptionsParser::Options &options) } camera_->freeBuffers(); - config_.reset(); return ret; } -int Capture::prepareConfig(const OptionsParser::Options &options) -{ - StreamRoles roles; - - if (options.isSet(OptStream)) { - const std::vector &streamOptions = - options[OptStream].toArray(); - - /* Use roles and get a default configuration. */ - for (auto const &value : streamOptions) { - KeyValueParser::Options opt = value.toKeyValues(); - - if (!opt.isSet("role")) { - roles.push_back(StreamRole::VideoRecording); - } else if (opt["role"].toString() == "viewfinder") { - roles.push_back(StreamRole::Viewfinder); - } else if (opt["role"].toString() == "video") { - roles.push_back(StreamRole::VideoRecording); - } else if (opt["role"].toString() == "still") { - roles.push_back(StreamRole::StillCapture); - } else { - std::cerr << "Unknown stream role " - << opt["role"].toString() << std::endl; - return -EINVAL; - } - } - } else { - /* If no configuration is provided assume a single video stream. */ - roles.push_back(StreamRole::VideoRecording); - } - - config_ = camera_->generateConfiguration(roles); - if (!config_ || config_->size() != roles.size()) { - std::cerr << "Failed to get default stream configuration" - << std::endl; - return -EINVAL; - } - - /* Apply configuration if explicitly requested. */ - if (options.isSet(OptStream)) { - const std::vector &streamOptions = - options[OptStream].toArray(); - - unsigned int i = 0; - for (auto const &value : streamOptions) { - KeyValueParser::Options opt = value.toKeyValues(); - StreamConfiguration &cfg = config_->at(i++); - - if (opt.isSet("width")) - cfg.size.width = opt["width"]; - - if (opt.isSet("height")) - cfg.size.height = opt["height"]; - - /* TODO: Translate 4CC string to ID. */ - if (opt.isSet("pixelformat")) - cfg.pixelFormat = opt["pixelformat"]; - } - } - - streamName_.clear(); - for (unsigned int index = 0; index < config_->size(); ++index) { - StreamConfiguration &cfg = config_->at(index); - streamName_[cfg.stream()] = "stream" + std::to_string(index); - } - - return 0; -} - int Capture::capture(EventLoop *loop) { int ret; diff --git a/src/cam/capture.h b/src/cam/capture.h index a97d1f44d229c214..1d4a25a84a51403b 100644 --- a/src/cam/capture.h +++ b/src/cam/capture.h @@ -20,19 +20,18 @@ class Capture { public: - Capture(libcamera::Camera *camera); + Capture(libcamera::Camera *camera, + libcamera::CameraConfiguration *config); int run(EventLoop *loop, const OptionsParser::Options &options); private: - int prepareConfig(const OptionsParser::Options &options); - int capture(EventLoop *loop); void requestComplete(libcamera::Request *request, const std::map &buffers); libcamera::Camera *camera_; - std::unique_ptr config_; + libcamera::CameraConfiguration *config_; std::map streamName_; BufferWriter *writer_; diff --git a/src/cam/main.cpp b/src/cam/main.cpp index dbf04917bcc5aa38..338740d1512c7189 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -33,19 +33,21 @@ public: private: int parseOptions(int argc, char *argv[]); + int prepareConfig(); int run(); static CamApp *app_; OptionsParser::Options options_; CameraManager *cm_; std::shared_ptr camera_; + std::unique_ptr config_; EventLoop *loop_; }; CamApp *CamApp::app_ = nullptr; CamApp::CamApp() - : cm_(nullptr), camera_(nullptr), loop_(nullptr) + : cm_(nullptr), camera_(nullptr), config_(nullptr), loop_(nullptr) { CamApp::app_ = this; } @@ -90,6 +92,10 @@ int CamApp::init(int argc, char **argv) } std::cout << "Using camera " << camera_->name() << std::endl; + + ret = prepareConfig(); + if (ret) + return ret; } loop_ = new EventLoop(cm_->eventDispatcher()); @@ -107,6 +113,8 @@ void CamApp::cleanup() camera_.reset(); } + config_.reset(); + cm_->stop(); } @@ -168,6 +176,69 @@ int CamApp::parseOptions(int argc, char *argv[]) return 0; } +int CamApp::prepareConfig() +{ + StreamRoles roles; + + if (options_.isSet(OptStream)) { + const std::vector &streamOptions = + options_[OptStream].toArray(); + + /* Use roles and get a default configuration. */ + for (auto const &value : streamOptions) { + KeyValueParser::Options opt = value.toKeyValues(); + + if (!opt.isSet("role")) { + roles.push_back(StreamRole::VideoRecording); + } else if (opt["role"].toString() == "viewfinder") { + roles.push_back(StreamRole::Viewfinder); + } else if (opt["role"].toString() == "video") { + roles.push_back(StreamRole::VideoRecording); + } else if (opt["role"].toString() == "still") { + roles.push_back(StreamRole::StillCapture); + } else { + std::cerr << "Unknown stream role " + << opt["role"].toString() << std::endl; + return -EINVAL; + } + } + } else { + /* If no configuration is provided assume a single video stream. */ + roles.push_back(StreamRole::VideoRecording); + } + + config_ = camera_->generateConfiguration(roles); + if (!config_ || config_->size() != roles.size()) { + std::cerr << "Failed to get default stream configuration" + << std::endl; + return -EINVAL; + } + + /* Apply configuration if explicitly requested. */ + if (options_.isSet(OptStream)) { + const std::vector &streamOptions = + options_[OptStream].toArray(); + + unsigned int i = 0; + for (auto const &value : streamOptions) { + KeyValueParser::Options opt = value.toKeyValues(); + StreamConfiguration &cfg = config_->at(i++); + + if (opt.isSet("width")) + cfg.size.width = opt["width"]; + + if (opt.isSet("height")) + cfg.size.height = opt["height"]; + + /* TODO: Translate 4CC string to ID. */ + if (opt.isSet("pixelformat")) + cfg.pixelFormat = opt["pixelformat"]; + } + } + + return 0; +} + int CamApp::run() { if (options_.isSet(OptList)) { @@ -177,7 +248,7 @@ int CamApp::run() } if (options_.isSet(OptCapture)) { - Capture capture(camera_.get()); + Capture capture(camera_.get(), config_.get()); return capture.run(loop_, options_); } From patchwork Mon May 27 00:15:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1309 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3518B60E47 for ; Mon, 27 May 2019 02:16:14 +0200 (CEST) X-Halon-ID: a1228b87-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a1228b87-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:10 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:41 +0200 Message-Id: <20190527001543.13593-16-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 15/17] cam: Validate camera 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, 27 May 2019 00:16:15 -0000 Use CameraConfiguration::validate() to validate and possibly update the camera configuration when its prepared. Signed-off-by: Niklas Söderlund Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/cam/main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 338740d1512c7189..25538f5ba95552d6 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -236,6 +236,18 @@ int CamApp::prepareConfig() } } + switch (config_->validate()) { + case CameraConfiguration::Valid: + break; + case CameraConfiguration::Adjusted: + std::cout << "Camera configuration adjusted" << std::endl; + break; + case CameraConfiguration::Invalid: + std::cout << "Camera configuration invalid" << std::endl; + config_.reset(); + return -EINVAL; + } + return 0; } From patchwork Mon May 27 00:15:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1307 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 359CB61903 for ; Mon, 27 May 2019 02:16:14 +0200 (CEST) X-Halon-ID: a150a5df-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a150a5df-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:10 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:42 +0200 Message-Id: <20190527001543.13593-17-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 16/17] cam: Add --info option to print information about stream(s) 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, 27 May 2019 00:16:15 -0000 Add a new option to cam tool which prints information about the configuration supplied by the user. If specified information is printed about the configuration after its been verified and possibly adjusted by the camera and information about each stream in the camera configuration. Signed-off-by: Niklas Söderlund --- src/cam/info.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/cam/info.h | 18 ++++++++++++++++++ src/cam/main.cpp | 8 ++++++++ src/cam/main.h | 1 + src/cam/meson.build | 1 + 5 files changed, 72 insertions(+) create mode 100644 src/cam/info.cpp create mode 100644 src/cam/info.h diff --git a/src/cam/info.cpp b/src/cam/info.cpp new file mode 100644 index 0000000000000000..35271942600494c7 --- /dev/null +++ b/src/cam/info.cpp @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * info.cpp - Displat stream information + */ + +#include +#include + +#include "info.h" + +using namespace libcamera; + +int Info::run(const CameraConfiguration *config) +{ + if (!config) { + std::cout + << "Can't display information, no configuration" + << std::endl; + return -ENODEV; + } + + unsigned int index = 0; + for (const StreamConfiguration cfg : *config) { + std::cout << index << ": " << cfg.toString() << std::endl; + + const StreamFormats &formats = cfg.formats(); + for (unsigned int pixelformat : formats.pixelformats()) { + std::cout << " * Pixelformat: 0x" << std::hex + << std::setw(8) << pixelformat << " " + << formats.range(pixelformat).toString() + << std::endl; + + for (const Size &size : formats.sizes(pixelformat)) + std::cout << " - " << size.toString() + << std::endl; + } + + index++; + } + + return 0; +} diff --git a/src/cam/info.h b/src/cam/info.h new file mode 100644 index 0000000000000000..72fd446491f95033 --- /dev/null +++ b/src/cam/info.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * info.h - Displat stream information + */ +#ifndef __CAM_INFO_H__ +#define __CAM_INFO_H__ + +#include + +class Info +{ +public: + int run(const libcamera::CameraConfiguration *config); +}; + +#endif /* __CAM_INFO_H__ */ diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 25538f5ba95552d6..bf7a92b51d27c890 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -13,6 +13,7 @@ #include "capture.h" #include "event_loop.h" +#include "info.h" #include "main.h" #include "options.h" @@ -162,6 +163,8 @@ int CamApp::parseOptions(int argc, char *argv[]) "Set configuration of a camera stream", "stream", true); parser.addOption(OptHelp, OptionNone, "Display this help message", "help"); + parser.addOption(OptInfo, OptionNone, + "Display information about stream(s)", "info"); parser.addOption(OptList, OptionNone, "List all cameras", "list"); options_ = parser.parse(argc, argv); @@ -259,6 +262,11 @@ int CamApp::run() std::cout << "- " << cam->name() << std::endl; } + if (options_.isSet(OptInfo)) { + Info info; + info.run(config_.get()); + } + if (options_.isSet(OptCapture)) { Capture capture(camera_.get(), config_.get()); return capture.run(loop_, options_); diff --git a/src/cam/main.h b/src/cam/main.h index fff81b1f6c860b57..6324c042f89e7396 100644 --- a/src/cam/main.h +++ b/src/cam/main.h @@ -12,6 +12,7 @@ enum { OptCapture = 'C', OptFile = 'F', OptHelp = 'h', + OptInfo = 'i', OptList = 'l', OptStream = 's', }; diff --git a/src/cam/meson.build b/src/cam/meson.build index 478346c59590631d..ee5b28421e4c1235 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -2,6 +2,7 @@ cam_sources = files([ 'buffer_writer.cpp', 'capture.cpp', 'event_loop.cpp', + 'info.cpp', 'main.cpp', 'options.cpp', ]) From patchwork Mon May 27 00:15:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 1310 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B4742618F9 for ; Mon, 27 May 2019 02:16:14 +0200 (CEST) X-Halon-ID: a199a472-8014-11e9-8ab4-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id a199a472-8014-11e9-8ab4-005056917a89; Mon, 27 May 2019 02:16:11 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 27 May 2019 02:15:43 +0200 Message-Id: <20190527001543.13593-18-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> References: <20190527001543.13593-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 17/17] libcamera: pipeline: uvcvideo: Add format information and validation 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, 27 May 2019 00:16:15 -0000 Extend the uvcvideo pipeline with format information and validation. The format information is gathered by enumerating the v4l2 device. This enumeration approach is valid for UVC as it has a static and simple media graph. Signed-off-by: Niklas Söderlund --- src/libcamera/pipeline/uvcvideo.cpp | 46 +++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 45260f34c8f5daba..ce9f281891a8bc5e 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -95,18 +95,42 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() } StreamConfiguration &cfg = config_[0]; + const StreamFormats &formats = cfg.formats(); - /* \todo: Validate the configuration against the device capabilities. */ const unsigned int pixelFormat = cfg.pixelFormat; const Size size = cfg.size; - cfg.pixelFormat = V4L2_PIX_FMT_YUYV; - cfg.size = { 640, 480 }; + bool found = false; + for (unsigned int pixfmt : formats.pixelformats()) { + if (pixfmt == pixelFormat) { + found = true; + break; + } + } + if (!found) + cfg.pixelFormat = formats.pixelformats().front(); - if (cfg.pixelFormat != pixelFormat || cfg.size != size) { + if (cfg.pixelFormat != pixelFormat) { LOG(UVC, Debug) - << "Adjusting configuration from " << cfg.toString() - << " to " << cfg.size.toString() << "-YUYV"; + << "Adjusting pixel format from " << pixelFormat + << " to " << cfg.pixelFormat; + status = Adjusted; + } + + const std::vector &formatSizes = formats.sizes(cfg.pixelFormat); + cfg.size = formatSizes.front(); + for (const Size &formatsSize : formatSizes) { + if (formatsSize <= size) + cfg.size = formatsSize; + + if (formatsSize == size) + break; + } + + if (cfg.size != size) { + LOG(UVC, Debug) + << "Adjusting size from " << size.toString() + << " to " << cfg.size.toString(); status = Adjusted; } @@ -123,14 +147,18 @@ PipelineHandlerUVC::PipelineHandlerUVC(CameraManager *manager) CameraConfiguration *PipelineHandlerUVC::generateConfiguration(Camera *camera, const StreamRoles &roles) { + UVCCameraData *data = cameraData(camera); CameraConfiguration *config = new UVCCameraConfiguration(); if (roles.empty()) return config; - StreamConfiguration cfg{}; - cfg.pixelFormat = V4L2_PIX_FMT_YUYV; - cfg.size = { 640, 480 }; + V4L2DeviceFormats v4l2formats = data->video_->formats(); + StreamFormats formats(v4l2formats.data()); + StreamConfiguration cfg(formats); + + cfg.pixelFormat = formats.pixelformats().front(); + cfg.size = formats.sizes(cfg.pixelFormat).back(); cfg.bufferCount = 4; config->addConfiguration(cfg);