From patchwork Thu Apr 18 14:14:25 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1048 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D4C3060DBE for ; Thu, 18 Apr 2019 16:14:53 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 735CE9A7 for ; Thu, 18 Apr 2019 16:14:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596893; bh=CUFVZNQfO/UhAvK/sOaxcRFRjHhHPh/vTLL5eIBCHc0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=DdUUdu4W9neC1B4AkPSmiSrpcIdWcnkTqXqh1ZdSnEYTZXXFmvc6ePbDbyr3KlNGe lA1ywhpS3qUQps20DJ3dzfZQXBhIaIzYDKN1reLrwdWzh/n1EaRsIDyK8vWYBwLZDs XrC4V+zeflwQZgEGBJ3phzYvYd7HMwVx16IWWM5w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:25 +0300 Message-Id: <20190418141437.14014-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:54 -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 Thu Apr 18 14:14:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 1049 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 4CBE460DBE for ; Thu, 18 Apr 2019 16:14:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D728B333 for ; Thu, 18 Apr 2019 16:14:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596894; bh=iwgyLW0MWnGp2TxvsW836wfzPZek82oY/7CT1iPNJy8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Yo3GHJ1qS5zYp0/9wjbgVRjhwrtpu6AtjyMn8qGAA6EOwx2qOwKX9uO6ZzkyA20xv UIrPwTHJDwBPCj7KyLal2Np3vnjJBfMkGi/un3KoVlPxOKKh6ZS0RlYcR6Su45KkDr hE7rH+11z76WhcJ8kOtfLyPm+Tm6P3AgmsghgWoA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:26 +0300 Message-Id: <20190418141437.14014-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:54 -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 Thu Apr 18 14:14: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: 1050 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A29AD60DBE for ; Thu, 18 Apr 2019 16:14:54 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 401FF9A7 for ; Thu, 18 Apr 2019 16:14:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596894; bh=Ny6jP45HuHVqIqIkP5dHZMgNKQnbd1VpGWNwzn2xLGY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=YKY+rCTR8NbYf+0x5rqhj1O1enmerC3d0RjKCGIrqR6j4PUASOWAPmFZFOLe74XCL nrDCdWXENaME93DqnqlEC4PeJqv+R+Agf8JOXQ+F4X4pFOVUYCmL9kJ9c6PkIFBeNj siTCY5mCVeSDQPluwKteYbvrvXCaLA/eXo9niwcc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:27 +0300 Message-Id: <20190418141437.14014-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:54 -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 75a21008070b..bd381fa1cb56 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 924eb46c58d8..f2306efba3bf 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -244,12 +244,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 Thu Apr 18 14:14: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: 1051 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 2214660DC9 for ; Thu, 18 Apr 2019 16:14:56 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A04F8333 for ; Thu, 18 Apr 2019 16:14:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596894; bh=3lLujraMWlCwqB0V7/9cBTs01fxkWVLer8n9Zz6khxA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=l4hCdK5cP2nEU0egU5ATRoU4iWHdea1f2m7It5QRfINWj1u5gszUbyQ2aqPAobTKN BY4kn7mcNEpaK2/PO0Kn+HKPPSUlSlE+h9olT8T4XqAAagNKq9i4V9tYZmN/cr9xTV KTLIl76pjSxPHS3Lm4Iflx+VBuoOZHFrOazJ4rc0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:28 +0300 Message-Id: <20190418141437.14014-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:57 -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 Thu Apr 18 14:14: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: 1052 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 83F0E60DC6 for ; Thu, 18 Apr 2019 16:14:56 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 07AB49D6 for ; Thu, 18 Apr 2019 16:14:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596896; bh=OGux1LxX1DkklAo1PNNeUYQrQHDpjDw+WM73yR2TIYA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=oxk5PrFv8q3BS1sbAGjnwKQ81812sP4d+NBrOEhaNna+m8mSQXiEW9isj0lZWHtwg GlffbIkUDPfsEn19XnEiveQciLNg7XZagdqMk0LtF3JRKGUL7zfD0GlOMYAiHJPrC0 2c1Yyrt91WI0bGdK17rVpv1K5qT3rBXqXAJlz7iM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:29 +0300 Message-Id: <20190418141437.14014-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:57 -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 f2306efba3bf..fb9ee0af6c3a 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -1058,10 +1058,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; } } @@ -1116,19 +1115,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 Thu Apr 18 14:14: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: 1053 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 F0C5160DC7 for ; Thu, 18 Apr 2019 16:14:56 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 83E28B85 for ; Thu, 18 Apr 2019 16:14:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596896; bh=5YdKs5SiFvFQkq7ZVXFBkrtwDRPewHOgP5TYywDlDIs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kqnCF5BZWAynBeEkXdJUbtupEKWX+IkHkiKu8pFv4czfmhx3v6XOQ6RujZkqaFpUx byc2jEoK0WDXGwf3YZvfk/ANdYGt9lP/MmFcL/huGHWshp0O8cUjGdP65TogzYZHrh KV+ZtGP1r6sPjctJ9erVhJoBIlK/QpyPhhS+Uvjo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:30 +0300 Message-Id: <20190418141437.14014-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:57 -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 Thu Apr 18 14:14: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: 1054 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 508CB60DC6 for ; Thu, 18 Apr 2019 16:14:57 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E60A09A7 for ; Thu, 18 Apr 2019 16:14:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596897; bh=cFvDd/CCqAepMcjnOcsvoqbRzt6gHKhXQuEPicQH/eA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=KTVUPCGsO8AMamXwsxGIxPQ8Rpopx4tUSwpPSItoGkgIuGXQZ6Zf/vODaO1KPqdSi z91zSICEopaK9qqK/8uog6j1MB8aFMVvTjGDTcO69lBLBsoy3FktgVS22tA/n3/PL7 gG28J5L0GLGG9PBD3Q3BywOKcM4WNzqNWX/nGHlg= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:31 +0300 Message-Id: <20190418141437.14014-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:57 -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 Thu Apr 18 14:14: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: 1055 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 BAA2C60DC6 for ; Thu, 18 Apr 2019 16:14:57 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4F469333 for ; Thu, 18 Apr 2019 16:14:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596897; bh=bWh0/QPbU0r4kITQv6ooxGQ4yRXLQO/1DRYUJh5+T0Q=; h=From:To:Subject:Date:In-Reply-To:References:From; b=AK4LzH7qU0kgLhlEGKPMIoneUXqIIYyYlCTkClswnuVgXoEVh3/qRCO/r6tIRLfFE /6x2lzt11bNhHftRPXnkmgm8kvGa9B1irZZA/UBR36LB67TfmsTKBRU4PBNjMCAXBQ kHXjt7EjEYLPkND78ncE6N62p9DzJsCZo5VhaZig= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:32 +0300 Message-Id: <20190418141437.14014-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:14:58 -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 Thu Apr 18 14:14: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: 1056 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 30E5C60DDC for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AFD2B9A7 for ; Thu, 18 Apr 2019 16:14:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596897; bh=/HOFiTfjXrNuaK6WbexcRsw61u3GR7weSKjD8dBPiYY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Q35yhMVXa0IyvyMoLlkJ2hTd1Cwff2b1cqa+o7FQTb1vNDnwUrbGZyaoP/shzNSiY wW9IQ5SU+Bf6qCHug0PzDEubB49R67NErGUnI1ZpGfh0Qrien7j0adEwxNsOWd3cpH W+7ukla3x46Y47r3GyroxlwvF75JP802MwVICb0M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:33 +0300 Message-Id: <20190418141437.14014-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:15:00 -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 Thu Apr 18 14:14: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: 1057 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 8BD5A60DD9 for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 20C9F333 for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596898; bh=ILRE3jes+SJol1CGWD4Buu8u4PvudE83VpUzdZPq0RE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=In6+5lGQ6Yre5akwBqBiQWNP+QzIZDJMrryj70JKJ4O28PEUSPdFaC2lrv8JQ7JrA hYd2uvSrVkeRVaH2HxCeQC8B/3xM3hmiFRxcXSW5oZSbn6mkx8xAztB1wJiPlZqZ3O eMkxRpLJ3NyElbx6ulT0d2Q1UcrF5rus/5idGtNY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:34 +0300 Message-Id: <20190418141437.14014-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:15:00 -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 fb9ee0af6c3a..f43969099b48 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -590,7 +590,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, @@ -1066,7 +1066,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 Thu Apr 18 14:14: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: 1058 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F10FD60DCC for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8075A9D6 for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596898; bh=KuiuGC3BtLU7nlLQG9RL+BKdzoQ7+Gw34/lM9hw3dyk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=d83OPYdovefeqjkBodNrGdRlMLguwDE91oId/viaByI5Ro+g5rUTTCpg4zgtHzLZ9 uU3lRF+KeV+UD+cOH7Gb2v8KZCUfTwWADrT+T1IZ5IPZ43D+O036FgVCqbAPr18Cep llXXhbQLwketX+6BjkTdHMFHka2W3w2mKHYKn/WM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:35 +0300 Message-Id: <20190418141437.14014-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:15:00 -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 Reviewed-by: Jacopo Mondi --- 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 Thu Apr 18 14:14: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: 1059 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5340660DC7 for ; Thu, 18 Apr 2019 16:14:59 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E5C35B85 for ; Thu, 18 Apr 2019 16:14:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596899; bh=2T13HuQWuqQbpNPNwWxSXU2xV147Zj4zVVhqREiXTQg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pZb/oRZdkryrYecU09r7l40evC2jGRxZycG3Fhn4JMgjxrXWsE6dQrEQXnMeihe/K iMQx0qgbDv4m+xHGzgssqiLsrhZrsakaeuJo1pK9kHdQX6c+ccaJc2XFqW0G1jH8AI RoSXIEHLeBdno/U/SOVjYm7fxA4Wn+JBNF0+7IjA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:36 +0300 Message-Id: <20190418141437.14014-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:15:00 -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 Reviewed-by: Jacopo Mondi --- Changes since v2: - Properly sort the CIO2 supported media bus codes numerically 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 f43969099b48..c677ee9b51da 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_; }; @@ -257,8 +255,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; @@ -1032,45 +1031,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_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_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(); @@ -1096,47 +1089,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 Thu Apr 18 14:14: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: 1060 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 226DB60DC7 for ; Thu, 18 Apr 2019 16:15:01 +0200 (CEST) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5024B9A7 for ; Thu, 18 Apr 2019 16:14:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555596899; bh=Oc8bWdtL7H/DSERhkhqsBsw/gptpde7IfBXrAYRSsog=; h=From:To:Subject:Date:In-Reply-To:References:From; b=OUPuZ+sf41himYKYzT47ajyS1h06xxE6GFy1Bt0WU4/Uer3UvxgfxPCeOzxc+geKp IgaWzG/s494Q8m6z05BiLS6zFCVTShlEDJ8RPeXHxvtSDEDNNU1/PbLctD7aE+Fzrx cxI/g+8JNWN6q0dWmibLddGr+DObMKY5HLZpbb3M= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Thu, 18 Apr 2019 17:14:37 +0300 Message-Id: <20190418141437.14014-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> References: <20190418141437.14014-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 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: Thu, 18 Apr 2019 14:15:01 -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 Reviewed-by: Jacopo Mondi --- Changes since v2: - Print the format configured at the sensor output - Close the media device when match() fails - Use V4L2Subdevice::fromEntityName() and V4L2Device::fromEntityName() - Rebased on top of the multi-stream preparation commits 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 | 448 ++++++++++++++++++++++ 3 files changed, 452 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..71faa880db49 --- /dev/null +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -0,0 +1,448 @@ +/* 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, + const std::set &streams) override; + int freeBuffers(Camera *camera, + const std::set &streams) 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 with " << format.toString(); + + ret = sensor->setFormat(&format); + if (ret < 0) + return ret; + + LOG(RkISP1, Debug) << "Sensor configured with " << format.toString(); + + 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; + + if (outputFormat.width != cfg.width || + outputFormat.height != cfg.height || + outputFormat.fourcc != V4L2_PIX_FMT_NV12) { + LOG(RkISP1, Error) + << "Unable to configure capture in " << cfg.width + << "x" << cfg.height << "-NV12"; + return -EINVAL; + } + + return 0; +} + +int PipelineHandlerRkISP1::allocateBuffers(Camera *camera, + const std::set &streams) +{ + Stream *stream = *streams.begin(); + return video_->exportBuffers(&stream->bufferPool()); +} + +int PipelineHandlerRkISP1::freeBuffers(Camera *camera, + const std::set &streams) +{ + 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) +{ + const MediaPad *pad; + 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. */ + dphy_ = V4L2Subdevice::fromEntityName(media_.get(), + "rockchip-sy-mipi-dphy"); + ret = dphy_->open(); + if (ret < 0) + goto done; + + isp_ = V4L2Subdevice::fromEntityName(media_.get(), "rkisp1-isp-subdev"); + ret = isp_->open(); + if (ret < 0) + goto done; + + /* Locate and open the capture video node. */ + video_ = V4L2Device::fromEntityName(media_.get(), "rkisp1_mainpath"); + ret = video_->open(); + if (ret < 0) + goto done; + + video_->bufferReady.connect(this, &PipelineHandlerRkISP1::bufferReady); + + /* Configure default links. */ + ret = initLinks(); + if (ret < 0) { + LOG(RkISP1, Error) << "Failed to setup links"; + goto done; + } + + /* + * Enumerate all sensors connected to the CSI-2 receiver and create one + * camera instance for each of them. + */ + pad = dphy_->entity()->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 */