From patchwork Tue Apr 16 22:08:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1010 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 28AF460DB4 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AE1722BA for ; Wed, 17 Apr 2019 00:08:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452531; bh=CUFVZNQfO/UhAvK/sOaxcRFRjHhHPh/vTLL5eIBCHc0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=JQXA8ml4olxISKVLRHpkSQAgAMHQFtRCyB9DQu5lzXhq1+LSIJy7XYVH/N5Vs8n2m mjYwTcIKCcvmg84BMYh7+WrsQFfx/1aSUESBYZUVDEWX3iJgt3K9zAbfQezu4D9ZUe GvRP6xJ/Edo0eUIuzSQrNfkaF+VzGj+5NsKlJ750= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:27 +0300 Message-Id: <20190416220839.1577-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/13] Install the cam and qcam utilities 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: Tue, 16 Apr 2019 22:08:52 -0000 The cam and qcam utilities are meant to be shipped with libcamera, install them by default. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/cam/meson.build | 1 + src/qcam/meson.build | 1 + 2 files changed, 2 insertions(+) diff --git a/src/cam/meson.build b/src/cam/meson.build index 1a1244fe25cd..851295091d0d 100644 --- a/src/cam/meson.build +++ b/src/cam/meson.build @@ -7,4 +7,5 @@ cam_sources = files([ cam = executable('cam', cam_sources, link_with : libcamera, + install : true, include_directories : libcamera_includes) diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 3d8b1b3b759d..56b57a266b29 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -16,6 +16,7 @@ qt5_dep = dependency('qt5', if qt5_dep.found() qcam = executable('qcam', qcam_sources, link_with : libcamera, + install : true, include_directories : libcamera_includes, dependencies : qt5_dep, cpp_args : '-DQT_NO_KEYWORDS') From patchwork Tue Apr 16 22:08:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1011 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5EF4C60004 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F375C2D2 for ; Wed, 17 Apr 2019 00:08:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452532; bh=iwgyLW0MWnGp2TxvsW836wfzPZek82oY/7CT1iPNJy8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=oPGiXEKquckO8HknOi7JXF4IY7c82RFKQhdX0mx9OmboOW5p1QEpJ0yP5VtEMUGp6 nW00RL2KxyYh4LbsXQS1qbvXiN3+h5c6vYfD8HKh6mULrf8dX0jeXPYMjpryGIt5TN Hz7QeqU/JPgROcevon4rz2lACUM9Q0zVfXWsAJzc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:28 +0300 Message-Id: <20190416220839.1577-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/13] libcamera: log: Mark Loggable::_log() methods as const 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: Tue, 16 Apr 2019 22:08:52 -0000 The methods don't modify the object instance, mark them as const. This allows using the LOG() macro from a const method of a Loggable object. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/include/log.h | 5 +++-- src/libcamera/log.cpp | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcamera/include/log.h b/src/libcamera/include/log.h index 8ea5a1eb673a..35a6fc105448 100644 --- a/src/libcamera/include/log.h +++ b/src/libcamera/include/log.h @@ -76,9 +76,10 @@ protected: virtual std::string logPrefix() const = 0; LogMessage _log(const char *file, unsigned int line, - LogSeverity severity); + LogSeverity severity) const; LogMessage _log(const char *file, unsigned int line, - const LogCategory &category, LogSeverity severity); + const LogCategory &category, + LogSeverity severity) const; }; LogMessage _log(const char *file, unsigned int line, LogSeverity severity); diff --git a/src/libcamera/log.cpp b/src/libcamera/log.cpp index 71cfbc422ba0..77927ec35b62 100644 --- a/src/libcamera/log.cpp +++ b/src/libcamera/log.cpp @@ -506,7 +506,7 @@ Loggable::~Loggable() * \return A log message */ LogMessage Loggable::_log(const char *fileName, unsigned int line, - LogSeverity severity) + LogSeverity severity) const { LogMessage msg(fileName, line, severity); @@ -527,7 +527,8 @@ LogMessage Loggable::_log(const char *fileName, unsigned int line, * \return A log message */ LogMessage Loggable::_log(const char *fileName, unsigned int line, - const LogCategory &category, LogSeverity severity) + const LogCategory &category, + LogSeverity severity) const { LogMessage msg(fileName, line, category, severity); From patchwork Tue Apr 16 22:08:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1012 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9EC4960004 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 43B32E2 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452532; bh=M3RMGnnhqJpI/UHN0JnapR03W/XkdfDLaBF92Mw1ZQY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aSfu1cXppVEsvL9tda2RyZphI2eEKFAQcnOGhHfASMPpHsDF6yGWYtsWR4XfDNWCt 2zeMO7679tlElhJ7P4HgY5lZ3BEeXsBjSC6fWkGcVTiRR6KC3iI7EbIvpB/hlU2jRn yWSSK4r1qA9RnoWah8o43UTx1UwVuV4fPtQQBVzs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:29 +0300 Message-Id: <20190416220839.1577-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/13] libcamera: camera: Log requested configuration in configureStreams() 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: Tue, 16 Apr 2019 22:08:53 -0000 The IPU3 pipeline handler logs the requested configuration in its configureStreams() handler. This is useful for other pipeline handlers as well, move it to the Camera class. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/camera.cpp | 14 ++++++++++++++ src/libcamera/pipeline/ipu3/ipu3.cpp | 6 ------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index bdf14b31d8ee..55f724a8db17 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -5,6 +5,8 @@ * camera.cpp - Camera device */ +#include + #include #include #include @@ -595,11 +597,23 @@ int Camera::configureStreams(const CameraConfiguration &config) return -EINVAL; } + std::ostringstream msg("configuring streams:"); + unsigned int index = 0; + for (Stream *stream : config) { if (streams_.find(stream) == streams_.end()) return -EINVAL; + + const StreamConfiguration &cfg = config[stream]; + msg << " (" << index << ") " << cfg.width << "x" + << cfg.height << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << cfg.pixelFormat; + + index++; } + LOG(Camera, Info) << msg.str(); + ret = pipe_->configureStreams(this, config); if (ret) return ret; diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ca09da753b90..ff72be14d696 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -242,12 +242,6 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, ImgUDevice *imgu = data->imgu_; int ret; - LOG(IPU3, Info) - << "Requested image format " << cfg.width << "x" - << cfg.height << "-0x" << std::hex << std::setfill('0') - << std::setw(8) << cfg.pixelFormat << " on camera '" - << camera->name() << "'"; - /* * Verify that the requested size respects the IPU3 alignement * requirements (the image width shall be a multiple of 8 pixels and From patchwork Tue Apr 16 22:08:30 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1013 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 00AB460DC5 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 94DFA2BA for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452532; bh=3lLujraMWlCwqB0V7/9cBTs01fxkWVLer8n9Zz6khxA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=hqv2w6Lwp6EjG/BHBrA7EDnDmRZLIlVHqiMkljBxnd1067jF7t4i8j/KffmgTukwI 19+sYObEpdqO1uHvzFVuvrzgu9p6a2XiO3WwGljyvcd+aty43Aso1Vhc9ybR0TwwVU VrpY2hBjFbW4kstFzNorukTgcb/xHrQOHDRPl+3o= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:30 +0300 Message-Id: <20190416220839.1577-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/13] libcamera: geometry: Sort classes alphabetically 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: Tue, 16 Apr 2019 22:08:55 -0000 Move the Size class before the SizeRange class. No functional change. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- include/libcamera/geometry.h | 30 +++++++++---------- src/libcamera/geometry.cpp | 58 ++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index f41017aa47bf..7704ab5add21 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -21,6 +21,21 @@ struct Rectangle { const std::string toString() const; }; +struct Size { + Size() + : Size(0, 0) + { + } + + Size(unsigned int w, unsigned int h) + : width(w), height(h) + { + } + + unsigned int width; + unsigned int height; +}; + struct SizeRange { SizeRange() : SizeRange(0, 0, 0, 0) @@ -40,21 +55,6 @@ struct SizeRange { unsigned int maxHeight; }; -struct Size { - Size() - : Size(0, 0) - { - } - - Size(unsigned int w, unsigned int h) - : width(w), height(h) - { - } - - unsigned int width; - unsigned int height; -}; - } /* namespace libcamera */ #endif /* __LIBCAMERA_GEOMETRY_H__ */ diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index d63eceaf827b..1f875bbe5f48 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -62,6 +62,35 @@ const std::string Rectangle::toString() const return ss.str(); } +/** + * \struct Size + * \brief Describe a two-dimensional size + * + * The Size structure defines a two-dimensional size with integer precision. + */ + +/** + * \fn Size::Size() + * \brief Construct a Size with width and height set to 0 + */ + +/** + * \fn Size::Size(unsigned int width, unsigned int height) + * \brief Construct a Size with given \a width and \a height + * \param width The Size width + * \param height The Size height + */ + +/** + * \var Size::width + * \brief The Size width + */ + +/** + * \var Size::height + * \brief The Size height + */ + /** * \struct SizeRange * \brief Describe a range of image sizes @@ -105,33 +134,4 @@ const std::string Rectangle::toString() const * \brief The maximum image height */ -/** - * \struct Size - * \brief Describe a two-dimensional size - * - * The Size structure defines a two-dimensional size with integer precision. - */ - -/** - * \fn Size::Size() - * \brief Construct a Size with width and height set to 0 - */ - -/** - * \fn Size::Size(unsigned int width, unsigned int height) - * \brief Construct a Size with given \a width and \a height - * \param width The Size width - * \param height The Size height - */ - -/** - * \var Size::width - * \brief The Size width - */ - -/** - * \var Size::height - * \brief The Size height - */ - } /* namespace libcamera */ From patchwork Tue Apr 16 22:08:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1014 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4674360DC3 for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D9506E2 for ; Wed, 17 Apr 2019 00:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452533; bh=LtUpLXwg6GT3gbro5vW9+VO+ATz91tNYTtXBhWViPdw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=WdZ5A+fmyvqmWrJyyq9d2oKLIXcElaShaN6MxgyCWA6U4fTaNmQdAR+dwIMiI4ZeH qdtstJm5TTmNDZOL/mBIaq4yYV1V5krqwBZAnH62wmx5JYBeUchYZuPVg5IpiNEzfN HPGX8LvRjmIjhdhchUgHhC2SRcHKNw7c8CF1jTbA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:31 +0300 Message-Id: <20190416220839.1577-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/13] libcamera: geometry: Use Size to store min and max in SizeRange 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: Tue, 16 Apr 2019 22:08:55 -0000 Instead of storing four integers for the minimum and maximum width and height in the SizeRange class, use two instance of the Size class for the minimum and maximum sizes. While it at replace the mention of image size with size in the SizeRange documentation, as the Size class isn't limited to image sizes. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- include/libcamera/geometry.h | 10 +++------- src/libcamera/geometry.cpp | 26 ++++++++------------------ src/libcamera/pipeline/ipu3/ipu3.cpp | 17 ++++++++--------- test/v4l2_subdevice/list_formats.cpp | 8 ++++---- 4 files changed, 23 insertions(+), 38 deletions(-) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 7704ab5add21..80f79c6ba2d3 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -38,21 +38,17 @@ struct Size { struct SizeRange { SizeRange() - : SizeRange(0, 0, 0, 0) { } SizeRange(unsigned int minW, unsigned int minH, unsigned int maxW, unsigned int maxH) - : minWidth(minW), minHeight(minH), maxWidth(maxW), - maxHeight(maxH) + : min(minW, minH), max(maxW, maxH) { } - unsigned int minWidth; - unsigned int minHeight; - unsigned int maxWidth; - unsigned int maxHeight; + Size min; + Size max; }; } /* namespace libcamera */ diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index 1f875bbe5f48..c1c7daed7259 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -93,11 +93,11 @@ const std::string Rectangle::toString() const /** * \struct SizeRange - * \brief Describe a range of image sizes + * \brief Describe a range of sizes * - * SizeRange describes a range of image sizes included in the (minWidth, - * minHeight) - (maxWidth, maxHeight) interval. If the minimum and - * maximum sizes are identical it represents a single image resolution. + * 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. */ /** @@ -115,23 +115,13 @@ const std::string Rectangle::toString() const */ /** - * \var SizeRange::minWidth - * \brief The minimum image width + * \var SizeRange::min + * \brief The minimum size */ /** - * \var SizeRange::minHeight - * \brief The minimum image height - */ - -/** - * \var SizeRange::maxWidth - * \brief The maximum image width - */ - -/** - * \var SizeRange::maxHeight - * \brief The maximum image height + * \var SizeRange::max + * \brief The maximum size */ } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index ff72be14d696..4ddd1ede1c81 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -1047,10 +1047,9 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) continue; for (const SizeRange &size : it.second) { - if (maxSize_.width < size.maxWidth && - maxSize_.height < size.maxHeight) { - maxSize_.width = size.maxWidth; - maxSize_.height = size.maxHeight; + if (maxSize_.width < size.max.width && + maxSize_.height < size.max.height) { + maxSize_ = size.max; mbusCode_ = mbusCode; } } @@ -1105,19 +1104,19 @@ int CIO2Device::configure(const StreamConfiguration &config, * as possible. This will need to be revisited when * implementing the scaling policy. */ - if (size.maxWidth < config.width || - size.maxHeight < config.height) + if (size.max.width < config.width || + size.max.height < config.height) continue; - unsigned int diff = size.maxWidth * size.maxHeight + unsigned int diff = size.max.width * size.max.height - imageSize; if (diff >= best) continue; best = diff; - sensorFormat.width = size.maxWidth; - sensorFormat.height = size.maxHeight; + sensorFormat.width = size.max.width; + sensorFormat.height = size.max.height; sensorFormat.mbus_code = it.first; } } diff --git a/test/v4l2_subdevice/list_formats.cpp b/test/v4l2_subdevice/list_formats.cpp index 47ae3a1c1a28..09dec9abe854 100644 --- a/test/v4l2_subdevice/list_formats.cpp +++ b/test/v4l2_subdevice/list_formats.cpp @@ -37,10 +37,10 @@ void ListFormatsTest::printFormats(unsigned int pad, for (SizeRange &size : sizes) { cout << " mbus code: 0x" << setfill('0') << setw(4) << hex << code << endl; - cout << " min width: " << dec << size.minWidth << endl; - cout << " min height: " << dec << size.minHeight << endl; - cout << " max width: " << dec << size.maxWidth << endl; - cout << " max height: " << dec << size.maxHeight << endl; + cout << " min width: " << dec << size.min.width << endl; + cout << " min height: " << dec << size.min.height << endl; + cout << " max width: " << dec << size.max.width << endl; + cout << " max height: " << dec << size.max.height << endl; } } From patchwork Tue Apr 16 22:08:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1015 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8DFD060DB4 for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 32A592BA for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452533; bh=5YdKs5SiFvFQkq7ZVXFBkrtwDRPewHOgP5TYywDlDIs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=sjPRhhkDw2IGefj7RYwAh6DydV2bCSFPYKr9bhTF1EsnufHOULhdWDUPlDU4yxzgg u958FE1DBf3aIzmgKIOqYHs6Sn6R3SNwS+FukUxPdNxyaEFymuYVVHTuLPLUTtsDa6 /2LrG5i34z57SCWPll72glEFt3Zy6Aql+GvVC/lE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:32 +0300 Message-Id: <20190416220839.1577-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/13] libcamera: geometry: Add comparison operators to geometry classes 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: Tue, 16 Apr 2019 22:08:55 -0000 Add equality and inequality comparison operators for the Rectangle, Size and SizeRange classes. For the Size class, also add ordering operators. Sizes are first compared on combined width and height, then on area, and finally on width only to achieve a stable ordering. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- Changes since v1: - Replace {left, right} hand size with \a lhs and \a rhs respectively --- include/libcamera/geometry.h | 35 +++++++++++++ src/libcamera/geometry.cpp | 98 ++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/include/libcamera/geometry.h b/include/libcamera/geometry.h index 80f79c6ba2d3..3dbbced5c76f 100644 --- a/include/libcamera/geometry.h +++ b/include/libcamera/geometry.h @@ -21,6 +21,12 @@ struct Rectangle { const std::string toString() const; }; +bool operator==(const Rectangle &lhs, const Rectangle &rhs); +static inline bool operator!=(const Rectangle &lhs, const Rectangle &rhs) +{ + return !(lhs == rhs); +} + struct Size { Size() : Size(0, 0) @@ -36,6 +42,29 @@ struct Size { unsigned int height; }; +bool operator==(const Size &lhs, const Size &rhs); +bool operator<(const Size &lhs, const Size &rhs); + +static inline bool operator!=(const Size &lhs, const Size &rhs) +{ + return !(lhs == rhs); +} + +static inline bool operator<=(const Size &lhs, const Size &rhs) +{ + return lhs < rhs || lhs == rhs; +} + +static inline bool operator>(const Size &lhs, const Size &rhs) +{ + return !(lhs <= rhs); +} + +static inline bool operator>=(const Size &lhs, const Size &rhs) +{ + return !(lhs < rhs); +} + struct SizeRange { SizeRange() { @@ -51,6 +80,12 @@ struct SizeRange { Size max; }; +bool operator==(const SizeRange &lhs, const SizeRange &rhs); +static inline bool operator!=(const SizeRange &lhs, const SizeRange &rhs) +{ + return !(lhs == rhs); +} + } /* namespace libcamera */ #endif /* __LIBCAMERA_GEOMETRY_H__ */ diff --git a/src/libcamera/geometry.cpp b/src/libcamera/geometry.cpp index c1c7daed7259..d14c925aaad2 100644 --- a/src/libcamera/geometry.cpp +++ b/src/libcamera/geometry.cpp @@ -6,6 +6,7 @@ */ #include +#include #include @@ -62,6 +63,22 @@ const std::string Rectangle::toString() const return ss.str(); } +/** + * \brief Compare rectangles for equality + * \return True if the two rectangles are equal, false otherwise + */ +bool operator==(const Rectangle &lhs, const Rectangle &rhs) +{ + return lhs.x == rhs.x && lhs.y == rhs.y && + lhs.w == rhs.w && lhs.h == rhs.h; +} + +/** + * \fn bool operator!=(const Rectangle &lhs, const Rectangle &rhs) + * \brief Compare rectangles for inequality + * \return True if the two rectangles are not equal, false otherwise + */ + /** * \struct Size * \brief Describe a two-dimensional size @@ -91,6 +108,72 @@ const std::string Rectangle::toString() const * \brief The Size height */ +/** + * \brief Compare sizes for equality + * \return True if the two sizes are equal, false otherwise + */ +bool operator==(const Size &lhs, const Size &rhs) +{ + return lhs.width == rhs.width && lhs.height == rhs.height; +} + +/** + * \brief Compare sizes for smaller than order + * + * Sizes are compared on three criteria, in the following order. + * + * - A size with smaller width and smaller height is smaller. + * - A size with smaller area is smaller. + * - A size with smaller width is smaller. + * + * \return True if \a lhs is smaller than \a rhs, false otherwise + */ +bool operator<(const Size &lhs, const Size &rhs) +{ + if (lhs.width < rhs.width && lhs.height < rhs.height) + return true; + else if (lhs.width >= rhs.width && lhs.height >= rhs.height) + return false; + + uint64_t larea = static_cast(lhs.width) * + static_cast(lhs.height); + uint64_t rarea = static_cast(rhs.width) * + static_cast(rhs.height); + if (larea < rarea) + return true; + else if (larea > rarea) + return false; + + return lhs.width < rhs.width; +} + +/** + * \fn bool operator!=(const Size &lhs, const Size &rhs) + * \brief Compare sizes for inequality + * \return True if the two sizes are not equal, false otherwise + */ + +/** + * \fn bool operator<=(const Size &lhs, const Size &rhs) + * \brief Compare sizes for smaller than or equal to order + * \return True if \a lhs is smaller than or equal to \a rhs, false otherwise + * \sa bool operator<(const Size &lhs, const Size &rhs) + */ + +/** + * \fn bool operator>(const Size &lhs, const Size &rhs) + * \brief Compare sizes for greater than order + * \return True if \a lhs is greater than \a rhs, false otherwise + * \sa bool operator<(const Size &lhs, const Size &rhs) + */ + +/** + * \fn bool operator>=(const Size &lhs, const Size &rhs) + * \brief Compare sizes for greater than or equal to order + * \return True if \a lhs is greater than or equal to \a rhs, false otherwise + * \sa bool operator<(const Size &lhs, const Size &rhs) + */ + /** * \struct SizeRange * \brief Describe a range of sizes @@ -124,4 +207,19 @@ const std::string Rectangle::toString() const * \brief The maximum size */ +/** + * \brief Compare size ranges for equality + * \return True if the two size ranges are equal, false otherwise + */ +bool operator==(const SizeRange &lhs, const SizeRange &rhs) +{ + return lhs.min == rhs.min && lhs.max == rhs.max; +} + +/** + * \fn bool operator!=(const SizeRange &lhs, const SizeRange &rhs) + * \brief Compare size ranges for inequality + * \return True if the two size ranges are not equal, false otherwise + */ + } /* namespace libcamera */ From patchwork Tue Apr 16 22:08:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1016 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CAABA60004 for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 78D9BE2 for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452533; bh=cFvDd/CCqAepMcjnOcsvoqbRzt6gHKhXQuEPicQH/eA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=LFzbwcK//WCBkJW2xz2u8POT+oam0PCW3yaPdp0r0YPfuX34w7cDhLBcka/t3QgZ1 sgGJ3TQParSC+bwHn1v3vNHoTPRTT6PqiNl4W8XmIYId2M00pVfFvtu7qUzOBQyH4f Es9R7NC5hOmMEI6tnnwWFXjZetcwPKjNZe69Op1s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:33 +0300 Message-Id: <20190416220839.1577-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/13] test: geometry: Add tests for Size class comparison operators 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: Tue, 16 Apr 2019 22:08:55 -0000 Add a test that exercises all the comparison operators for the Size class. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- Changes since v1: - Remove the init() and cleanup() methods --- test/geometry.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 117 insertions(+) create mode 100644 test/geometry.cpp diff --git a/test/geometry.cpp b/test/geometry.cpp new file mode 100644 index 000000000000..27e65565d7c6 --- /dev/null +++ b/test/geometry.cpp @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * geometry.cpp - Geometry classes tests + */ + +#include + +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class GeometryTest : public Test +{ +protected: + bool compare(const Size &lhs, const Size &rhs, + bool (*op)(const Size &lhs, const Size &rhs), + const char *opName, bool expect) + { + bool result = op(lhs, rhs); + + if (result != expect) { + cout << "Size(" << lhs.width << ", " << lhs.height << ") " + << opName << " " + << "Size(" << rhs.width << ", " << rhs.height << ") " + << "test failed" << std::endl; + return false; + } + + return true; + } + + int run() + { + /* Test Size equality and inequality. */ + if (!compare(Size(100, 100), Size(100, 100), &operator==, "==", true)) + return TestFail; + if (!compare(Size(100, 100), Size(100, 100), &operator!=, "!=", false)) + return TestFail; + + if (!compare(Size(100, 100), Size(200, 100), &operator==, "==", false)) + return TestFail; + if (!compare(Size(100, 100), Size(200, 100), &operator!=, "!=", true)) + return TestFail; + + if (!compare(Size(100, 100), Size(100, 200), &operator==, "==", false)) + return TestFail; + if (!compare(Size(100, 100), Size(100, 200), &operator!=, "!=", true)) + return TestFail; + + /* Test Size ordering based on combined with and height. */ + if (!compare(Size(100, 100), Size(200, 200), &operator<, "<", true)) + return TestFail; + if (!compare(Size(100, 100), Size(200, 200), &operator<=, "<=", true)) + return TestFail; + if (!compare(Size(100, 100), Size(200, 200), &operator>, ">", false)) + return TestFail; + if (!compare(Size(100, 100), Size(200, 200), &operator>=, ">=", false)) + return TestFail; + + if (!compare(Size(200, 200), Size(100, 100), &operator<, "<", false)) + return TestFail; + if (!compare(Size(200, 200), Size(100, 100), &operator<=, "<=", false)) + return TestFail; + if (!compare(Size(200, 200), Size(100, 100), &operator>, ">", true)) + return TestFail; + if (!compare(Size(200, 200), Size(100, 100), &operator>=, ">=", true)) + return TestFail; + + /* Test Size ordering based on area (with overlapping sizes). */ + if (!compare(Size(200, 100), Size(100, 400), &operator<, "<", true)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 400), &operator<=, "<=", true)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 400), &operator>, ">", false)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 400), &operator>=, ">=", false)) + return TestFail; + + if (!compare(Size(100, 400), Size(200, 100), &operator<, "<", false)) + return TestFail; + if (!compare(Size(100, 400), Size(200, 100), &operator<=, "<=", false)) + return TestFail; + if (!compare(Size(100, 400), Size(200, 100), &operator>, ">", true)) + return TestFail; + if (!compare(Size(100, 400), Size(200, 100), &operator>=, ">=", true)) + return TestFail; + + /* Test Size ordering based on width (with identical areas). */ + if (!compare(Size(100, 200), Size(200, 100), &operator<, "<", true)) + return TestFail; + if (!compare(Size(100, 200), Size(200, 100), &operator<=, "<=", true)) + return TestFail; + if (!compare(Size(100, 200), Size(200, 100), &operator>, ">", false)) + return TestFail; + if (!compare(Size(100, 200), Size(200, 100), &operator>=, ">=", false)) + return TestFail; + + if (!compare(Size(200, 100), Size(100, 200), &operator<, "<", false)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 200), &operator<=, "<=", false)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 200), &operator>, ">", true)) + return TestFail; + if (!compare(Size(200, 100), Size(100, 200), &operator>=, ">=", true)) + return TestFail; + + return TestPass; + } +}; + +TEST_REGISTER(GeometryTest) diff --git a/test/meson.build b/test/meson.build index 71a96921697c..d501f2beaf96 100644 --- a/test/meson.build +++ b/test/meson.build @@ -9,6 +9,7 @@ subdir('v4l2_subdevice') public_tests = [ ['event', 'event.cpp'], ['event-dispatcher', 'event-dispatcher.cpp'], + ['geometry', 'geometry.cpp'], ['list-cameras', 'list-cameras.cpp'], ['signal', 'signal.cpp'], ['timer', 'timer.cpp'], From patchwork Tue Apr 16 22:08:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1017 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27E8D60DCB for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BFB732BA for ; Wed, 17 Apr 2019 00:08:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452533; bh=ZYd1SJs0RXKjpv+tW9G+JC/iNNeE9LETC1uoqYqMHk0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=nldVa4AXcSgkjZLSDGNGULwHIoI3kRumZshLV4qRFKG4bTjuzBkIL2QzIUUEgbh/O 1G9jeu9vpIL2Vmd2UvM/1zMSO2TKTUK4vFSApkG8wuJxcdAqXSWcI7nGgpeZC8CrvS eTpSU0u53B0RjyLwyA1yX1jux893C+I4muT7Ke2k= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:34 +0300 Message-Id: <20190416220839.1577-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/13] libcamera: utils: Add set_overlap() function 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: Tue, 16 Apr 2019 22:08:55 -0000 The new set_overlap() function counts the number of overlapping elements in the intersection of two sorted ranges defined by their beginning and ending iterators. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/include/utils.h | 19 +++++++++++++++++++ src/libcamera/utils.cpp | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/libcamera/include/utils.h b/src/libcamera/include/utils.h index 79038a96feab..97bd470a45b0 100644 --- a/src/libcamera/include/utils.h +++ b/src/libcamera/include/utils.h @@ -26,6 +26,25 @@ std::unique_ptr make_unique(Args&&... args) char *secure_getenv(const char *name); +template +unsigned int set_overlap(InputIt1 first1, InputIt1 last1, + InputIt2 first2, InputIt2 last2) +{ + unsigned int count = 0; + + while (first1 != last1 && first2 != last2) { + if (*first1 < *first2) { + ++first1; + } else { + if (!(*first2 < *first1)) + count++; + ++first2; + } + } + + return count; +} + } /* namespace utils */ } /* namespace libcamera */ diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp index cd0fd7614cc7..e38f32684bb1 100644 --- a/src/libcamera/utils.cpp +++ b/src/libcamera/utils.cpp @@ -68,6 +68,18 @@ char *secure_getenv(const char *name) * \brief Constructs an object of type T and wraps it in a std::unique_ptr. */ +/** + * \fn libcamera::utils::set_overlap(InputIt1 first1, InputIt1 last1, + * InputIt2 first2, InputIt2 last2) + * \brief Count the number of elements in the intersection of two ranges + * + * Count the number of elements in the intersection of the sorted ranges [\a + * first1, \a last1) and [\a first1, \a last2). Elements are compared using + * operator< and the ranges must be sorted with respect to the same. + * + * \return The number of elements in the intersection of the two ranges + */ + } /* namespace utils */ } /* namespace libcamera */ From patchwork Tue Apr 16 22:08:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1018 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6D86360DCC for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1347BE2 for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452534; bh=a5p2WN0SdnqNVGvtj5mUdm1cWRoe34iGSLYcw0Rw86A=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rOuHG4CRB6qsN4N574shsp7RIVUbu+WN1qev+EdJ7eteJLV+8ZinMkZCIJGoZoSr3 HYrqr4PvOLlV87OoOr+e1ezZbAYEk1369Xz/68JSUHkv8qFbFOGdaQvQRFPTW7wo6x HBV6OlyLzm/y2Opjrofk2AtkyY52pTuv3Bjecw8I= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:35 +0300 Message-Id: <20190416220839.1577-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/13] libcamera: v4l2_subdevice: Close subdevice when destroyed 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: Tue, 16 Apr 2019 22:08:55 -0000 Make sure the subdevice file descriptor isn't leaked by closing it when the V4L2Subdevice instance is destroyed. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/include/v4l2_subdevice.h | 1 + src/libcamera/v4l2_subdevice.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index c71dce7d8644..e592d67dd043 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -35,6 +35,7 @@ public: explicit V4L2Subdevice(const MediaEntity *entity); V4L2Subdevice(const V4L2Subdevice &) = delete; V4L2Subdevice &operator=(const V4L2Subdevice &) = delete; + ~V4L2Subdevice(); int open(); bool isOpen() const; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index e34cc1693b46..a03fadfd579e 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -112,6 +112,11 @@ V4L2Subdevice::V4L2Subdevice(const MediaEntity *entity) { } +V4L2Subdevice::~V4L2Subdevice() +{ + close(); +} + /** * \brief Open a V4L2 subdevice * From patchwork Tue Apr 16 22:08:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1019 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D2DE960DC0 for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 58A982BA for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452534; bh=cMpbBV72CoEG8V8PaJaGE5AqvOAtchALPQ5WewmQSbc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=W9r1m2l6VoStgbcRKs8s101OL/Qt9uRc4nvGSAE3NJuZ8jG3G88a1K9RTE1lqt25p QYtmdR5UB0/cB6NnQhzAVNNSrUZqFmFvgxcfM4GZf/ZQuin0ULQkzzuNwFtMBdgi1m hli6l4Pgo0DrW9T4Ypcoy3kz4l0QEK024W9bqmEo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:36 +0300 Message-Id: <20190416220839.1577-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/13] libcamera: v4l2-subdevice: Add method to retrieve the media entity 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: Tue, 16 Apr 2019 22:08:56 -0000 Add a method to retrieve the media entity associated with a subdevice. The entityName() and deviceNode() methods are not needed anymore as they can be accessed through the media entity, remove them. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/include/v4l2_subdevice.h | 3 +-- src/libcamera/pipeline/ipu3/ipu3.cpp | 4 ++-- src/libcamera/v4l2_subdevice.cpp | 22 +++++++-------------- test/v4l2_subdevice/list_formats.cpp | 6 +++--- test/v4l2_subdevice/v4l2_subdevice_test.cpp | 2 +- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/libcamera/include/v4l2_subdevice.h b/src/libcamera/include/v4l2_subdevice.h index e592d67dd043..c7b0b4cb76ea 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -41,8 +41,7 @@ public: bool isOpen() const; void close(); - const std::string &deviceNode() const { return entity_->deviceNode(); } - const std::string &entityName() const { return entity_->name(); } + const MediaEntity *entity() const { return entity_; } int setCrop(unsigned int pad, Rectangle *rect); int setCompose(unsigned int pad, Rectangle *rect); diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 4ddd1ede1c81..e3c79f93963e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -579,7 +579,7 @@ int PipelineHandlerIPU3::registerCameras() &IPU3CameraData::imguOutputBufferReady); /* Create and register the Camera instance. */ - std::string cameraName = cio2->sensor_->entityName() + " " + std::string cameraName = cio2->sensor_->entity()->name() + " " + std::to_string(id); std::shared_ptr camera = Camera::create(this, cameraName, @@ -1055,7 +1055,7 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) } } if (maxSize_.width == 0) { - LOG(IPU3, Info) << "Sensor '" << sensor_->entityName() + LOG(IPU3, Info) << "Sensor '" << sensor_->entity()->name() << "' detected, but no supported image format " << " found: skip camera creation"; return -ENODEV; diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp index a03fadfd579e..5d5b168f98a2 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -131,12 +131,12 @@ int V4L2Subdevice::open() return -EBUSY; } - ret = ::open(deviceNode().c_str(), O_RDWR); + ret = ::open(entity_->deviceNode().c_str(), O_RDWR); if (ret < 0) { ret = -errno; LOG(V4L2Subdev, Error) - << "Failed to open V4L2 subdevice '" << deviceNode() - << "': " << strerror(-ret); + << "Failed to open V4L2 subdevice '" + << entity_->deviceNode() << "': " << strerror(-ret); return ret; } fd_ = ret; @@ -166,17 +166,9 @@ void V4L2Subdevice::close() } /** - * \fn V4L2Subdevice::deviceNode() - * \brief Retrieve the path of the device node associated with the subdevice - * - * \return The subdevice's device node system path - */ - -/** - * \fn V4L2Subdevice::entityName() - * \brief Retrieve the name of the media entity associated with the subdevice - * - * \return The name of the media entity the subdevice is associated to + * \fn V4L2Subdevice::entity() + * \brief Retrieve the media entity associated with the subdevice + * \return The subdevice's associated media entity. */ /** @@ -343,7 +335,7 @@ V4L2Subdevice *V4L2Subdevice::fromEntityName(const MediaDevice *media, std::string V4L2Subdevice::logPrefix() const { - return "'" + entityName() + "'"; + return "'" + entity_->name() + "'"; } int V4L2Subdevice::enumPadSizes(unsigned int pad,unsigned int code, diff --git a/test/v4l2_subdevice/list_formats.cpp b/test/v4l2_subdevice/list_formats.cpp index 09dec9abe854..18dd8761a8ab 100644 --- a/test/v4l2_subdevice/list_formats.cpp +++ b/test/v4l2_subdevice/list_formats.cpp @@ -52,7 +52,7 @@ int ListFormatsTest::run() formats = scaler_->formats(0); if (formats.empty()) { cerr << "Failed to list formats on pad 0 of subdevice " - << scaler_->entityName() << endl; + << scaler_->entity()->name() << endl; return TestFail; } for (auto it = formats.begin(); it != formats.end(); ++it) @@ -61,7 +61,7 @@ int ListFormatsTest::run() formats = scaler_->formats(1); if (formats.empty()) { cerr << "Failed to list formats on pad 1 of subdevice " - << scaler_->entityName() << endl; + << scaler_->entity()->name() << endl; return TestFail; } for (auto it = formats.begin(); it != formats.end(); ++it) @@ -71,7 +71,7 @@ int ListFormatsTest::run() formats = scaler_->formats(2); if (!formats.empty()) { cerr << "Listing formats on non-existing pad 2 of subdevice " - << scaler_->entityName() + << scaler_->entity()->name() << " should return an empty format list" << endl; return TestFail; } diff --git a/test/v4l2_subdevice/v4l2_subdevice_test.cpp b/test/v4l2_subdevice/v4l2_subdevice_test.cpp index 06582969eb45..dfcf779af95e 100644 --- a/test/v4l2_subdevice/v4l2_subdevice_test.cpp +++ b/test/v4l2_subdevice/v4l2_subdevice_test.cpp @@ -66,7 +66,7 @@ int V4L2SubdeviceTest::init() ret = scaler_->open(); if (ret) { cerr << "Unable to open video subdevice " - << scaler_->deviceNode() << endl; + << scaler_->entity()->deviceNode() << endl; media_->release(); return TestSkip; } From patchwork Tue Apr 16 22:08:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1020 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 353A060DC4 for ; Wed, 17 Apr 2019 00:08:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C07412D2 for ; Wed, 17 Apr 2019 00:08:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452535; bh=KuiuGC3BtLU7nlLQG9RL+BKdzoQ7+Gw34/lM9hw3dyk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vZLHngzzeEvqFotPjFq6DsemTviTOKTSPqJxNT+EylJHQBS/H4WodWwZLmqJfAniu muYvBRHB7Dgt7om9d4XM2jLRPKQTvjo8iTmeTdoU4TEGYHltoAFE5xJY3qtmSRl8hr oBPB87G1eLsCXeFcFamlleuK05fq+5BBJ2hzRxjg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:37 +0300 Message-Id: <20190416220839.1577-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/13] libcamera: camera_sensor: Add a new class to model a camera sensor 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: Tue, 16 Apr 2019 22:08:56 -0000 The CameraSensor class abstracts camera sensors and provides helper functions to ease interactions with them. It is currently limited to sensors that expose a single subdev, and offer the same frame sizes for all media bus codes, but will be extended to support more complex sensors as the needs arise. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Add sensor entity function check - Sort the media bus codes - Remove the unneeded std::endl for LOG() - Improve documentation - Inherit from Loggable with the protected qualifier --- src/libcamera/camera_sensor.cpp | 258 ++++++++++++++++++++++++++ src/libcamera/include/camera_sensor.h | 56 ++++++ src/libcamera/meson.build | 2 + 3 files changed, 316 insertions(+) create mode 100644 src/libcamera/camera_sensor.cpp create mode 100644 src/libcamera/include/camera_sensor.h diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp new file mode 100644 index 000000000000..ca4dd0c92efa --- /dev/null +++ b/src/libcamera/camera_sensor.cpp @@ -0,0 +1,258 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_sensor.cpp - A camera sensor + */ + +#include +#include +#include +#include +#include + +#include "camera_sensor.h" +#include "formats.h" +#include "v4l2_subdevice.h" + +/** + * \file camera_sensor.h + * \brief A camera sensor + */ + +namespace libcamera { + +LOG_DEFINE_CATEGORY(CameraSensor); + +/** + * \class CameraSensor + * \brief A camera sensor based on V4L2 subdevices + * + * The CameraSensor class eases handling of sensors for pipeline handlers by + * hiding the details of the V4L2 subdevice kernel API and caching sensor + * information. + * + * The implementation is currently limited to sensors that expose a single V4L2 + * subdevice with a single pad, and support the same frame sizes for all + * supported media bus codes. It will be extended to support more complex + * devices as the needs arise. + */ + +/** + * \brief Construct a CameraSensor + * \param[in] entity The media entity backing the camera sensor + * + * Once constructed the instance must be initialized with init(). + */ +CameraSensor::CameraSensor(const MediaEntity *entity) + : entity_(entity) +{ + subdev_ = new V4L2Subdevice(entity); +} + +/** + * \brief Destroy a CameraSensor + */ +CameraSensor::~CameraSensor() +{ + delete subdev_; +} + +/** + * \brief Initialize the camera sensor instance + * + * This method performs the initialisation steps of the CameraSensor that may + * fail. It shall be called once and only once after constructing the instance. + * + * \return 0 on success or a negative error code otherwise + */ +int CameraSensor::init() +{ + int ret; + + if (entity_->pads().size() != 1) { + LOG(CameraSensor, Error) + << "Sensors with more than one pad are not supported"; + return -EINVAL; + } + + if (entity_->function() != MEDIA_ENT_F_CAM_SENSOR) { + LOG(CameraSensor, Error) + << "Invalid sensor function 0x" + << std::hex << std::setfill('0') << std::setw(8) + << entity_->function(); + return -EINVAL; + } + + ret = subdev_->open(); + if (ret < 0) + return ret; + + /* Enumerate and cache media bus codes and sizes. */ + const FormatEnum formats = subdev_->formats(0); + if (formats.empty()) { + LOG(CameraSensor, Error) << "No image format found"; + return -EINVAL; + } + + std::transform(formats.begin(), formats.end(), + std::back_inserter(mbusCodes_), + [](decltype(*formats.begin()) f) { return f.first; }); + + /* + * 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; + 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) { + LOG(CameraSensor, Error) + << "Frame sizes differ between media bus codes"; + return -EINVAL; + } + } + + /* Sort the media bus codes and sizes. */ + std::sort(mbusCodes_.begin(), mbusCodes_.end()); + std::sort(sizes_.begin(), sizes_.end()); + + return 0; +} + +/** + * \fn CameraSensor::entity() + * \brief Retrieve the sensor media entity + * \return The sensor media entity + */ + +/** + * \fn CameraSensor::mbusCodes() + * \brief Retrieve the media bus codes supported by the camera sensor + * \return The supported media bus codes sorted in increasing order + */ + +/** + * \fn CameraSensor::sizes() + * \brief Retrieve the frame sizes supported by the camera sensor + * \return The supported frame sizes sorted in increasing order + */ + +/** + * \brief Retrieve the camera sensor resolution + * \return The camera sensor resolution in pixels + */ +const Size &CameraSensor::resolution() const +{ + /* + * The sizes_ vector is sorted in ascending order, the resolution is + * thus the last element of the vector. + */ + return sizes_.back(); +} + +/** + * \brief Retrieve the best sensor format for a desired output + * \param[in] mbusCodes The list of acceptable media bus codes + * \param[in] size The desired size + * + * Media bus codes are selected from \a mbusCodes, which lists all acceptable + * codes in decreasing order of preference. This method selects the first code + * from the list that is supported by the sensor. If none of the desired codes + * is supported, it returns an error. + * + * \a size indicates the desired size at the output of the sensor. This method + * selects the best size supported by the sensor according to the following + * criteria. + * + * - The desired \a size shall fit in the sensor output size to avoid the need + * to up-scale. + * - The sensor output size shall match the desired aspect ratio to avoid the + * need to crop the field of view. + * - The sensor output size shall be as small as possible to lower the required + * bandwidth. + * + * The use of this method is optional, as the above criteria may not match the + * needs of all pipeline handlers. Pipeline handlers may implement custom + * sensor format selection when needed. + * + * The returned sensor output format is guaranteed to be acceptable by the + * setFormat() method without any modification. + * + * \return The best sensor output format matching the desired media bus codes + * and size on success, or an empty format otherwise. + */ +V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector &mbusCodes, + const Size &size) const +{ + V4L2SubdeviceFormat format{}; + + for (unsigned int code : mbusCodes_) { + if (std::any_of(mbusCodes.begin(), mbusCodes.end(), + [code](unsigned int c) { return c == code; })) { + format.mbus_code = code; + break; + } + } + + if (!format.mbus_code) { + LOG(CameraSensor, Debug) << "No supported format found"; + return format; + } + + unsigned int desiredArea = size.width * size.height; + unsigned int bestArea = UINT_MAX; + float desiredRatio = static_cast(size.width) / size.height; + float bestRatio = FLT_MAX; + const Size *bestSize = nullptr; + + for (const Size &sz : sizes_) { + if (sz.width < size.width || sz.height < size.height) + continue; + + float ratio = static_cast(sz.width) / sz.height; + float ratioDiff = fabsf(ratio - desiredRatio); + unsigned int area = sz.width * sz.height; + unsigned int areaDiff = area - desiredArea; + + if (ratioDiff > bestRatio) + continue; + + if (ratioDiff < bestRatio || areaDiff < bestArea) { + bestRatio = ratioDiff; + bestArea = areaDiff; + bestSize = &sz; + } + } + + if (!bestSize) { + LOG(CameraSensor, Debug) << "No supported size found"; + return format; + } + + format.width = bestSize->width; + format.height = bestSize->height; + + return format; +} + +/** + * \brief Set the sensor output format + * \param[in] format The desired sensor output format + * + * \return 0 on success or a negative error code otherwise + */ +int CameraSensor::setFormat(V4L2SubdeviceFormat *format) +{ + return subdev_->setFormat(0, format); +} + +std::string CameraSensor::logPrefix() const +{ + return "'" + subdev_->entity()->name() + "'"; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h new file mode 100644 index 000000000000..7f2f906be8df --- /dev/null +++ b/src/libcamera/include/camera_sensor.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_sensor.h - A camera sensor + */ +#ifndef __LIBCAMERA_CAMERA_SENSOR_H__ +#define __LIBCAMERA_CAMERA_SENSOR_H__ + +#include +#include + +#include + +#include "log.h" + +namespace libcamera { + +class MediaEntity; +class V4L2Subdevice; +class V4L2SubdeviceFormat; + +class CameraSensor : protected Loggable +{ +public: + explicit CameraSensor(const MediaEntity *entity); + ~CameraSensor(); + + CameraSensor(const CameraSensor &) = delete; + CameraSensor &operator=(const CameraSensor &) = delete; + + int init(); + + const MediaEntity *entity() const { return entity_; } + const std::vector &mbusCodes() const { return mbusCodes_; } + const std::vector &sizes() const { return sizes_; } + const Size &resolution() const; + + V4L2SubdeviceFormat getFormat(const std::vector &mbusCodes, + const Size &size) const; + int setFormat(V4L2SubdeviceFormat *format); + +protected: + std::string logPrefix() const; + +private: + const MediaEntity *entity_; + V4L2Subdevice *subdev_; + + std::vector mbusCodes_; + std::vector sizes_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CAMERA_SENSOR_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index cd36ac307518..cf4edec05755 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -2,6 +2,7 @@ libcamera_sources = files([ 'buffer.cpp', 'camera.cpp', 'camera_manager.cpp', + 'camera_sensor.cpp', 'device_enumerator.cpp', 'event_dispatcher.cpp', 'event_dispatcher_poll.cpp', @@ -23,6 +24,7 @@ libcamera_sources = files([ ]) libcamera_headers = files([ + 'include/camera_sensor.h', 'include/device_enumerator.h', 'include/event_dispatcher_poll.h', 'include/formats.h', From patchwork Tue Apr 16 22:08:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1021 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 88FAE60DCE for ; Wed, 17 Apr 2019 00:08:55 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2B9832BA for ; Wed, 17 Apr 2019 00:08:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452535; bh=9ceZmuZ/MTu5Mhpo/nBsm3sTOyjsUmxf8y++Mtlj+Mk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=eCcD8mgsrbTOKoRuSjALuE3ikw4F4Z98m0Qkj1Z8Un6aigiIM2gwZK7iP1c/A2gDf +P9sbd+tO0q9xoaGfoQxm0tBcWmTQGOJqwARDg0SifJP00+sesrOQPhDz6k9cqfsVM YtQIlAGuPZU03XnakH9fU6UozjgcnLFu6qzO0BIA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:38 +0300 Message-Id: <20190416220839.1577-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/13] libcamera: pipeline: ipu3: Use the new CameraSensor class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 16 Apr 2019 22:08:56 -0000 Replace the manual handling of sensor formats with usage of the new CameraSensor class. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund --- Changes since v1: - Move sensor entity function check to CameraSensor class - Verify sensor media bus codes at init time --- src/libcamera/pipeline/ipu3/ipu3.cpp | 107 +++++++++------------------ 1 file changed, 36 insertions(+), 71 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index e3c79f93963e..861c0da7550a 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -5,6 +5,7 @@ * ipu3.cpp - Pipeline handler for Intel IPU3 */ +#include #include #include #include @@ -15,6 +16,7 @@ #include #include +#include "camera_sensor.h" #include "device_enumerator.h" #include "log.h" #include "media_device.h" @@ -124,11 +126,7 @@ public: V4L2Device *output_; V4L2Subdevice *csi2_; - V4L2Subdevice *sensor_; - - /* Maximum sizes and the mbus code used to produce them. */ - unsigned int mbusCode_; - Size maxSize_; + CameraSensor *sensor_; BufferPool pool_; }; @@ -255,8 +253,9 @@ int PipelineHandlerIPU3::configureStreams(Camera *camera, return -EINVAL; } - if (cfg.width > cio2->maxSize_.width || - cfg.height > cio2->maxSize_.height) { + const Size &resolution = cio2->sensor_->resolution(); + if (cfg.width > resolution.width || + cfg.height > resolution.height) { LOG(IPU3, Error) << "Invalid stream size: larger than sensor resolution"; return -EINVAL; @@ -1021,45 +1020,39 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) MediaLink *link = links[0]; MediaEntity *sensorEntity = link->source()->entity(); - if (sensorEntity->function() != MEDIA_ENT_F_CAM_SENSOR) - return -ENODEV; + sensor_ = new CameraSensor(sensorEntity); + ret = sensor_->init(); + if (ret) + return ret; ret = link->setEnabled(true); if (ret) return ret; /* - * Now that we're sure a sensor subdevice is connected, make sure it - * produces at least one image format compatible with CIO2 requirements - * and cache the camera maximum size. + * Make sure the sensor produces at least one format compatible with + * the CIO2 requirements. * + * utils::set_overlap requires the ranges to be sorted, keep the + * cio2Codes vector sorted in ascending order. + */ + const std::vector cio2Codes{ MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10 }; + const std::vector &sensorCodes = sensor_->mbusCodes(); + if (!utils::set_overlap(sensorCodes.begin(), sensorCodes.end(), + cio2Codes.begin(), cio2Codes.end())) { + LOG(IPU3, Error) + << "Sensor " << sensor_->entity()->name() + << " has not format compatible with the IPU3"; + return -EINVAL; + } + + /* * \todo Define when to open and close video device nodes, as they * might impact on power consumption. */ - sensor_ = new V4L2Subdevice(sensorEntity); - ret = sensor_->open(); - if (ret) - return ret; - - for (auto it : sensor_->formats(0)) { - int mbusCode = mediaBusToFormat(it.first); - if (mbusCode < 0) - continue; - - for (const SizeRange &size : it.second) { - if (maxSize_.width < size.max.width && - maxSize_.height < size.max.height) { - maxSize_ = size.max; - mbusCode_ = mbusCode; - } - } - } - if (maxSize_.width == 0) { - LOG(IPU3, Info) << "Sensor '" << sensor_->entity()->name() - << "' detected, but no supported image format " - << " found: skip camera creation"; - return -ENODEV; - } csi2_ = new V4L2Subdevice(csi2Entity); ret = csi2_->open(); @@ -1085,47 +1078,19 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) int CIO2Device::configure(const StreamConfiguration &config, V4L2DeviceFormat *outputFormat) { - unsigned int imageSize = config.width * config.height; - V4L2SubdeviceFormat sensorFormat = {}; - unsigned int best = ~0; + V4L2SubdeviceFormat sensorFormat; int ret; - for (auto it : sensor_->formats(0)) { - /* Only consider formats consumable by the CIO2 unit. */ - if (mediaBusToFormat(it.first) < 0) - continue; - - for (const SizeRange &size : it.second) { - /* - * Only select formats bigger than the requested sizes - * as the IPU3 cannot up-scale. - * - * \todo: Unconditionally scale on the sensor as much - * as possible. This will need to be revisited when - * implementing the scaling policy. - */ - if (size.max.width < config.width || - size.max.height < config.height) - continue; - - unsigned int diff = size.max.width * size.max.height - - imageSize; - if (diff >= best) - continue; - - best = diff; - - sensorFormat.width = size.max.width; - sensorFormat.height = size.max.height; - sensorFormat.mbus_code = it.first; - } - } - /* * Apply the selected format to the sensor, the CSI-2 receiver and * the CIO2 output device. */ - ret = sensor_->setFormat(0, &sensorFormat); + sensorFormat = sensor_->getFormat({ MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10 }, + Size(config.width, config.height)); + ret = sensor_->setFormat(&sensorFormat); if (ret) return ret; From patchwork Tue Apr 16 22:08:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1022 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0E11960DC2 for ; Wed, 17 Apr 2019 00:08:56 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B17CAE2 for ; Wed, 17 Apr 2019 00:08:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555452535; bh=e6W1iCCt2NmcZMdutAn6xWeVKbRACdlz7nB8pWVzIxo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=G9+6Jtn0PJmw4NVSLQbKE/U1TFY8KLgGdHapo0wwYz3+Ckj63mKPQWCHOoGJ/9Lj4 MEybENy0XwP6ixoVc+eTPtzK3SW66ulWhWh++prLf7aZEMnPKx8EYe9oL+/q4e6+Qf lHppIDYaxDAke7Do7SxMJKWY5PNKeTteQMWPkaCM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Wed, 17 Apr 2019 01:08:39 +0300 Message-Id: <20190416220839.1577-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> References: <20190416220839.1577-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 13/13] libcamera: pipeline: Add RKISP1 pipeline 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: Tue, 16 Apr 2019 22:08:57 -0000 The pipeline handler for the Rockchip ISP creates one camera instance per detected raw Bayer CSI-2 sensor. Parallel sensors and YUV sensors are not supported yet. As the ISP has a single CSI-2 receiver, only one camera can be used at a time. Mutual exclusion isn't implemented yet. Signed-off-by: Laurent Pinchart Reviewed-by: Niklas Söderlund Tested-by: Niklas Söderlund --- Changes since v1: - Move sensor entity sanity checks to CameraSensor class - Remove unneeded LOG() message --- src/libcamera/pipeline/meson.build | 1 + src/libcamera/pipeline/rkisp1/meson.build | 3 + src/libcamera/pipeline/rkisp1/rkisp1.cpp | 431 ++++++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 src/libcamera/pipeline/rkisp1/meson.build create mode 100644 src/libcamera/pipeline/rkisp1/rkisp1.cpp diff --git a/src/libcamera/pipeline/meson.build b/src/libcamera/pipeline/meson.build index 40bb26405b88..0d466225a72e 100644 --- a/src/libcamera/pipeline/meson.build +++ b/src/libcamera/pipeline/meson.build @@ -4,3 +4,4 @@ libcamera_sources += files([ ]) subdir('ipu3') +subdir('rkisp1') diff --git a/src/libcamera/pipeline/rkisp1/meson.build b/src/libcamera/pipeline/rkisp1/meson.build new file mode 100644 index 000000000000..f1cc4046b5d0 --- /dev/null +++ b/src/libcamera/pipeline/rkisp1/meson.build @@ -0,0 +1,3 @@ +libcamera_sources += files([ + 'rkisp1.cpp', +]) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp new file mode 100644 index 000000000000..d44b546fa008 --- /dev/null +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -0,0 +1,431 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * rkisp1.cpp - Pipeline handler for Rockchip ISP1 + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "camera_sensor.h" +#include "device_enumerator.h" +#include "log.h" +#include "media_device.h" +#include "pipeline_handler.h" +#include "utils.h" +#include "v4l2_device.h" +#include "v4l2_subdevice.h" + +namespace libcamera { + +LOG_DEFINE_CATEGORY(RkISP1) + +class PipelineHandlerRkISP1 : public PipelineHandler +{ +public: + PipelineHandlerRkISP1(CameraManager *manager); + ~PipelineHandlerRkISP1(); + + CameraConfiguration streamConfiguration(Camera *camera, + const std::vector &usages) override; + int configureStreams(Camera *camera, + const CameraConfiguration &config) override; + + int allocateBuffers(Camera *camera, Stream *stream) override; + int freeBuffers(Camera *camera, Stream *stream) override; + + int start(Camera *camera) override; + void stop(Camera *camera) override; + + int queueRequest(Camera *camera, Request *request) override; + + bool match(DeviceEnumerator *enumerator) override; + +private: + class RkISP1CameraData : public CameraData + { + public: + RkISP1CameraData(PipelineHandler *pipe) + : CameraData(pipe), sensor_(nullptr) + { + } + + ~RkISP1CameraData() + { + delete sensor_; + } + + Stream stream_; + CameraSensor *sensor_; + }; + + static constexpr unsigned int RKISP1_BUFFER_COUNT = 4; + + RkISP1CameraData *cameraData(const Camera *camera) + { + return static_cast( + PipelineHandler::cameraData(camera)); + } + + int initLinks(); + int createCamera(MediaEntity *sensor); + void bufferReady(Buffer *buffer); + + std::shared_ptr media_; + V4L2Subdevice *dphy_; + V4L2Subdevice *isp_; + V4L2Device *video_; + + Camera *activeCamera_; +}; + +PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager) + : PipelineHandler(manager), dphy_(nullptr), isp_(nullptr), + video_(nullptr) +{ +} + +PipelineHandlerRkISP1::~PipelineHandlerRkISP1() +{ + delete video_; + delete isp_; + delete dphy_; + + if (media_) + media_->release(); +} + +/* ----------------------------------------------------------------------------- + * Pipeline Operations + */ + +CameraConfiguration PipelineHandlerRkISP1::streamConfiguration(Camera *camera, + const std::vector &usages) +{ + RkISP1CameraData *data = cameraData(camera); + CameraConfiguration configs; + StreamConfiguration config{}; + + const Size &resolution = data->sensor_->resolution(); + config.width = resolution.width; + config.height = resolution.height; + config.pixelFormat = V4L2_PIX_FMT_NV12; + config.bufferCount = RKISP1_BUFFER_COUNT; + + configs[&data->stream_] = config; + + LOG(RkISP1, Debug) + << "Stream format set to " << config.width << "x" + << config.height << "-0x" << std::hex << std::setfill('0') + << std::setw(8) << config.pixelFormat; + + return configs; +} + +int PipelineHandlerRkISP1::configureStreams(Camera *camera, + const CameraConfiguration &config) +{ + RkISP1CameraData *data = cameraData(camera); + const StreamConfiguration &cfg = config[&data->stream_]; + CameraSensor *sensor = data->sensor_; + int ret; + + /* Verify the configuration. */ + const Size &resolution = sensor->resolution(); + if (cfg.width > resolution.width || + cfg.height > resolution.height) { + LOG(RkISP1, Error) + << "Invalid stream size: larger than sensor resolution"; + return -EINVAL; + } + + /* + * Configure the sensor links: enable the link corresponding to this + * camera and disable all the other sensor links. + */ + const MediaPad *pad = dphy_->entity()->getPadByIndex(0); + + ret = media_->open(); + if (ret < 0) + return ret; + + for (MediaLink *link : pad->links()) { + bool enable = link->source()->entity() == sensor->entity(); + + if (!!(link->flags() & MEDIA_LNK_FL_ENABLED) == enable) + continue; + + LOG(RkISP1, Debug) + << (enable ? "Enabling" : "Disabling") + << " link from sensor '" + << link->source()->entity()->name() + << "' to CSI-2 receiver"; + + ret = link->setEnabled(enable); + if (ret < 0) + break; + } + + media_->close(); + + if (ret < 0) + return ret; + + /* + * Configure the format on the sensor output and propagate it through + * the pipeline. + */ + V4L2SubdeviceFormat format; + format = sensor->getFormat({ MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8 }, + Size(cfg.width, cfg.height)); + + LOG(RkISP1, Debug) << "Configuring sensor for " << format.toString(); + + ret = sensor->setFormat(&format); + if (ret < 0) + return ret; + + ret = dphy_->setFormat(0, &format); + if (ret < 0) + return ret; + + ret = dphy_->getFormat(1, &format); + if (ret < 0) + return ret; + + ret = isp_->setFormat(0, &format); + if (ret < 0) + return ret; + + V4L2DeviceFormat outputFormat = {}; + outputFormat.width = cfg.width; + outputFormat.height = cfg.height; + outputFormat.fourcc = V4L2_PIX_FMT_NV12; + outputFormat.planesCount = 2; + + ret = video_->setFormat(&outputFormat); + if (ret) + return ret; + + return 0; +} + +int PipelineHandlerRkISP1::allocateBuffers(Camera *camera, Stream *stream) +{ + return video_->exportBuffers(&stream->bufferPool()); +} + +int PipelineHandlerRkISP1::freeBuffers(Camera *camera, Stream *stream) +{ + if (video_->releaseBuffers()) + LOG(RkISP1, Error) << "Failed to release buffers"; + + return 0; +} + +int PipelineHandlerRkISP1::start(Camera *camera) +{ + int ret; + + ret = video_->streamOn(); + if (ret) + LOG(RkISP1, Error) + << "Failed to start camera " << camera->name(); + + activeCamera_ = camera; + + return ret; +} + +void PipelineHandlerRkISP1::stop(Camera *camera) +{ + int ret; + + ret = video_->streamOff(); + if (ret) + LOG(RkISP1, Warning) + << "Failed to stop camera " << camera->name(); + + PipelineHandler::stop(camera); + + activeCamera_ = nullptr; +} + +int PipelineHandlerRkISP1::queueRequest(Camera *camera, Request *request) +{ + RkISP1CameraData *data = cameraData(camera); + Stream *stream = &data->stream_; + + Buffer *buffer = request->findBuffer(stream); + if (!buffer) { + LOG(RkISP1, Error) + << "Attempt to queue request with invalid stream"; + return -ENOENT; + } + + int ret = video_->queueBuffer(buffer); + if (ret < 0) + return ret; + + PipelineHandler::queueRequest(camera, request); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Match and Setup + */ + +int PipelineHandlerRkISP1::initLinks() +{ + MediaLink *link; + int ret; + + ret = media_->disableLinks(); + if (ret < 0) + return ret; + + link = media_->link("rockchip-sy-mipi-dphy", 1, "rkisp1-isp-subdev", 0); + if (!link) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret < 0) + return ret; + + link = media_->link("rkisp1-isp-subdev", 2, "rkisp1_mainpath", 0); + if (!link) + return -ENODEV; + + ret = link->setEnabled(true); + if (ret < 0) + return ret; + + return 0; +} + +int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) +{ + int ret; + + std::unique_ptr data = + utils::make_unique(this); + + data->sensor_ = new CameraSensor(sensor); + ret = data->sensor_->init(); + if (ret) + return ret; + + std::set streams{ &data->stream_ }; + std::shared_ptr camera = + Camera::create(this, sensor->name(), streams); + registerCamera(std::move(camera), std::move(data)); + + return 0; +} + +bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) +{ + int ret; + + DeviceMatch dm("rkisp1"); + dm.add("rkisp1-isp-subdev"); + dm.add("rkisp1_selfpath"); + dm.add("rkisp1_mainpath"); + dm.add("rkisp1-statistics"); + dm.add("rkisp1-input-params"); + dm.add("rockchip-sy-mipi-dphy"); + + media_ = enumerator->search(dm); + if (!media_) + return false; + + media_->acquire(); + + ret = media_->open(); + if (ret < 0) + return ret; + + /* Create the V4L2 subdevices we will need. */ + MediaEntity *dphy = media_->getEntityByName("rockchip-sy-mipi-dphy"); + dphy_ = new V4L2Subdevice(dphy); + ret = dphy_->open(); + if (ret < 0) + return ret; + + MediaEntity *isp = media_->getEntityByName("rkisp1-isp-subdev"); + isp_ = new V4L2Subdevice(isp); + ret = isp_->open(); + if (ret < 0) + return ret; + + /* Locate and open the capture video node. */ + video_ = new V4L2Device(media_->getEntityByName("rkisp1_mainpath")); + if (video_->open()) + return false; + + video_->bufferReady.connect(this, &PipelineHandlerRkISP1::bufferReady); + + /* Configure default links. */ + ret = initLinks(); + if (ret < 0) { + LOG(RkISP1, Error) << "Failed to setup links"; + return false; + } + + /* + * Enumerate all sensors connected to the CSI-2 receiver and create one + * camera instance for each of them. + */ + const MediaPad *pad = dphy->getPadByIndex(0); + if (!pad) { + ret = -EINVAL; + goto done; + } + + for (MediaLink *link : pad->links()) + createCamera(link->source()->entity()); + +done: + media_->close(); + + return ret == 0; +} + +/* ----------------------------------------------------------------------------- + * Buffer Handling + */ + +void PipelineHandlerRkISP1::bufferReady(Buffer *buffer) +{ + ASSERT(activeCamera_); + + RkISP1CameraData *data = cameraData(activeCamera_); + Request *request = data->queuedRequests_.front(); + + completeBuffer(activeCamera_, request, buffer); + completeRequest(activeCamera_, request); +} + +REGISTER_PIPELINE_HANDLER(PipelineHandlerRkISP1); + +} /* namespace libcamera */