From patchwork Wed Jun 12 00:43:44 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: 1397 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 1702261F6D for ; Wed, 12 Jun 2019 02:44:54 +0200 (CEST) X-Halon-ID: 34396a09-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 34396a09-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:16 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:44 +0200 Message-Id: <20190612004359.15772-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:54 -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 12 00:43:45 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: 1398 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 8C3D161F83 for ; Wed, 12 Jun 2019 02:44:54 +0200 (CEST) X-Halon-ID: 34d571ee-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 34d571ee-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:16 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:45 +0200 Message-Id: <20190612004359.15772-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:54 -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 --- include/libcamera/geometry.h | 13 +++++++++-- src/libcamera/geometry.cpp | 44 +++++++++++++++++++++++++++++++++--- 2 files changed, 52 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..c56c4e399ef307f5 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -186,9 +186,24 @@ 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. + * 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 describe a vertical and horizontal step. The step + * describes the value in pixels the width/height size can be incremented with, + * starting from the minimum size. + * + * width = min.width + hStep * x + * height = min.height + vStep * y + * + * Where: + * + * width <= max.width + * height < max.height + * + * For SizeRanges describing a single size the incremental step values are fixed + * to 1. */ /** @@ -213,6 +228,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 +251,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 12 00:43:46 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: 1399 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 1011161F83 for ; Wed, 12 Jun 2019 02:44:55 +0200 (CEST) X-Halon-ID: 35356679-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 35356679-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:17 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:46 +0200 Message-Id: <20190612004359.15772-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:55 -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 | 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 c56c4e399ef307f5..6a1d1d78870b23ec 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -261,6 +261,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 12 00:43:47 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: 1400 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 8E7D961F6D for ; Wed, 12 Jun 2019 02:44:56 +0200 (CEST) X-Halon-ID: 357e6b64-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 357e6b64-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:18 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:47 +0200 Message-Id: <20190612004359.15772-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:56 -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: Jacopo Mondi --- include/libcamera/geometry.h | 2 ++ src/libcamera/geometry.cpp | 17 +++++++++++++++++ 2 files changed, 19 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 6a1d1d78870b23ec..a4d472d9fce2e226 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -107,6 +107,7 @@ bool operator==(const Rectangle &lhs, const Rectangle &rhs) * \brief The Size height */ + /** * \brief Assemble and return a string describing the size * \return A string describing the size @@ -261,6 +262,22 @@ bool operator<(const Size &lhs, const Size &rhs) * \brief The vertical step */ +/** + * \brief Test if a size can be contained in the range + * \param[in] size Size to check + * \returns True if \a size can be contained + */ +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 12 00:43:48 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: 1401 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 C706A61F72 for ; Wed, 12 Jun 2019 02:44:56 +0200 (CEST) X-Halon-ID: 35ddf7ca-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 35ddf7ca-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:18 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:48 +0200 Message-Id: <20190612004359.15772-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:57 -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 --- src/libcamera/formats.cpp | 83 +++++++++++++++++++++++++++++++++ src/libcamera/include/formats.h | 17 +++++++ 2 files changed, 100 insertions(+) diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index 56f4ddb51ffad4d3..ab4bae0a5928d9ba 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -24,4 +24,87 @@ namespace libcamera { * resolutions represented by SizeRange items. */ +/** + * \class ImageFormats + * \brief Describe V4L2Device and V4L2SubDevice image formats + * + * The class describes information about image formats and supported sizes. If + * the ImageFormat describe a V4L2Device the formats described are pixel formats + * while if it describes a V4L2SubDevice the formats are media bus codes. + */ + +ImageFormats::ImageFormats() +{ +} + +/** + * \brief Add a format and sizes to the description + * \param[in] format Pixel format or media bus code to describe + * \param[in] sizes List of supported sizes for the format + * + * \return 0 on success or a negative error code otherwise + * \retval -EBUSY The format is already described + */ +int ImageFormats::addFormat(unsigned int format, const std::vector &sizes) +{ + if (data_.find(format) != data_.end()) + return -EBUSY; + + data_[format] = sizes; + + return 0; +} + +/** + * \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()); + + for (auto const &it : data_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve all sizes for a specific format + * \param[in] format A pixelformat or mbus code + * + * Retrieve all SizeRanges for a specific format. For V4L2Device \a format is a + * pixel format while for a V4L2Subdevice \a format is a media bus code. + * + * \return he list of image sizes produced using \a format, or an empty list if + * format is not supported + */ +std::vector ImageFormats::sizes(unsigned int format) const +{ + auto const &it = data_.find(format); + if (it == data_.end()) + return {}; + + return it->second; +} + +/** + * \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 the map that associates formats to image sizes + * \return 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..a31aa42bcb4742ac 100644 --- a/src/libcamera/include/formats.h +++ b/src/libcamera/include/formats.h @@ -17,6 +17,23 @@ namespace libcamera { typedef std::map> FormatEnum; +class ImageFormats +{ +public: + ImageFormats(); + + int addFormat(unsigned int format, const std::vector &sizes); + + std::vector formats() const; + std::vector sizes(unsigned int format) const; + + bool isEmpty() const; + const std::map> &data() const; + +private: + std::map> data_; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_FORMATS_H__ */ From patchwork Wed Jun 12 00:43:49 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: 1402 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 37BE661F72 for ; Wed, 12 Jun 2019 02:44:57 +0200 (CEST) X-Halon-ID: 3674edd3-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 3674edd3-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:19 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:49 +0200 Message-Id: <20190612004359.15772-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:57 -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 --- 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 12 00:43:50 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: 1404 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 EE26961F83 for ; Wed, 12 Jun 2019 02:44:58 +0200 (CEST) X-Halon-ID: 36c31c6d-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 36c31c6d-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:50 +0200 Message-Id: <20190612004359.15772-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:59 -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 --- src/libcamera/include/v4l2_subdevice.h | 4 +-- src/libcamera/v4l2_subdevice.cpp | 37 ++++++++++++++------------ 2 files changed, 22 insertions(+), 19 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..35052b4aa45d3e42 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -209,10 +209,15 @@ 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 +340,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, + sizes.emplace_back(sizeEnum.min_width, sizeEnum.min_height, sizeEnum.max_width, sizeEnum.max_height); - - sizeEnum.index++; } if (ret && (errno != EINVAL && errno != ENOTTY)) { @@ -361,12 +366,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 12 00:43:51 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: 1403 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 B043661F6D for ; Wed, 12 Jun 2019 02:44:58 +0200 (CEST) X-Halon-ID: 37289c28-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 37289c28-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:51 +0200 Message-Id: <20190612004359.15772-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:59 -0000 Replace all usage of FormatEnum with ImageFormats and completely remove FormatEnum which is no longer needed. Signed-off-by: Niklas Söderlund --- 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 ab4bae0a5928d9ba..da485a1bafeb8bae 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 a31aa42bcb4742ac..dc0c01bd9173643a 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 35052b4aa45d3e42..e109a00bcd3bdd46 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; @@ -215,10 +210,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 12 00:43:52 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: 1405 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1B44561F88 for ; Wed, 12 Jun 2019 02:44:59 +0200 (CEST) X-Halon-ID: 379ccc70-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 379ccc70-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:21 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:52 +0200 Message-Id: <20190612004359.15772-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:44:59 -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 --- src/libcamera/include/v4l2_device.h | 5 ++ src/libcamera/v4l2_device.cpp | 110 ++++++++++++++++++++++++++++ 2 files changed, 115 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..202680d8632a4dd1 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -634,6 +634,29 @@ int V4L2Device::setFormatSingleplane(V4L2DeviceFormat *format) return 0; } +/** + * \brief Enumerate all pixelformats and frame sizes + * + * Enumerate all pixelformats 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()) { + if (formats.addFormat(pixelformat, enumSizes(pixelformat))) { + 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 +786,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 pixelformats: " + << 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 12 00:43:53 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: 1406 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9C23D61FAF for ; Wed, 12 Jun 2019 02:45:00 +0200 (CEST) X-Halon-ID: 37efd401-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 37efd401-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:22 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:53 +0200 Message-Id: <20190612004359.15772-11-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:00 -0000 Add a StreamFormats class which describes all the formats a stream can support. The object does not collect any formation itself but can simplify user interactions 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 Reviewed-by: Jacopo Mondi --- include/libcamera/stream.h | 16 +++ src/libcamera/stream.cpp | 228 +++++++++++++++++++++++++++++++++++++ 2 files changed, 244 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..52340c2644aac8d8 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,230 @@ 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. There is a possibility to supplement the + * range description with a horizontal and vertical step. The step describes the + * size in pixels from the minimum with/height. + * + * When sizes are viewed as a list of discrete sizes they describe 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 a pixel format is described as a list of discrete sizes then a range is + * 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 it is + * generated. + * + * - If a pixel format is described as a range then a list of discrete sizes + * 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 quantity of possible Size combinations which 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 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 supported pixel formats + * \returns The list of supported 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 + * + * If the sizes described for \a pixelformat are discrete they are returned + * directly. If the size described is a range a list of discrete sizes are + * computed from a set list of common resolutions which fits inside the + * described range. When computing the discrete list step values are considered + * but there are no guarantees that all sizes computed are supported. + * + * \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 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 frame size range + * \param[in] pixelformat Pixel format to retrieve range for + * + * If the size described for \a pixelformat is a range the range is returned + * directly. If the sizes described are a list of discrete sizes a range is + * computed from the minimum and maxim sizes in the list. The step values of + * a computed range is set to 0 to indicate that the range is generated and + * that the full range may not supported. + * + * \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 std::vector &ranges = it->second; + if (ranges.size() == 1) + return ranges[0]; + + LOG(Stream, Debug) << "Building range from discrete"; + 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 12 00:43:54 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: 1407 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 25A5961FAF for ; Wed, 12 Jun 2019 02:45:01 +0200 (CEST) X-Halon-ID: 38c85b80-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 38c85b80-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:23 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:54 +0200 Message-Id: <20190612004359.15772-12-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:01 -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 --- 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 52340c2644aac8d8..254a5e10db24287d 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -268,6 +268,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 @@ -308,6 +321,18 @@ SizeRange StreamFormats::range(unsigned int pixelformat) const * \param[in] stream The stream */ +/** + * \fn StreamConfiguration::formats() + * \brief Retrieve advisory stream format information + * + * Retrieve information about pixel formats and sizes for possible stream + * configuration. The size information is advisory and not guaranteed to + * be fully satisfied by the hardware, users should always inspect the actual + * size used by the device after a camera have been configured. + * + * \return Stream formats information + */ + /** * \brief Assemble and return a string describing the configuration * From patchwork Wed Jun 12 00:43:55 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: 1408 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 EAFA262EC4 for ; Wed, 12 Jun 2019 02:45:02 +0200 (CEST) X-Halon-ID: 3927915a-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 3927915a-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:24 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:55 +0200 Message-Id: <20190612004359.15772-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:03 -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 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..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 12 00:43:56 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: 1409 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 D843461FB7 for ; Wed, 12 Jun 2019 02:45:04 +0200 (CEST) X-Halon-ID: 39bb26c8-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 39bb26c8-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:26 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:56 +0200 Message-Id: <20190612004359.15772-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:05 -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 f03a9faf87fac865..c9ae22df5f9f123b 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 Wed Jun 12 00:43:57 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: 1410 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6891661FB7 for ; Wed, 12 Jun 2019 02:45:05 +0200 (CEST) X-Halon-ID: 3b1b2b01-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 3b1b2b01-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:27 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:57 +0200 Message-Id: <20190612004359.15772-15-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:05 -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 c9ae22df5f9f123b..191fef3a3c8a2b64 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 Wed Jun 12 00:43:58 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: 1411 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 7FF3961FBB for ; Wed, 12 Jun 2019 02:45:06 +0200 (CEST) X-Halon-ID: 3ba66762-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 3ba66762-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:28 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:58 +0200 Message-Id: <20190612004359.15772-16-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:06 -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 possibly adjusted by the camera. Signed-off-by: Niklas Söderlund --- src/cam/info.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/cam/info.h | 14 ++++++++++++++ src/cam/main.cpp | 6 ++++++ src/cam/main.h | 1 + src/cam/meson.build | 1 + 5 files changed, 59 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..fe32ceb614e85794 --- /dev/null +++ b/src/cam/info.cpp @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * info.cpp - Display stream information + */ + +#include +#include + +#include "info.h" + +using namespace libcamera; + +int infoConfiguration(const libcamera::CameraConfiguration &config) +{ + 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..d4b4fc7e73d261b6 --- /dev/null +++ b/src/cam/info.h @@ -0,0 +1,14 @@ +/* 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 + +int infoConfiguration(const libcamera::CameraConfiguration &config); + +#endif /* __CAM_INFO_H__ */ diff --git a/src/cam/main.cpp b/src/cam/main.cpp index 191fef3a3c8a2b64..c0a5601316d1959d 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,9 @@ int CamApp::run() std::cout << "- " << cam->name() << std::endl; } + if (options_.isSet(OptInfo)) + infoConfiguration(*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..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', }; 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 Wed Jun 12 00:43:59 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: 1412 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 0DBDF61F6D for ; Wed, 12 Jun 2019 02:45:08 +0200 (CEST) X-Halon-ID: 3c57258a-8cab-11e9-8601-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (unknown [89.233.230.99]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 3c57258a-8cab-11e9-8601-0050569116f7; Wed, 12 Jun 2019 02:44:29 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Wed, 12 Jun 2019 02:43:59 +0200 Message-Id: <20190612004359.15772-17-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> References: <20190612004359.15772-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 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, 12 Jun 2019 00:45:08 -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 --- 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);