From patchwork Wed Jun 19 02:51:14 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: 1451 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 3D44561A23 for ; Wed, 19 Jun 2019 04:52:23 +0200 (CEST) X-Halon-ID: 3af7e874-923d-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 3af7e874-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:09 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:14 +0200 Message-Id: <20190619025129.21164-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 01/16] 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: Wed, 19 Jun 2019 02:52:23 -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 fb8f628a0d8af200..26a05b9e7d800077 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 a size range representing a single size + * \param[in] width The size width + * \param[in] height The size height + */ + /** * \fn SizeRange::SizeRange(unsigned int minW, unsigned int minH, * unsigned int maxW, unsigned int maxH) From patchwork Wed Jun 19 02:51:15 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: 1453 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A4A0561A2F for ; Wed, 19 Jun 2019 04:52:24 +0200 (CEST) X-Halon-ID: 3b53e2e9-923d-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 3b53e2e9-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:10 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:15 +0200 Message-Id: <20190619025129.21164-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 02/16] libcamera: geometry: SizeRange: Extend with step 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: Wed, 19 Jun 2019 02:52:25 -0000 The size range described might be subject to certain step limitations. Make it possible to record this information. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/geometry.h | 13 ++++++++-- src/libcamera/geometry.cpp | 49 +++++++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index ec5ed2bee196c82d..b2a8e5b0e005e4db 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(1), vStep(1) { } 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 26a05b9e7d800077..1ea102935bdb256c 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -186,9 +186,29 @@ bool operator<(const Size &lhs, const Size &rhs) * \struct SizeRange * \brief Describe a range of sizes * - * 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. + * A 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. + * + * Size ranges may further limit the valid sizes through steps in the horizontal + * and vertical direction. The step values represent the increase in pixels + * between two valid width or height values, starting from the minimum. Valid + * sizes within the range are thus expressed as + * + * width = min.width + hStep * x + * height = min.height + vStep * y + * + * Where + * + * width <= max.width + * height < max.height + * + * Note that the step values are not equivalent to alignments, as the minimum + * width or height may not be a multiple of the corresponding step. + * + * The step values may be zero when the range describes only minimum and + * maximum sizes without implying that all, or any, intermediate size is valid. + * SizeRange instances the describe a single size have both set values set to 1. */ /** @@ -213,6 +233,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 @@ -223,6 +256,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 Wed Jun 19 02:51:16 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: 1452 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 9F95361A29 for ; Wed, 19 Jun 2019 04:52:24 +0200 (CEST) X-Halon-ID: 3bd9d88b-923d-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 3bd9d88b-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:10 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:16 +0200 Message-Id: <20190619025129.21164-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 03/16] 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: Wed, 19 Jun 2019 02:52:25 -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 Reviewed-by: Laurent Pinchart --- include/libcamera/geometry.h | 6 +++++- src/libcamera/geometry.cpp | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index b2a8e5b0e005e4db..03962d7d09fac2b0 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 { { } + std::string toString() const; + Size min; Size max; unsigned int hStep; diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 1ea102935bdb256c..e598f6ad66076996 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -266,6 +266,20 @@ 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 + */ +std::string SizeRange::toString() const +{ + std::stringstream ss; + + ss << "(" << min.toString() << ")-(" << max.toString() << ")/(+" + << hStep << ",+" << vStep << ")"; + + return ss.str(); +} + /** * \brief Compare size ranges for equality * \return True if the two size ranges are equal, false otherwise From patchwork Wed Jun 19 02:51:17 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: 1454 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 1FF2761A31 for ; Wed, 19 Jun 2019 04:52:25 +0200 (CEST) X-Halon-ID: 3c34d883-923d-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 3c34d883-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:11 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:17 +0200 Message-Id: <20190619025129.21164-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 04/16] libcamera: geometry: SizeRange: Add contains() 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: Wed, 19 Jun 2019 02:52:25 -0000 Add a method to check if a Size can fit inside a SizeRange. When determining if a size is containable take step values into account if they are not set to 0. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- include/libcamera/geometry.h | 2 ++ src/libcamera/geometry.cpp | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 03962d7d09fac2b0..52f4d010de76f840 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -92,6 +92,8 @@ public: { } + bool contains(const Size &size) const; + std::string toString() const; Size min; diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index e598f6ad66076996..32b0faeadc6376e3 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -266,6 +266,22 @@ bool operator<(const Size &lhs, const Size &rhs) * \brief The vertical step */ +/** + * \brief Test if a size is contained in the range + * \param[in] size Size to check + * \returns True if \a size is contained in the range + */ +bool SizeRange::contains(const Size &size) const +{ + if (size.width < min.width || size.width > max.width || + size.height < min.height || size.height > max.height || + (hStep && (size.width - min.width) % hStep) || + (vStep && (size.height - min.height) % vStep)) + return false; + + return true; +} + /** * \brief Assemble and return a string describing the size range * \return A string describing the SizeRange From patchwork Wed Jun 19 02:51:18 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: 1455 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 0546361A4B for ; Wed, 19 Jun 2019 04:52:25 +0200 (CEST) X-Halon-ID: 3c98ed5b-923d-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 3c98ed5b-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:12 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:18 +0200 Message-Id: <20190619025129.21164-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 05/16] libcamera: formats: Add ImageFormats 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: Wed, 19 Jun 2019 02:52:26 -0000 Add a new class to hold format information for V4L2 devices and subdevices. The object describes the relationship between either pixel formats (V4L2 devices) or media bus codes (V4L2 subdevice) and a list of image sizes which can be produced with that format. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/formats.cpp | 88 +++++++++++++++++++++++++++++++++ src/libcamera/include/formats.h | 14 ++++++ 2 files changed, 102 insertions(+) diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index 56f4ddb51ffad4d3..312db6557c5beff9 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -24,4 +24,92 @@ namespace libcamera { * resolutions represented by SizeRange items. */ +/** + * \class ImageFormats + * \brief Describe V4L2Device and V4L2SubDevice image formats + * + * This class stores a list of image formats, each associated with a + * corresponding set of image sizes. It is used to describe the formats and + * sizes supported by a V4L2Device or V4L2Subdevice. + * + * Formats are stored as an integer. When used for a V4L2Device, the image + * formats are fourcc pixel formats. When used for a V4L2Subdevice they are + * media bus codes. Both are defined by the V4L2 specification. + * + * Sizes are stored as a list of SizeRange. + */ + +/** + * \brief Add a format and corresponding sizes to the description + * \param[in] format Pixel format or media bus code to describe + * \param[in] sizes List of supported size ranges for the format + * + * \return 0 on success or a negative error code otherwise + * \retval -EEXIST The format is already described + */ +int ImageFormats::addFormat(unsigned int format, const std::vector &sizes) +{ + if (data_.find(format) != data_.end()) + return -EEXIST; + + data_[format] = sizes; + + return 0; +} + +/** + * \brief Check if the list of devices supported formats is empty + * \return True if the list of supported formats is empty + */ +bool ImageFormats::isEmpty() const +{ + return data_.empty(); +} + +/** + * \brief Retrieve a list of all supported image formats + * \return List of pixel formats or media bus codes + */ +std::vector ImageFormats::formats() const +{ + std::vector formats; + formats.reserve(data_.size()); + + /* \todo: Should this be cached instead of computed each time? */ + for (auto const &it : data_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve all sizes for a specific format + * \param[in] format The pixel format or mbus code + * + * Retrieve all size ranges for a specific format. For V4L2Device \a format is a + * pixel format while for a V4L2Subdevice \a format is a media bus code. + * + * \return The list of image sizes supported for \a format, or an empty list if + * the format is not supported + */ +const std::vector &ImageFormats::sizes(unsigned int format) const +{ + static std::vector empty; + + auto const &it = data_.find(format); + if (it == data_.end()) + return empty; + + return it->second; +} + +/** + * \brief Retrieve the map that associates formats to image sizes + * \return The map that associates formats to image sizes + */ +const std::map> &ImageFormats::data() const +{ + return data_; +} + } /* namespace libcamera */ diff --git a/src/libcamera/include/formats.h b/src/libcamera/include/formats.h index a73772b1eda068b4..6ec8312590b74f03 100644 --- a/src/libcamera/include/formats.h +++ b/src/libcamera/include/formats.h @@ -17,6 +17,20 @@ namespace libcamera { typedef std::map> FormatEnum; +class ImageFormats +{ +public: + int addFormat(unsigned int format, const std::vector &sizes); + + bool isEmpty() const; + std::vector formats() const; + const std::vector &sizes(unsigned int format) const; + const std::map> &data() const; + +private: + std::map> data_; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_FORMATS_H__ */ From patchwork Wed Jun 19 02:51:19 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: 1456 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 A2E0361A54 for ; Wed, 19 Jun 2019 04:52:26 +0200 (CEST) X-Halon-ID: 3cfa4602-923d-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 3cfa4602-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:12 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:19 +0200 Message-Id: <20190619025129.21164-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 06/16] 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: Wed, 19 Jun 2019 02:52:27 -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 Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_subdevice.h | 1 + src/libcamera/v4l2_subdevice.cpp | 59 ++++++++++++++------------ 2 files changed, 34 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..99e202fa264af5a6 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,35 @@ 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 = {}; + mbusEnum.pad = pad; + mbusEnum.index = index; + mbusEnum.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 Wed Jun 19 02:51:20 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: 1457 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 8CAD161A48 for ; Wed, 19 Jun 2019 04:52:27 +0200 (CEST) X-Halon-ID: 3d71c56c-923d-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 3d71c56c-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:13 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:20 +0200 Message-Id: <20190619025129.21164-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 07/16] 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: Wed, 19 Jun 2019 02:52:28 -0000 Align the enumPadSizes() interface and implementation with that of enumPadCodes(). There is no functional change. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/include/v4l2_subdevice.h | 4 +-- src/libcamera/v4l2_subdevice.cpp | 38 ++++++++++++++------------ 2 files changed, 22 insertions(+), 20 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 99e202fa264af5a6..3296bc010fe8313f 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -209,10 +209,14 @@ FormatEnum V4L2Subdevice::formats(unsigned int pad) return {}; } - for (unsigned int code : enumPadCodes(pad)) - if (enumPadSizes(pad, code, &formatMap[code])) + for (unsigned int code : enumPadCodes(pad)) { + std::vector sizes = enumPadSizes(pad, code); + if (sizes.empty()) return {}; + formatMap[code] = sizes; + } + return formatMap; } @@ -335,25 +339,25 @@ 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 = {}; + sizeEnum.index = index; + sizeEnum.pad = pad; + sizeEnum.code = code; + sizeEnum.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, - sizeEnum.max_width, sizeEnum.max_height); - - sizeEnum.index++; + sizes.emplace_back(sizeEnum.min_width, sizeEnum.min_height, + sizeEnum.max_width, sizeEnum.max_height); } if (ret && (errno != EINVAL && errno != ENOTTY)) { @@ -361,12 +365,10 @@ int V4L2Subdevice::enumPadSizes(unsigned int pad,unsigned int code, LOG(V4L2Subdev, Error) << "Unable to enumerate sizes on pad " << pad << ": " << strerror(-ret); - sizes->clear(); - - return ret; + return {}; } - return 0; + return sizes; } int V4L2Subdevice::setSelection(unsigned int pad, unsigned int target, From patchwork Wed Jun 19 02:51:21 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: 1458 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 5B84F61A26 for ; Wed, 19 Jun 2019 04:52:28 +0200 (CEST) X-Halon-ID: 3de1fc3b-923d-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 3de1fc3b-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:14 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:21 +0200 Message-Id: <20190619025129.21164-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 08/16] libcamera: v4l2_subdevice: Replace FormatEnum with ImageFormats 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: Wed, 19 Jun 2019 02:52:28 -0000 Replace all usage of FormatEnum with ImageFormats and completely remove FormatEnum which is no longer needed. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/camera_sensor.cpp | 14 ++++++-------- src/libcamera/formats.cpp | 10 ---------- src/libcamera/include/formats.h | 2 -- src/libcamera/include/v4l2_subdevice.h | 2 +- src/libcamera/v4l2_subdevice.cpp | 26 +++++++++++++------------- test/v4l2_subdevice/list_formats.cpp | 16 ++++++++-------- 6 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index cb6649efac3ff794..a804a68c9d91cda6 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); - if (formats.empty()) { + const ImageFormats formats = subdev_->formats(0); + if (formats.isEmpty()) { 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.formats(); /* * 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 312db6557c5beff9..f1a62d47e67870af 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -14,16 +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 ImageFormats * \brief Describe V4L2Device and V4L2SubDevice image formats diff --git a/src/libcamera/include/formats.h b/src/libcamera/include/formats.h index 6ec8312590b74f03..796d65f1fba3f84a 100644 --- a/src/libcamera/include/formats.h +++ b/src/libcamera/include/formats.h @@ -15,8 +15,6 @@ namespace libcamera { -typedef std::map> FormatEnum; - class ImageFormats { public: diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index c6fdf417b43c0423..9afd28b6db023ddf 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); + ImageFormats 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 3296bc010fe8313f..c38f95a3b69d9f18 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -187,22 +187,17 @@ int V4L2Subdevice::setCompose(unsigned int pad, Rectangle *rect) } /** - * \brief List the sub-device image resolutions and formats on \a pad + * \brief Enumerate all media bus codes and frame sizes on a \a pad * \param[in] pad The 0-indexed pad number to enumerate formats on * - * Retrieve a list of image formats and sizes on the \a pad of a video - * subdevice. Subdevices can report either a list of discrete sizes they - * support or a list of intervals expressed as a [min-max] sizes range. + * Enumerate all media bus codes and frame sizes supported by the subdevice on + * a \a pad. * - * Each image size list is associated with a media bus pixel code for which - * the reported resolutions are supported. - * - * \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 + * \return A list of the supported device formats */ -FormatEnum V4L2Subdevice::formats(unsigned int pad) +ImageFormats V4L2Subdevice::formats(unsigned int pad) { - FormatEnum formatMap = {}; + ImageFormats formats; if (pad >= entity_->pads().size()) { LOG(V4L2Subdev, Error) << "Invalid pad: " << pad; @@ -214,10 +209,15 @@ FormatEnum V4L2Subdevice::formats(unsigned int pad) if (sizes.empty()) return {}; - formatMap[code] = sizes; + if (formats.addFormat(code, sizes)) { + LOG(V4L2Subdev, Error) + << "Could not add sizes for media bus code " + << code << " on pad " << pad; + return {}; + } } - return formatMap; + return formats; } /** diff --git a/test/v4l2_subdevice/list_formats.cpp b/test/v4l2_subdevice/list_formats.cpp index 3f0edafcdcd72d6b..067dc5ed30f4edd9 100644 --- a/test/v4l2_subdevice/list_formats.cpp +++ b/test/v4l2_subdevice/list_formats.cpp @@ -47,29 +47,29 @@ void ListFormatsTest::printFormats(unsigned int pad, int ListFormatsTest::run() { /* List all formats available on existing "Scaler" pads. */ - std::map> formats; + ImageFormats formats; formats = scaler_->formats(0); - if (formats.empty()) { + if (formats.isEmpty()) { cerr << "Failed to list formats on pad 0 of subdevice " << 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.formats()) + printFormats(0, code, formats.sizes(code)); formats = scaler_->formats(1); - if (formats.empty()) { + if (formats.isEmpty()) { cerr << "Failed to list formats on pad 1 of subdevice " << 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.formats()) + printFormats(1, code, formats.sizes(code)); /* List format on a non-existing pad, format vector shall be empty. */ formats = scaler_->formats(2); - if (!formats.empty()) { + if (!formats.isEmpty()) { cerr << "Listing formats on non-existing pad 2 of subdevice " << scaler_->entity()->name() << " should return an empty format list" << endl; From patchwork Wed Jun 19 02:51:22 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: 1459 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2864861A26 for ; Wed, 19 Jun 2019 04:52:29 +0200 (CEST) X-Halon-ID: 3e849a76-923d-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 3e849a76-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:15 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:22 +0200 Message-Id: <20190619025129.21164-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 09/16] 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: Wed, 19 Jun 2019 02:52:29 -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 Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- * Changes since v3 - Catch the error from V4L2Device::enumSizes() in V4L2Device::formats() - s/pixelformats/pixel formats/ --- src/libcamera/include/v4l2_device.h | 5 ++ src/libcamera/v4l2_device.cpp | 114 ++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/libcamera/include/v4l2_device.h b/src/libcamera/include/v4l2_device.h index bdecc087fe5afae0..1a67850ac4c1088f 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 { @@ -132,6 +133,7 @@ public: int getFormat(V4L2DeviceFormat *format); int setFormat(V4L2DeviceFormat *format); + ImageFormats formats(); int exportBuffers(BufferPool *pool); int importBuffers(BufferPool *pool); @@ -163,6 +165,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 0821bd75fb428766..e14fc6109a4db470 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -634,6 +634,33 @@ int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *format) return 0; } +/** + * \brief Enumerate all pixel formats and frame sizes + * + * Enumerate all pixel formats and frame sizes supported by the video device. + * + * \return A list of the supported device formats + */ +ImageFormats V4L2Device::formats() +{ + ImageFormats formats; + + for (unsigned int pixelformat : enumPixelformats()) { + std::vector sizes = enumSizes(pixelformat); + if (sizes.empty()) + return {}; + + if (formats.addFormat(pixelformat, sizes)) { + LOG(V4L2, Error) + << "Could not add sizes for pixel format " + << pixelformat; + return {}; + } + } + + return formats; +} + int V4L2Device::requestBuffers(unsigned int count) { struct v4l2_requestbuffers rb = {}; @@ -763,6 +790,93 @@ int V4L2Device::createPlane(Buffer *buffer, unsigned int planeIndex, return 0; } +std::vector V4L2Device::enumPixelformats() +{ + std::vector formats; + int ret; + + for (unsigned int index = 0; ; index++) { + struct v4l2_fmtdesc pixelformatEnum = {}; + pixelformatEnum.index = index; + pixelformatEnum.type = bufferType_; + + ret = ioctl(fd_, VIDIOC_ENUM_FMT, &pixelformatEnum); + if (ret) + break; + + formats.push_back(pixelformatEnum.pixelformat); + } + + if (ret && errno != EINVAL) { + ret = -errno; + LOG(V4L2, Error) + << "Unable to enumerate pixel formats: " + << strerror(-ret); + return {}; + } + + return formats; +} + +std::vector V4L2Device::enumSizes(unsigned int pixelFormat) +{ + std::vector sizes; + int ret; + + for (unsigned int index = 0;; index++) { + struct v4l2_frmsizeenum frameSize = {}; + frameSize.index = index; + frameSize.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) + << "Non-zero index for non 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) + << "Unknown 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 * \param[in] pool BufferPool of buffers to import From patchwork Wed Jun 19 02:51:23 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: 1460 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EC0B261A65 for ; Wed, 19 Jun 2019 04:52:29 +0200 (CEST) X-Halon-ID: 3ee5f911-923d-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 3ee5f911-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:15 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:23 +0200 Message-Id: <20190619025129.21164-11-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 10/16] 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: Wed, 19 Jun 2019 02:52:30 -0000 Add a StreamFormats class which describes all the formats supported by a stream. The object does not collect any information itself but can simplify user interactions with formats as it's able to translate a stream format range into a discrete list and a discrete list to a range. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- * Changes since v3 - Fix spelling and grammar. - Add \todo markers for potential caching of calculated values. - Change std::vector<> to std::array<> for list of sizes in sizes(). --- include/libcamera/stream.h | 16 +++ src/libcamera/stream.cpp | 230 +++++++++++++++++++++++++++++++++++++ 2 files changed, 246 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 0c59a31a3a0501d3..bfb072d691ae0e25 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -7,9 +7,13 @@ #include +#include +#include #include #include +#include "log.h" + /** * \file stream.h * \brief Video stream for a Camera @@ -32,6 +36,232 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(Stream) + +/** + * \class StreamFormats + * \brief Hold information about supported stream formats + * + * The StreamFormats class holds information about the 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. The range description can include + * horizontal and vertical steps. + * + * When sizes are viewed as a list of discrete sizes they describe the 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 translate between the two different ways to view them. The translations + * are performed as: + * + * - If the StreamFormat is constructed using a list of discrete image sizes + * and a range is requested, it gets created by taking the minimum and + * maximum width/height in the list. The step information is not recreated + * and is set to 0 to indicate the range is generated. + * + * - If the image sizes used to construct a StreamFormat are expressed as a + * range and a list of discrete sizes is requested, one which fits inside + * that range are selected from a list of common sizes. The step information + * is taken into consideration when generating the sizes. + * + * Applications examining sizes as a range with step values of 0 shall be + * aware that the range are generated from a list of discrete sizes and there + * could be a large number of possible Size combinations that may not be + * supported by the Stream. + * + * All sizes retrieved from StreamFormats shall be treated as advisory and no + * size shall be considered to be supported until it has been verified using + * CameraConfiguration::validate(). + */ + +StreamFormats::StreamFormats() +{ +} + +/** + * \brief Construct a StreamFormats object with a map of image formats + * \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 supported pixel formats + * \return The list of supported pixel formats + */ +std::vector StreamFormats::pixelformats() const +{ + std::vector formats; + + /* \todo: Should this be cached instead of computed each time? */ + for (auto const &it : formats_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve the list of frame sizes supported for \a pixelformat + * \param[in] pixelformat Pixel format to retrieve sizes for + * + * If the sizes described for \a pixelformat are discrete they are returned + * directly. + * + * If the sizes are described as a range, a list of discrete sizes are computed + * from a list of common resolutions that fit inside the described range. When + * computing the discrete list step values are considered but there are no + * guarantees that all sizes computed are supported. + * + * \todo: Should the sizes be cached instead of computed each time? + * + * \return A list of frame sizes or an empty list on error + */ +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::array 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 creating a 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); + } + + /* 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 (limit.contains(size)) + sizes.push_back(size); + } + + std::sort(sizes.begin(), sizes.end()); + + return sizes; +} + +/** + * \brief Retrieve the range of minimum and maximum sizes + * \param[in] pixelformat Pixel format to retrieve range for + * + * If the size described for \a pixelformat is a range, that range is returned + * directly. If the sizes described are a list of discrete sizes, a range is + * created from the minimum and maximum sizes in the list. The step values of + * the range are set to 0 to indicate that the range is generated and that not + * all image sizes contained in the range might be supported. + * + * \return A range of valid image sizes or an empty range on error + */ +SizeRange StreamFormats::range(unsigned int pixelformat) const +{ + auto const it = formats_.find(pixelformat); + if (it == formats_.end()) + return {}; + + const std::vector &ranges = it->second; + if (ranges.size() == 1) + return ranges[0]; + + LOG(Stream, Debug) << "Building range from discrete sizes"; + SizeRange range(UINT_MAX, UINT_MAX, 0, 0); + for (const SizeRange &limit : ranges) { + if (limit.min < range.min) + range.min = limit.min; + + if (limit.max > range.max) + range.max = limit.max; + } + + range.hStep = 0; + range.vStep = 0; + + return range; +} + /** * \struct StreamConfiguration * \brief Configuration parameters for a stream From patchwork Wed Jun 19 02:51:24 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: 1461 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 B611261A2C for ; Wed, 19 Jun 2019 04:52:30 +0200 (CEST) X-Halon-ID: 3f65d020-923d-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 3f65d020-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:17 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:24 +0200 Message-Id: <20190619025129.21164-12-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 11/16] 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: Wed, 19 Jun 2019 02:52:30 -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 Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- include/libcamera/stream.h | 8 ++++---- src/libcamera/stream.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 29 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 bfb072d691ae0e25..cfa7a327fdd0f1a8 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -270,6 +270,19 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * configured for a single video stream. */ +StreamConfiguration::StreamConfiguration() + : stream_(nullptr) +{ +} + +/** + * \brief Construct a configuration with stream formats + */ +StreamConfiguration::StreamConfiguration(const StreamFormats &formats) + : stream_(nullptr), formats_(formats) +{ +} + /** * \var StreamConfiguration::size * \brief Stream size in pixels @@ -310,6 +323,18 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * \param[in] stream The stream */ +/** + * \fn StreamConfiguration::formats() + * \brief Retrieve advisory stream format information + * + * This method retrieves information about the pixel formats and sizes supported + * by the stream configuration. The sizes are advisory and not all of them are + * guaranteed to be supported by the stream. Users shall always inspect the size + * in the stream configuration after calling CameraConfiguration::validate(). + * + * \return Stream formats information + */ + /** * \brief Assemble and return a string describing the configuration * From patchwork Wed Jun 19 02:51:25 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: 1462 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 66F9861A2C for ; Wed, 19 Jun 2019 04:52:31 +0200 (CEST) X-Halon-ID: 3fd4f63b-923d-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 3fd4f63b-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:17 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:25 +0200 Message-Id: <20190619025129.21164-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 12/16] 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: Wed, 19 Jun 2019 02:52:31 -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 updated 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 | 101 +++++++++++++++++++++++++++++++++ 3 files changed, 113 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 25f181c20308583f..654e00890e03efec 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..2f2493de38ae0954 --- /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..a391f5cd087d3872 --- /dev/null +++ b/test/stream/stream_formats.cpp @@ -0,0 +1,101 @@ +/* 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 Wed Jun 19 02:51:26 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: 1463 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 3E98461A56 for ; Wed, 19 Jun 2019 04:52:32 +0200 (CEST) X-Halon-ID: 4055aad5-923d-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 4055aad5-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:18 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:26 +0200 Message-Id: <20190619025129.21164-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 13/16] 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: Wed, 19 Jun 2019 02:52:32 -0000 Most of the camera configuration preparation that 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 cd0afcb9bec2b148..784f58cb2d8758e4 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; } @@ -97,6 +99,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()); @@ -114,6 +120,8 @@ void CamApp::cleanup() camera_.reset(); } + config_.reset(); + cm_->stop(); } @@ -175,6 +183,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)) { @@ -188,7 +259,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 Wed Jun 19 02:51: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: 1464 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 0946B61A31 for ; Wed, 19 Jun 2019 04:52:33 +0200 (CEST) X-Halon-ID: 40cf6add-923d-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 40cf6add-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:19 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:27 +0200 Message-Id: <20190619025129.21164-15-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 14/16] 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: Wed, 19 Jun 2019 02:52:33 -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 784f58cb2d8758e4..4e9abf666fedf211 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -243,6 +243,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 Wed Jun 19 02:51: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: 1465 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 CB9A161A31 for ; Wed, 19 Jun 2019 04:52:33 +0200 (CEST) X-Halon-ID: 41478f34-923d-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 41478f34-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:28 +0200 Message-Id: <20190619025129.21164-16-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 15/16] 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: Wed, 19 Jun 2019 02:52:34 -0000 Add a new option to the cam tool that prints information about the configuration supplied by the user. If the option is specified, information about the configuration is printed after the configuration has been verified and possibly adjusted by the camera. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/cam/main.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ src/cam/main.h | 1 + 2 files changed, 43 insertions(+) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 4e9abf666fedf211..77bb20e9622ec857 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -5,6 +5,7 @@ * main.cpp - cam - The libcamera swiss army knife */ +#include #include #include #include @@ -34,6 +35,7 @@ public: private: int parseOptions(int argc, char *argv[]); int prepareConfig(); + int infoConfiguration(); int run(); static CamApp *app_; @@ -169,6 +171,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); @@ -258,8 +262,40 @@ int CamApp::prepareConfig() return 0; } +int CamApp::infoConfiguration() +{ + if (!config_) { + std::cout << "Cannot print stream information without a camera" + << std::endl; + return -EINVAL; + } + + 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; +} + int CamApp::run() { + int ret; + if (options_.isSet(OptList)) { std::cout << "Available cameras:" << std::endl; @@ -270,6 +306,12 @@ int CamApp::run() } } + if (options_.isSet(OptInfo)) { + ret = infoConfiguration(); + if (ret) + return ret; + } + 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..0997476bb335e446 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', }; From patchwork Wed Jun 19 02:51: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: 1466 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 2F87961A31 for ; Wed, 19 Jun 2019 04:52:34 +0200 (CEST) X-Halon-ID: 41a3af63-923d-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 41a3af63-923d-11e9-8ab4-005056917a89; Wed, 19 Jun 2019 04:52:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 19 Jun 2019 04:51:29 +0200 Message-Id: <20190619025129.21164-17-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> References: <20190619025129.21164-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v4 16/16] 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: Wed, 19 Jun 2019 02:52:34 -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 Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/libcamera/pipeline/uvcvideo.cpp | 41 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 45260f34c8f5daba..7ca9d0eefe8223e8 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -5,6 +5,8 @@ * uvcvideo.cpp - Pipeline handler for uvcvideo devices */ +#include + #include #include #include @@ -95,18 +97,33 @@ CameraConfiguration::Status UVCCameraConfiguration::validate() } StreamConfiguration &cfg = config_[0]; - - /* \todo: Validate the configuration against the device capabilities. */ + const StreamFormats &formats = cfg.formats(); const unsigned int pixelFormat = cfg.pixelFormat; const Size size = cfg.size; - cfg.pixelFormat = V4L2_PIX_FMT_YUYV; - cfg.size = { 640, 480 }; + const std::vector pixelFormats = formats.pixelformats(); + auto iter = std::find(pixelFormats.begin(), pixelFormats.end(), pixelFormat); + if (iter == pixelFormats.end()) { + cfg.pixelFormat = pixelFormats.front(); + LOG(UVC, Debug) + << "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) + break; + + cfg.size = formatsSize; + } - if (cfg.pixelFormat != pixelFormat || cfg.size != size) { + if (cfg.size != size) { LOG(UVC, Debug) - << "Adjusting configuration from " << cfg.toString() - << " to " << cfg.size.toString() << "-YUYV"; + << "Adjusting size from " << size.toString() + << " to " << cfg.size.toString(); status = Adjusted; } @@ -123,14 +140,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 }; + ImageFormats 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);