From patchwork Sun Jun 16 13:33: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: 1433 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 645B56477E for ; Sun, 16 Jun 2019 15:35:32 +0200 (CEST) X-Halon-ID: 9549f39e-903b-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 9549f39e-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:19 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:47 +0200 Message-Id: <20190616133402.21934-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:32 -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 Sun Jun 16 13:33: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: 1432 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 5D5CC6475D for ; Sun, 16 Jun 2019 15:35:32 +0200 (CEST) X-Halon-ID: 959b668a-903b-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 959b668a-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:48 +0200 Message-Id: <20190616133402.21934-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:32 -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 | 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..dfc264b2700f7f61 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 gets incremented by, + * starting from the minimum size. + * + * width = min.width + hStep * x + * height = min.height + vStep * y + * + * Where: + * + * width <= max.width + * height < max.height + * + * For SizeRange instances 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 Sun Jun 16 13:33: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: 1434 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1885A6475D for ; Sun, 16 Jun 2019 15:35:33 +0200 (CEST) X-Halon-ID: 95fef8e5-903b-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 95fef8e5-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:20 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:49 +0200 Message-Id: <20190616133402.21934-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:33 -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 dfc264b2700f7f61..895861eb0678181b 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 Sun Jun 16 13:33: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: 1435 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 721B464785 for ; Sun, 16 Jun 2019 15:35:33 +0200 (CEST) X-Halon-ID: 9662028c-903b-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 9662028c-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:21 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:50 +0200 Message-Id: <20190616133402.21934-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:34 -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 895861eb0678181b..ef919cb6beb19864 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -261,6 +261,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 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 Sun Jun 16 13:33: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: 1436 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EBD3F6477F for ; Sun, 16 Jun 2019 15:35:34 +0200 (CEST) X-Halon-ID: 96a85828-903b-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 96a85828-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:21 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:51 +0200 Message-Id: <20190616133402.21934-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:35 -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 | 80 +++++++++++++++++++++++++++++++++ src/libcamera/include/formats.h | 14 ++++++ 2 files changed, 94 insertions(+) diff --git a/src/libcamera/formats.cpp b/src/libcamera/formats.cpp index 56f4ddb51ffad4d3..2fd0c5480324ce33 100644 --- a/src/libcamera/formats.cpp +++ b/src/libcamera/formats.cpp @@ -24,4 +24,84 @@ 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 image formats are described with a + * fourcc pixel format code, while if it describes a V4L2SubDevice the formats + * are described with media bus codes, both defined by the V4L2 specification. + */ + +/** + * \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 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()); + + 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 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..a49f83f3d8d60621 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; + std::vector sizes(unsigned int format) const; + const std::map> &data() const; + +private: + std::map> data_; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_FORMATS_H__ */ From patchwork Sun Jun 16 13:33: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: 1437 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 EB8666475D for ; Sun, 16 Jun 2019 15:35:34 +0200 (CEST) X-Halon-ID: 970bbf98-903b-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 970bbf98-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:22 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:52 +0200 Message-Id: <20190616133402.21934-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:35 -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 Sun Jun 16 13:33: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: 1438 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9755A64793 for ; Sun, 16 Jun 2019 15:35:36 +0200 (CEST) X-Halon-ID: 9778db02-903b-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 9778db02-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:23 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:53 +0200 Message-Id: <20190616133402.21934-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:37 -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 | 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 Sun Jun 16 13:33: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: 1439 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 0B2F964784 for ; Sun, 16 Jun 2019 15:35:37 +0200 (CEST) X-Halon-ID: 9819b4ee-903b-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 9819b4ee-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:24 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:54 +0200 Message-Id: <20190616133402.21934-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:37 -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 2fd0c5480324ce33..0d196ee3a83e9c0d 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 a49f83f3d8d60621..de63ba557e045585 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 Sun Jun 16 13:33: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: 1440 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 89D876477F for ; Sun, 16 Jun 2019 15:35:38 +0200 (CEST) X-Halon-ID: 98bdceb9-903b-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 98bdceb9-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:25 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:55 +0200 Message-Id: <20190616133402.21934-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:39 -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 --- 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..96aa525025629697 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 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()) { + 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 Sun Jun 16 13:33: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: 1441 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 80C9D6475A for ; Sun, 16 Jun 2019 15:35:39 +0200 (CEST) X-Halon-ID: 995bc1cf-903b-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 995bc1cf-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:26 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:56 +0200 Message-Id: <20190616133402.21934-11-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:39 -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 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 | 226 +++++++++++++++++++++++++++++++++++++ 2 files changed, 242 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..27fde5fe29eeb340 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,228 @@ 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 starting from the minimum with/height. + * + * 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 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(). + */ + +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; + + for (auto const &it : formats_) + formats.push_back(it.first); + + return formats; +} + +/** + * \brief Retrieve the list of frame sizes supported by \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 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. + * + * \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::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 range of minimum and maximu 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 + * 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 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"; + 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 Sun Jun 16 13:33: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: 1442 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 D71CE64781 for ; Sun, 16 Jun 2019 15:35:39 +0200 (CEST) X-Halon-ID: 9a1f3d46-903b-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 9a1f3d46-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:27 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:57 +0200 Message-Id: <20190616133402.21934-12-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:40 -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 27fde5fe29eeb340..a0d77348d418917a 100644 --- a/src/libcamera/stream.cpp +++ b/src/libcamera/stream.cpp @@ -266,6 +266,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 @@ -306,6 +319,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 supported by the hardware, users should always inspect the actual + * size applied on the device after a camera has been configured. + * + * \return Stream formats information + */ + /** * \brief Assemble and return a string describing the configuration * From patchwork Sun Jun 16 13:33: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: 1443 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 F0A5A6478E for ; Sun, 16 Jun 2019 15:35:40 +0200 (CEST) X-Halon-ID: 9a7a73e6-903b-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 9a7a73e6-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:28 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:58 +0200 Message-Id: <20190616133402.21934-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:41 -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 Sun Jun 16 13:33: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: 1444 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 71E3964789 for ; Sun, 16 Jun 2019 15:35:41 +0200 (CEST) X-Halon-ID: 9ae935d7-903b-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 9ae935d7-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:29 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:33:59 +0200 Message-Id: <20190616133402.21934-14-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:41 -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 Sun Jun 16 13:34:00 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: 1445 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 55B0B6478C for ; Sun, 16 Jun 2019 15:35:42 +0200 (CEST) X-Halon-ID: 9b73c17a-903b-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 9b73c17a-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:30 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:34:00 +0200 Message-Id: <20190616133402.21934-15-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:42 -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 Sun Jun 16 13:34:01 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: 1446 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 AD56A6478C for ; Sun, 16 Jun 2019 15:35:42 +0200 (CEST) X-Halon-ID: 9bc9a9ef-903b-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 9bc9a9ef-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:30 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:34:01 +0200 Message-Id: <20190616133402.21934-16-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:43 -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 Reviewed-by: Laurent Pinchart --- src/cam/info.cpp | 37 +++++++++++++++++++++++++++++++++++++ src/cam/info.h | 14 ++++++++++++++ src/cam/main.cpp | 13 +++++++++++++ src/cam/main.h | 1 + src/cam/meson.build | 1 + 5 files changed, 66 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..65e31497e5cac358 --- /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 - Display 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..7c68cb290d597430 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,16 @@ int CamApp::run() std::cout << "- " << cam->name() << std::endl; } + if (options_.isSet(OptInfo)) { + if (!config_.get()) { + std::cout << "Can't print information without a camera" + << std::endl; + return -ENODEV; + } + + 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 Sun Jun 16 13:34:02 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: 1447 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 351D164780 for ; Sun, 16 Jun 2019 15:35:44 +0200 (CEST) X-Halon-ID: 9c2935e2-903b-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 9c2935e2-903b-11e9-8ab4-005056917a89; Sun, 16 Jun 2019 15:35:31 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 16 Jun 2019 15:34:02 +0200 Message-Id: <20190616133402.21934-17-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> References: <20190616133402.21934-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Sun, 16 Jun 2019 13:35:44 -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);