From patchwork Mon Apr 15 16:56:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 982 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 622D960DBF for ; Mon, 15 Apr 2019 18:57:14 +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 DF898B81 for ; Mon, 15 Apr 2019 18:57:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347434; bh=d/bTABQ0WxrOAndOTIFFl13Ukb5J/m5peNUZU2TU4dQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=dLfl5wlJSyXEMQX2O7n4lS0nCBNc8xeFej+TsOD+h0ur6lYYZ5hKQIE/WxNXlo35n VW73jLNaZTltgjx6L+mtFfiYqipZgyni6ylpm2gNrJjHcJIYkR9h+yHfYprmnMLHXt YoaQgxhxckQo1ZYdk6Dueo9hyi8BYI5eHHUMQHtE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:50 +0300 Message-Id: <20190415165700.22970-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/11] 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: Mon, 15 Apr 2019 16:57:14 -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 Mon Apr 15 16:56:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 983 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 C651A60DBF for ; Mon, 15 Apr 2019 18:57:14 +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 5C877333 for ; Mon, 15 Apr 2019 18:57:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347434; bh=dpMsSqVFr8uPm2fOOOAPDZdVkcjiYIyorTtBVSGEX48=; h=From:To:Subject:Date:In-Reply-To:References:From; b=wMSd1w9oanXfqvO3Xh7I/FX0/1cFK3ltG3RXliH9eAwzou96NdWEL7lb03Y2Kj6n5 dm8RvsAmbrysy2DgKkxnt6mDrLiJlGUSBZbNVrVQn2twnFj/ra+TgcHq/7GdRDiRmm nS+vQJRLDpXUzcWpUK9T8x3/ZJrP3cNYovGS1yDk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:51 +0300 Message-Id: <20190415165700.22970-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/11] 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: Mon, 15 Apr 2019 16:57:15 -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 Mon Apr 15 16:56:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 984 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3287760DBF for ; Mon, 15 Apr 2019 18:57:15 +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 BACA0B81 for ; Mon, 15 Apr 2019 18:57:14 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347434; bh=gk+2Z40UM/TXch3cDOWs9HuvY8eoi8m5fC3GTHxIld0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Btg9B1nAAnDBog3IToivJC4EIoBu1JNu9e11hImXgqgGxzSVoV7SEqE+uzi69edo3 qvwNUJ2UGRMsrmv/lvMPhmZG8T8yh2UyEUWn8MjqwDnQEJbXwp7VDOoO+ZlckyjJSQ rIVq4eYrZQ/bvrOo6reEZXIDtgdLtCfIKOtqQa6U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:52 +0300 Message-Id: <20190415165700.22970-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/11] 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: Mon, 15 Apr 2019 16:57:17 -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 Mon Apr 15 16:56:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 985 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 9339160DC5 for ; Mon, 15 Apr 2019 18:57:15 +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 2948A333 for ; Mon, 15 Apr 2019 18:57:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347435; bh=QLmAgOOBJVx6S+WNAS8PF9P2lAPAMIUz9033cnxeVd0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=YAjLhx/K3okfXgGxcU1GXp0sNZNPun5Cnx16anoi/NkW62acr62Dy754k6KOCiECi eC/aFdFrYCvSttHeLfYOGNnuW2rVlKK6DsgvgPCQk7PuHUPRYfsKMxbaCWAx8Nqbai iBV1gMr0c8kKlg1ycwO+JlRMG7SR1I+Z5eBlbt3I= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:53 +0300 Message-Id: <20190415165700.22970-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/11] 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: Mon, 15 Apr 2019 16:57:17 -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 Mon Apr 15 16:56:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 986 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id EDC4860DCB for ; Mon, 15 Apr 2019 18:57:15 +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 88F7EB81 for ; Mon, 15 Apr 2019 18:57:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347435; bh=QHeBinlR4NTTDjFxMTfivZ74CUVah9VPVkdkZ2VqHdM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Znt14mxdU4xHDdxwrfXdkyPWJEa0tV1MjWBD9gAev6tovxy9MJ9S/naaP9VrW6JII RHLjAZ4m8uDYzeD25gBp4JVl5HVPewlQ2weQZ2GrTQhlMFCji6Nu3zzqWhUr2LDD9A BYObJs5dB/MCIdWRgu/BUly8n6wmTEkahQLhg0Ys= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:54 +0300 Message-Id: <20190415165700.22970-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/11] 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: Mon, 15 Apr 2019 16:57:17 -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 Mon Apr 15 16:56:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 987 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 77BEE60DC1 for ; Mon, 15 Apr 2019 18:57:16 +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 E76DB333 for ; Mon, 15 Apr 2019 18:57:15 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347436; bh=ovhaqq34QoTOi/qg9DDjQZfuPQbPoYVh6USwqqUEwR0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Rr7NQFCoqL6vdGkHpvd4oe1rkKfs3Gh+/lPseB6+Y9G6LgLtBVk9tpR1vxwV5D7Dq sC6dxu5ZbIQbEpRKik7Uws7NJ6msDxQvBpvkfzeD+tvjpie9uB4Hz7N7IVcF6+reY5 peFEGRd3M27UVZvNGjdOWtDPv6LHnuVWdBGpIuXI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:55 +0300 Message-Id: <20190415165700.22970-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/11] 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: Mon, 15 Apr 2019 16:57:17 -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 --- include/libcamera/geometry.h | 35 ++++++++++++ src/libcamera/geometry.cpp | 102 +++++++++++++++++++++++++++++++++++ 2 files changed, 137 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..7b65e63f2ebd 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,76 @@ 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 the left hand size is smaller than the right hand size, 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 the left hand size is smaller than or equal to the right + * hand size, 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 the left hand size is greater than the right hand size, + * 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 the left hand size is greater than or equal to the right + * hand size, false otherwise + * \sa bool operator<(const Size &lhs, const Size &rhs) + */ + /** * \struct SizeRange * \brief Describe a range of sizes @@ -124,4 +211,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 Mon Apr 15 16:56:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 988 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 EB32860DCC for ; Mon, 15 Apr 2019 18:57:16 +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 81180B81 for ; Mon, 15 Apr 2019 18:57:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347436; bh=3xVTvaBVOA4Plyd3pIxARfd1JmMrOkx92cNZikTLFUg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FCDa2Lz0/QsSqTfwHd1OsFxlHaKCWIhVV7go/Prhl+0LSWNVNVviVDDiazaK0olYc 4N2T/HI/tEQM0v4UkRbs3a/cm0RLZeYydNIKI/2zHyXrGRfBPApDQLs/+cf6OIU5JC 9lcwYcnvp1p6mNOc3ZWDGJ0K8Fxn7cFClrjZU4/o= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:56 +0300 Message-Id: <20190415165700.22970-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/11] 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: Mon, 15 Apr 2019 16:57:17 -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 --- test/geometry.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 126 insertions(+) create mode 100644 test/geometry.cpp diff --git a/test/geometry.cpp b/test/geometry.cpp new file mode 100644 index 000000000000..7ba3f72ed71d --- /dev/null +++ b/test/geometry.cpp @@ -0,0 +1,125 @@ +/* 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: + int init() + { + return 0; + } + + 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; + } + + void cleanup() + { + } +}; + +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 Mon Apr 15 16:56:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 989 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 4B5EB60DCD for ; Mon, 15 Apr 2019 18:57:17 +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 DFD82D82 for ; Mon, 15 Apr 2019 18:57:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347437; bh=dOgeYcAcLpZS9dLxPjaI9sVH6kP4eFSJllxtR6uNn+c=; h=From:To:Subject:Date:In-Reply-To:References:From; b=mtyuliQijBnx3S+Nsiju/jh0MHxdy1T/K+f4osr73XCglE8vdiNALBuRO8Nq7TCDQ 5noCKNnzdSwRAKW7T0tmMGL7EA4TQs3cPXVI3S5fiuLBgETo/3AW3tRgmIf8BE9sMh bs3EiLvXqxs4ma0CaIPJba0N19jsWJYAmU6BALzk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:57 +0300 Message-Id: <20190415165700.22970-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/11] 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: Mon, 15 Apr 2019 16:57:17 -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 --- 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 c71dce7d8644..31bc9d298e5b 100644 --- a/src/libcamera/include/v4l2_subdevice.h +++ b/src/libcamera/include/v4l2_subdevice.h @@ -40,8 +40,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 e34cc1693b46..6b2d7cce6794 100644 --- a/src/libcamera/v4l2_subdevice.cpp +++ b/src/libcamera/v4l2_subdevice.cpp @@ -126,12 +126,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; @@ -161,17 +161,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. */ /** @@ -338,7 +330,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 Mon Apr 15 16:56:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 990 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B56EC60DD2 for ; Mon, 15 Apr 2019 18:57:17 +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 4B5AAB81 for ; Mon, 15 Apr 2019 18:57:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347437; bh=Bz9Y9H3jLPNExSqP/LWu0BK/tiWD/ZAFjREnFp0JTIg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ZAkMY5MLb24Gm630kZPLskzSJz9PSK4xaDQVqqI1Lkr0b/B1+a5YpVmJYSx3BLaGH ltiJZoILXXR8liuFPuIXqfAeIRt3JW47dgzGcr1y5Z5AycY0gen3+nahyP5ULWr9sL n90WPg9vQoogodTTw93iLvqE5BvbpFI3LtPFKmX8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:58 +0300 Message-Id: <20190415165700.22970-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/11] 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: Mon, 15 Apr 2019 16:57:18 -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 --- src/libcamera/camera_sensor.cpp | 245 ++++++++++++++++++++++++++ src/libcamera/include/camera_sensor.h | 56 ++++++ src/libcamera/meson.build | 2 + 3 files changed, 303 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..aca9e77fd986 --- /dev/null +++ b/src/libcamera/camera_sensor.cpp @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2019, Google Inc. + * + * camera_sensor.cpp - A camera sensor + */ + +#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 + * + * 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 for 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 methods perform 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" + << std::endl; + 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" << std::endl; + return -EINVAL; + } + + std::transform(formats.begin(), formats.end(), + std::back_inserter(mbusCodes_), + [](decltype(*formats.begin()) f) { return f.first; }); + + const std::vector &sizes = formats.begin()->second; + std::transform(sizes.begin(), sizes.end(), std::back_inserter(sizes_), + [](const SizeRange &range) { return range.max; }); + + /* + * Verify the assumption that all available media bus codes support the + * same frame sizes. + */ + for (auto it = ++formats.begin(); it != formats.end(); ++it) { + if (it->second != sizes) { + LOG(CameraSensor, Error) + << "Frame sizes differ between media bus codes" + << std::endl; + return -EINVAL; + } + } + + /* Sort the sizes. */ + 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 + */ + +/** + * \fn CameraSensor::sizes() + * \brief Retrieve the frame sizes supported by the camera sensor + * \return The supported frame sizes + */ + +/** + * \fn CameraSensor::resolution() + * \brief Retrieve the camera sensor resolution + * \return The camera sensor resolution in pixels + */ + +/** + * \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" << std::endl; + 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" << std::endl; + 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..7d92af05248c --- /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" +#include "v4l2_subdevice.h" + +namespace libcamera { + +class MediaEntity; +class V4L2SubdeviceFormat; + +class CameraSensor : public 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 { return sizes_.back(); } + + 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 Mon Apr 15 16:56:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 991 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1A02060DCD for ; Mon, 15 Apr 2019 18:57:18 +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 AAB39333 for ; Mon, 15 Apr 2019 18:57:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347437; bh=d5n1IDYL+g4wIEsKjbsQrvWlYR4aMV37xjBq86RQpQs=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UYVhJakjJdZRg7Q49xR+rZ5c+0Yy62EtsO/ouyrH2OE1yXO9HnAS37FRtLT/vMe+b nW6pAhNyEHq2uyJMfDXFhrDCSJmAaHHPN9gVU8H5CZN7jB7lJ5sI36o5MqJjUhMUwU 6h49yKGycHJRzasr6lijWRHnG1z9mUjAFI9vIn+w= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:56:59 +0300 Message-Id: <20190415165700.22970-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/11] 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: Mon, 15 Apr 2019 16:57:20 -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 --- src/libcamera/pipeline/ipu3/ipu3.cpp | 78 +++++----------------------- 1 file changed, 14 insertions(+), 64 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index e3c79f93963e..1326a1be105f 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -15,6 +15,7 @@ #include #include +#include "camera_sensor.h" #include "device_enumerator.h" #include "log.h" #include "media_device.h" @@ -124,11 +125,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 +252,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; @@ -1036,31 +1034,11 @@ int CIO2Device::init(const MediaDevice *media, unsigned int index) * \todo Define when to open and close video device nodes, as they * might impact on power consumption. */ - sensor_ = new V4L2Subdevice(sensorEntity); - ret = sensor_->open(); + sensor_ = new CameraSensor(sensorEntity); + ret = sensor_->init(); 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(); if (ret) @@ -1085,47 +1063,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 Mon Apr 15 16:57:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 992 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8850860DCB for ; Mon, 15 Apr 2019 18:57:18 +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 1958CB81 for ; Mon, 15 Apr 2019 18:57:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1555347438; bh=xDOV2cq+pgHPWcXNN6HUC7P+143izrgd8HAazKxVa9o=; h=From:To:Subject:Date:In-Reply-To:References:From; b=mZCso7vAgK3ez9sZknOPWS8w6EnGmZ47Z/ZW+Adal5Ot8jeQjmgWEKQaKFUCv1nrT wlUadw4Tt/IgCb16oHaxPey9MVgjXxXvflDyBg+n4v4ZkTygvlkKP+aJdBqCknS9rr suK2U0cYDlzGom0P0Wc2/AvDKNDj/WMybrgki+UM= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 15 Apr 2019 19:57:00 +0300 Message-Id: <20190415165700.22970-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> References: <20190415165700.22970-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/11] 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: Mon, 15 Apr 2019 16:57:20 -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 --- 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..887c879d9024 --- /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, 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)); + 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; + + LOG(RkISP1, Debug) + << "Configured pipeline for " << format.toString() << " -> " + << outputFormat.toString(); + + 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()) { + /* + * A sensor is expected to have a single pad and expose the + * SENSOR function. This is overly restrictive, a better logic + * is needed to support sensor that expose multiple subdevs. + * + * \todo Create a helper to identify sensors + */ + MediaEntity *sensor = link->source()->entity(); + if (!sensor) + continue; + if (sensor->pads().size() != 1) + continue; + if (sensor->function() != MEDIA_ENT_F_CAM_SENSOR) + continue; + + createCamera(sensor); + } + +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 */