From patchwork Wed Jul 17 10:09:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20687 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id D4F98BDB1C for ; Wed, 17 Jul 2024 10:09:36 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5DCA963380; Wed, 17 Jul 2024 12:09:31 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="GnvCoUfN"; dkim-atps=neutral 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 921C66336F for ; Wed, 17 Jul 2024 12:09:27 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7CF32ABE; Wed, 17 Jul 2024 12:08:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210929; bh=oS1K5mHbfgZ71VXWbywrJkWoZXwEDojw9t/G+Go1imc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GnvCoUfN0k0cBkxWs4DT1uYFebRH9cAFPE1LCeCWXJ+DkukYmxKfbiKkYVzaJGXAe JFJORwMXi0YnXY78fcVK0ogWXPQtSKVa2LLzvsiZlVjmVygTdUA3iCBEq7GE4aB6U+ 6ViOCnsssy6PVT3YrXj02vWLiJM+3dfPGMKl5i88= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 1/9] libcamera: converter: Add interface for feature flags Date: Wed, 17 Jul 2024 12:09:04 +0200 Message-ID: <20240717100913.16640-2-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Umang Jain This patch intends to extend the converter interface to have feature flags, which enables each converter to expose the set of features it supports. Signed-off-by: Umang Jain Signed-off-by: Kieran Bingham --- include/libcamera/internal/converter.h | 13 ++++++++++- .../internal/converter/converter_v4l2_m2m.h | 2 +- src/libcamera/converter.cpp | 22 ++++++++++++++++++- .../converter/converter_v4l2_m2m.cpp | 5 +++-- 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h index b51563d7ca6a..7e4783566a44 100644 --- a/include/libcamera/internal/converter.h +++ b/include/libcamera/internal/converter.h @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -32,7 +33,13 @@ struct StreamConfiguration; class Converter { public: - Converter(MediaDevice *media); + enum class Feature { + None = 0, + }; + + using Features = Flags; + + Converter(MediaDevice *media, Features features = Feature::None); virtual ~Converter(); virtual int loadConfiguration(const std::string &filename) = 0; @@ -61,8 +68,12 @@ public: const std::string &deviceNode() const { return deviceNode_; } + Features getFeatures() const { return features_; } + private: std::string deviceNode_; + + Features features_; }; class ConverterFactoryBase diff --git a/include/libcamera/internal/converter/converter_v4l2_m2m.h b/include/libcamera/internal/converter/converter_v4l2_m2m.h index b9e59899ee2b..91701dbed58d 100644 --- a/include/libcamera/internal/converter/converter_v4l2_m2m.h +++ b/include/libcamera/internal/converter/converter_v4l2_m2m.h @@ -35,7 +35,7 @@ class V4L2M2MDevice; class V4L2M2MConverter : public Converter { public: - V4L2M2MConverter(MediaDevice *media); + V4L2M2MConverter(MediaDevice *media, Features features = Feature::None); int loadConfiguration([[maybe_unused]] const std::string &filename) { return 0; } bool isValid() const { return m2m_ != nullptr; } diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp index 2ab461332677..2c3da6d4502b 100644 --- a/src/libcamera/converter.cpp +++ b/src/libcamera/converter.cpp @@ -34,14 +34,27 @@ LOG_DEFINE_CATEGORY(Converter) * parameters from the same input stream. */ +/** + * \enum Converter::Feature + * \brief Specify the features supported by the converter + * \var Converter::Feature::None + * \brief No extra features supported by the converter + */ + +/** + * \typedef Converter::Features + * \brief A bitwise combination of features supported by the converter + */ + /** * \brief Construct a Converter instance * \param[in] media The media device implementing the converter + * \param[in] features Features flags representing supported features * * This searches for the entity implementing the data streaming function in the * media graph entities and use its device node as the converter device node. */ -Converter::Converter(MediaDevice *media) +Converter::Converter(MediaDevice *media, Features features) { const std::vector &entities = media->entities(); auto it = std::find_if(entities.begin(), entities.end(), @@ -56,6 +69,7 @@ Converter::Converter(MediaDevice *media) } deviceNode_ = (*it)->deviceNode(); + features_ = features; } Converter::~Converter() @@ -163,6 +177,12 @@ Converter::~Converter() * \return The converter device node string */ +/** + * \fn Converter::getFeatures() + * \brief Gets the supported features by the converter + * \return The converter Features flag + */ + /** * \class ConverterFactoryBase * \brief Base class for converter factories diff --git a/src/libcamera/converter/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp index 2e77872e1710..4aeb7dd93676 100644 --- a/src/libcamera/converter/converter_v4l2_m2m.cpp +++ b/src/libcamera/converter/converter_v4l2_m2m.cpp @@ -191,10 +191,11 @@ void V4L2M2MConverter::V4L2M2MStream::captureBufferReady(FrameBuffer *buffer) * \fn V4L2M2MConverter::V4L2M2MConverter * \brief Construct a V4L2M2MConverter instance * \param[in] media The media device implementing the converter + * \param[in] features Features flags representing supported features */ -V4L2M2MConverter::V4L2M2MConverter(MediaDevice *media) - : Converter(media) +V4L2M2MConverter::V4L2M2MConverter(MediaDevice *media, Features features) + : Converter(media, features) { if (deviceNode().empty()) return; From patchwork Wed Jul 17 10:09:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20688 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id AF96FBDB1C for ; Wed, 17 Jul 2024 10:09:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E97D263375; Wed, 17 Jul 2024 12:09:32 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AhPT1u5U"; dkim-atps=neutral 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 C7C5163371 for ; Wed, 17 Jul 2024 12:09:27 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D3CF4836; Wed, 17 Jul 2024 12:08:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210930; bh=kcOAEenvH7G/QTCGDRqLsI+p61DJqTiO4QTbx/2+Xbg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AhPT1u5U+lgCRV0cDyWXLdcmWVGvEYO53DicEw8jM5bActGCKyQ8354nq+biXw/ZF TjDyUxFD+wHqdN43l8ZrAeOTW74NnsbkWSAbEx5Pa98QIm3RgU6PKeybLPnJjqnZcL fUBTxT4bfVS4UXiy/gUx6q9rSKJK4JkNYy1FIMVI= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 2/9] fixup: Add Features at Converter registration time Date: Wed, 17 Jul 2024 12:09:05 +0200 Message-ID: <20240717100913.16640-3-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Jacopo Mondi --- include/libcamera/internal/converter.h | 23 +++++++++++++---------- src/libcamera/converter.cpp | 10 ++++++---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h index 7e4783566a44..ead465170d01 100644 --- a/include/libcamera/internal/converter.h +++ b/include/libcamera/internal/converter.h @@ -39,7 +39,7 @@ public: using Features = Flags; - Converter(MediaDevice *media, Features features = Feature::None); + Converter(MediaDevice *media, Features features); virtual ~Converter(); virtual int loadConfiguration(const std::string &filename) = 0; @@ -68,21 +68,22 @@ public: const std::string &deviceNode() const { return deviceNode_; } - Features getFeatures() const { return features_; } + Features features() const { return features_; } private: std::string deviceNode_; - Features features_; }; class ConverterFactoryBase { public: - ConverterFactoryBase(const std::string name, std::initializer_list compatibles); + ConverterFactoryBase(const std::string name, std::initializer_list compatibles, + Converter::Features feat); virtual ~ConverterFactoryBase() = default; const std::vector &compatibles() const { return compatibles_; } + const Converter::Features features() const { return features_; } static std::unique_ptr create(MediaDevice *media); static std::vector &factories(); @@ -93,28 +94,30 @@ private: static void registerType(ConverterFactoryBase *factory); - virtual std::unique_ptr createInstance(MediaDevice *media) const = 0; + virtual std::unique_ptr createInstance(MediaDevice *media, Converter::Features feat) const = 0; std::string name_; std::vector compatibles_; + Converter::Features features_; }; template class ConverterFactory : public ConverterFactoryBase { public: - ConverterFactory(const char *name, std::initializer_list compatibles) - : ConverterFactoryBase(name, compatibles) + ConverterFactory(const char *name, std::initializer_list compatibles, Converter::Features feat) + : ConverterFactoryBase(name, compatibles, feat) { } - std::unique_ptr createInstance(MediaDevice *media) const override + std::unique_ptr createInstance(MediaDevice *media, Converter::Features feat) const override { - return std::make_unique<_Converter>(media); + return std::make_unique<_Converter>(media, feat); } }; #define REGISTER_CONVERTER(name, converter, compatibles) \ - static ConverterFactory global_##converter##Factory(name, compatibles); + static ConverterFactory global_##converter##Factory(name, compatibles, \ + Converter::Feature::None); } /* namespace libcamera */ diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp index 2c3da6d4502b..dcbc442ccf68 100644 --- a/src/libcamera/converter.cpp +++ b/src/libcamera/converter.cpp @@ -178,7 +178,7 @@ Converter::~Converter() */ /** - * \fn Converter::getFeatures() + * \fn Converter::features() * \brief Gets the supported features by the converter * \return The converter Features flag */ @@ -209,8 +209,10 @@ Converter::~Converter() * The factory \a compatibles holds a list of driver names implementing a generic * subsystem without any personalizations. */ -ConverterFactoryBase::ConverterFactoryBase(const std::string name, std::initializer_list compatibles) - : name_(name), compatibles_(compatibles) +ConverterFactoryBase::ConverterFactoryBase(const std::string name, + std::initializer_list compatibles, + Converter::Features feat) + : name_(name), compatibles_(compatibles), features_(feat) { registerType(this); } @@ -247,7 +249,7 @@ std::unique_ptr ConverterFactoryBase::create(MediaDevice *media) << factory->name_ << " factory with " << (it == compatibles.end() ? "no" : media->driver()) << " alias."; - std::unique_ptr converter = factory->createInstance(media); + std::unique_ptr converter = factory->createInstance(media, factory->features()); if (converter->isValid()) return converter; } From patchwork Wed Jul 17 10:09:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20689 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id AA50ABDB1C for ; Wed, 17 Jul 2024 10:09:41 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 3BB9663383; Wed, 17 Jul 2024 12:09:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="C7BTKLe6"; dkim-atps=neutral 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 2BE6C63369 for ; Wed, 17 Jul 2024 12:09:28 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 34768ABE; Wed, 17 Jul 2024 12:08:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210930; bh=xqXoeB7ybBMidkZKEB9nnUbEtQ8XMotOtU/aedcAEG8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C7BTKLe6ATdgIf/BcQBeWmmD+zmzS3tWspxCj8tQaGCOPc4WW2c9nlLeX63ZsOSQe lO0fUiPmhkGgZYfE1Gej3Xa91es/T8tnOEkuEVtWC010EAnd4xJRKBh7CXurIiOciL Hy4BBrg9IjhlrbfaS55uGo8Ap8kJ3JwB6Se6BKfg= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 3/9] libcamera: converter: Allow registering with feature Date: Wed, 17 Jul 2024 12:09:06 +0200 Message-ID: <20240717100913.16640-4-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Provide a way to overload the REGISTER_CONVERTER() macro to allow it to be called with or without an optional set of features. Signed-off-by: Jacopo Mondi --- include/libcamera/internal/converter.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h index ead465170d01..035e6ffff135 100644 --- a/include/libcamera/internal/converter.h +++ b/include/libcamera/internal/converter.h @@ -116,8 +116,17 @@ public: } }; -#define REGISTER_CONVERTER(name, converter, compatibles) \ +#define __REGISTER_CONVERTER(name, converter, compatibles, features) \ static ConverterFactory global_##converter##Factory(name, compatibles, \ - Converter::Feature::None); + features); +#define __REGISTER_CONVERTER_NO_FEAT(name, converter, compatibles) \ + __REGISTER_CONVERTER(name, converter, compatibles, Converter::Feature::None); + +#define __register_converter_expand(_1, _2, _3, _4, EXT, ...) \ + __REGISTER_CONVERTER ## EXT + +#define REGISTER_CONVERTER(name, converter, compatibles, ...) \ + __register_converter_expand(name, converter, compatibles, ##__VA_ARGS__, , _NO_FEAT) \ + (name, converter, compatibles, ##__VA_ARGS__) } /* namespace libcamera */ From patchwork Wed Jul 17 10:09:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20690 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5FB01BDB1C for ; Wed, 17 Jul 2024 10:09:43 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 826ED63379; Wed, 17 Jul 2024 12:09:36 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="fTqaUuyz"; dkim-atps=neutral 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 7B8B663374 for ; Wed, 17 Jul 2024 12:09:28 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 89879836; Wed, 17 Jul 2024 12:08:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210930; bh=+sV3jnHH0zuPWm6+x2xDvVhM87TtHLe/8Y057n8kI3g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fTqaUuyzv48epVqWgWcXGhgZ80UOS0Up/eEdCjGxf8nfXsMUz2CAF2b26rp4AyMbJ cYEF40NN3/vzTMS+HZO5PEDcjv04K8P40L0jK/QLb4d1al31Zdtg0qbhpgoBhPC4aj rbVRZqXflRq7xOApiHW7jC6rpr/yVRRx73vZ62GA= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 4/9] libcamera: converter: Add interface to support cropping capability Date: Wed, 17 Jul 2024 12:09:07 +0200 Message-ID: <20240717100913.16640-5-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Umang Jain If the converter has cropping capability, the interface should support it by providing appropriate virtual functions. Provide Feature::Crop in Feature enumeration for the same. Provide virtual setCrop() and getCropBounds() interfaces so that the converter can implement their own cropping functionality. The V4L2M2MConverter implements these interfaces of the Converter interface. Not all V4L2M2M converters will have cropping capability, hence Feature::Crop should be set while construction for all those converters. Signed-off-by: Umang Jain Signed-off-by: Kieran Bingham --- include/libcamera/internal/converter.h | 5 ++ .../internal/converter/converter_v4l2_m2m.h | 6 ++ src/libcamera/converter.cpp | 51 +++++++++++ .../converter/converter_v4l2_m2m.cpp | 88 +++++++++++++++++++ 4 files changed, 150 insertions(+) diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h index 035e6ffff135..5f9acc573210 100644 --- a/include/libcamera/internal/converter.h +++ b/include/libcamera/internal/converter.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,7 @@ class Converter public: enum class Feature { None = 0, + Crop = (1 << 0), }; using Features = Flags; @@ -63,6 +65,9 @@ public: virtual int queueBuffers(FrameBuffer *input, const std::map &outputs) = 0; + virtual int setCrop(const Stream *stream, Rectangle *rect); + virtual std::pair getCropBounds(const Stream *stream); + Signal inputBufferReady; Signal outputBufferReady; diff --git a/include/libcamera/internal/converter/converter_v4l2_m2m.h b/include/libcamera/internal/converter/converter_v4l2_m2m.h index 91701dbed58d..2697eed99f07 100644 --- a/include/libcamera/internal/converter/converter_v4l2_m2m.h +++ b/include/libcamera/internal/converter/converter_v4l2_m2m.h @@ -30,6 +30,7 @@ class Size; class SizeRange; class Stream; struct StreamConfiguration; +class Rectangle; class V4L2M2MDevice; class V4L2M2MConverter : public Converter @@ -57,6 +58,9 @@ public: int queueBuffers(FrameBuffer *input, const std::map &outputs); + int setCrop(const Stream *stream, Rectangle *rect); + std::pair getCropBounds(const Stream *stream); + private: class V4L2M2MStream : protected Loggable { @@ -75,6 +79,8 @@ private: int queueBuffers(FrameBuffer *input, FrameBuffer *output); + int setSelection(unsigned int target, Rectangle *rect); + protected: std::string logPrefix() const override; diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp index dcbc442ccf68..65f4f96bafa5 100644 --- a/src/libcamera/converter.cpp +++ b/src/libcamera/converter.cpp @@ -11,6 +11,8 @@ #include +#include + #include "libcamera/internal/media_device.h" /** @@ -39,6 +41,8 @@ LOG_DEFINE_CATEGORY(Converter) * \brief Specify the features supported by the converter * \var Converter::Feature::None * \brief No extra features supported by the converter + * \var Converter::Feature::Crop + * \brief Cropping capability is supported by the converter */ /** @@ -161,6 +165,53 @@ Converter::~Converter() * \return 0 on success or a negative error code otherwise */ +/** + * \brief Set the crop rectangle \a rect for \a stream + * \param[in] stream Pointer to output stream + * \param[inout] rect The crop rectangle to be applied + * + * Set the crop rectangle \a rect for \a stream provided the converter supports + * cropping. The converter should have the Feature::Crop flag in this case. + * + * \return 0 on success or a negative error code otherwise + */ +int Converter::setCrop([[maybe_unused]] const Stream *stream, [[maybe_unused]] Rectangle *rect) +{ + if (!(getFeatures() & Feature::Crop)) { + LOG(Converter, Error) << "Converter doesn't support cropping capabilities"; + return -ENOTSUP; + } + + return 0; +} + +/** + * \brief Get the crop bounds \a stream + * \param[in] stream Pointer to output stream + * + * Get the minimum and maximum crop bounds for \a stream. The converter + * should supporting cropping (Feature::Crop). + * + * \return A std::pair containining minimum and maximum + * crop bound respectively. + */ +std::pair Converter::getCropBounds([[maybe_unused]] const Stream *stream) +{ + const StreamConfiguration &config = stream->configuration(); + Rectangle rect; + + if (!(getFeatures() & Feature::Crop)) + LOG(Converter, Error) << "Converter doesn't support cropping capabilities"; + + /* + * This is base implementation for the Converter class, so just return + * the stream configured size as minimum and maximum crop bounds. + */ + rect.size() = config.size; + + return { rect, rect }; +} + /** * \var Converter::inputBufferReady * \brief A signal emitted when the input frame buffer completes diff --git a/src/libcamera/converter/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp index 4aeb7dd93676..eaae35288194 100644 --- a/src/libcamera/converter/converter_v4l2_m2m.cpp +++ b/src/libcamera/converter/converter_v4l2_m2m.cpp @@ -155,6 +155,15 @@ int V4L2M2MConverter::V4L2M2MStream::queueBuffers(FrameBuffer *input, FrameBuffe return 0; } +int V4L2M2MConverter::V4L2M2MStream::setSelection(unsigned int target, Rectangle *rect) +{ + int ret = m2m_->output()->setSelection(target, rect); + if (ret < 0) + return ret; + + return 0; +} + std::string V4L2M2MConverter::V4L2M2MStream::logPrefix() const { return stream_->configuration().toString(); @@ -375,6 +384,81 @@ int V4L2M2MConverter::exportBuffers(const Stream *stream, unsigned int count, return iter->second->exportBuffers(count, buffers); } +/** + * \copydoc libcamera::Converter::setCrop + */ +int V4L2M2MConverter::setCrop(const Stream *stream, Rectangle *rect) +{ + if (!(getFeatures() & Feature::Crop)) + return -ENOTSUP; + + auto iter = streams_.find(stream); + if (iter == streams_.end()) + return -EINVAL; + + return iter->second->setSelection(V4L2_SEL_TGT_CROP, rect); +} + +/** + * \copydoc libcamera::Converter::getCropBounds + */ +std::pair +V4L2M2MConverter::getCropBounds(const Stream *stream) +{ + Rectangle minCrop; + Rectangle maxCrop; + int ret; + + minCrop.width = 1; + minCrop.height = 1; + maxCrop.width = UINT_MAX; + maxCrop.height = UINT_MAX; + + if (!(getFeatures() & Feature::Crop)) { + LOG(Converter, Error) << "Crop functionality is not supported"; + return {}; + } + + auto iter = streams_.find(stream); + if (iter == streams_.end()) { + /* + * No streams configured, return minimum and maximum crop + * bounds at initialization. + */ + ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &minCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query minimum crop bound"; + return {}; + } + + ret = m2m_->output()->setSelection(V4L2_SEL_TGT_CROP, &maxCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query maximum crop bound"; + return {}; + } + + return { minCrop, maxCrop }; + } + + /* + * If the streams are configured, return bounds from according to + * stream configuration. + */ + ret = setCrop(stream, &minCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query minimum crop bound"; + return {}; + } + + ret = setCrop(stream, &maxCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query maximum crop bound"; + return {}; + } + + return { minCrop, maxCrop }; +} + /** * \copydoc libcamera::Converter::start */ @@ -448,6 +532,10 @@ int V4L2M2MConverter::queueBuffers(FrameBuffer *input, return 0; } +/* + * \todo: This should be extended to include Feature::Flag to denote + * what each converter supports feature-wise. + */ static std::initializer_list compatibles = { "mtk-mdp", "pxp", From patchwork Wed Jul 17 10:09:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20691 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 9B5B1C3243 for ; Wed, 17 Jul 2024 10:09:44 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 148E263382; Wed, 17 Jul 2024 12:09:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="pnD9N+ci"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D94976336F for ; Wed, 17 Jul 2024 12:09:28 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E1502ABE; Wed, 17 Jul 2024 12:08:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210931; bh=hQDRXTq2uBYowpiXe2ATjbRCs9EdyvNYwqK56ISW14M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pnD9N+ci3aDAEJCRi+hRYtWbZ9KMKKyiF+eA+1x+HvYidIQnVgTKktPrM3l5fmdzt dpp2hVoEBpn31FE3JR1A1OhdwFMK17+GzHa1p4RlqWhHG0WP5XgUrIGyXFWkcNQP4H nlVORblk/adTZw/DYBxIydQ+8MKt8N4UwsuU01cc= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 5/9] fixups: Make it compile Date: Wed, 17 Jul 2024 12:09:08 +0200 Message-ID: <20240717100913.16640-6-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Jacopo Mondi --- src/libcamera/converter.cpp | 4 ++-- src/libcamera/converter/converter_v4l2_m2m.cpp | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp index 65f4f96bafa5..a959003aaa73 100644 --- a/src/libcamera/converter.cpp +++ b/src/libcamera/converter.cpp @@ -177,7 +177,7 @@ Converter::~Converter() */ int Converter::setCrop([[maybe_unused]] const Stream *stream, [[maybe_unused]] Rectangle *rect) { - if (!(getFeatures() & Feature::Crop)) { + if (!(features() & Feature::Crop)) { LOG(Converter, Error) << "Converter doesn't support cropping capabilities"; return -ENOTSUP; } @@ -200,7 +200,7 @@ std::pair Converter::getCropBounds([[maybe_unused]] const const StreamConfiguration &config = stream->configuration(); Rectangle rect; - if (!(getFeatures() & Feature::Crop)) + if (!(features() & Feature::Crop)) LOG(Converter, Error) << "Converter doesn't support cropping capabilities"; /* diff --git a/src/libcamera/converter/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp index eaae35288194..e381e474c1c7 100644 --- a/src/libcamera/converter/converter_v4l2_m2m.cpp +++ b/src/libcamera/converter/converter_v4l2_m2m.cpp @@ -389,7 +389,7 @@ int V4L2M2MConverter::exportBuffers(const Stream *stream, unsigned int count, */ int V4L2M2MConverter::setCrop(const Stream *stream, Rectangle *rect) { - if (!(getFeatures() & Feature::Crop)) + if (!(features() & Feature::Crop)) return -ENOTSUP; auto iter = streams_.find(stream); @@ -414,7 +414,7 @@ V4L2M2MConverter::getCropBounds(const Stream *stream) maxCrop.width = UINT_MAX; maxCrop.height = UINT_MAX; - if (!(getFeatures() & Feature::Crop)) { + if (!(features() & Feature::Crop)) { LOG(Converter, Error) << "Crop functionality is not supported"; return {}; } @@ -532,10 +532,6 @@ int V4L2M2MConverter::queueBuffers(FrameBuffer *input, return 0; } -/* - * \todo: This should be extended to include Feature::Flag to denote - * what each converter supports feature-wise. - */ static std::initializer_list compatibles = { "mtk-mdp", "pxp", From patchwork Wed Jul 17 10:09:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20692 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E15C3BDB1C for ; Wed, 17 Jul 2024 10:09:45 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 452986338A; Wed, 17 Jul 2024 12:09:40 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="atDxJk5f"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 48CB963371 for ; Wed, 17 Jul 2024 12:09:29 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4B218836; Wed, 17 Jul 2024 12:08:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210931; bh=BcRM7ZeiiuQLERHPK89P4dXChjgt3Lr9NFfcQBMuePw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=atDxJk5fYXOE/+dT1wK7RuDf9CvGN871z6ZFDGt5I3ODWI83ngCWw6DdpWlqsSBk/ qS3miwcGhiW/hX3YYOeF3+8byS7SH5jgwlv66MGsJwWm1TvMX/He6qndZKexLeQX4N 0mB60cU/qa3k3Ed2ZROysWBGF0SqfjPhyrcKIP1U= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi , Paul Elder Subject: [RFC 6/9] libcamera: rkisp1: Prepare for additional camera controls Date: Wed, 17 Jul 2024 12:09:09 +0200 Message-ID: <20240717100913.16640-7-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Umang Jain Currently the rkisp1 pipeline handler only registers controls that are related to the IPA. This patch prepares the rkisp1 pipeline-handler to register camera controls which are not related to the IPA. Hence, introduce a additional ControlInfoMap for IPA controls. These controls will be merged together with the controls in the pipeline handler (introduced subsequently) as part of updateControls() and together will be registered during the registration of the camera. This is similar to what IPU3 pipeline handler handles its controls. Signed-off-by: Umang Jain Reviewed-by: Paul Elder Signed-off-by: Kieran Bingham --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 28 +++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 4cbf105dbdcd..bfc44239dc3d 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -109,6 +109,8 @@ public: std::unique_ptr ipa_; + ControlInfoMap ipaControls_; + private: void paramFilled(unsigned int frame); void setSensorControls(unsigned int frame, @@ -184,6 +186,8 @@ private: int allocateBuffers(Camera *camera); int freeBuffers(Camera *camera); + int updateControls(RkISP1CameraData *data); + MediaDevice *media_; std::unique_ptr isp_; std::unique_ptr param_; @@ -370,7 +374,7 @@ int RkISP1CameraData::loadIPA(unsigned int hwRevision) } ret = ipa_->init({ ipaTuningFile, sensor_->model() }, hwRevision, - sensorInfo, sensor_->controls(), &controlInfo_); + sensorInfo, sensor_->controls(), &ipaControls_); if (ret < 0) { LOG(RkISP1, Error) << "IPA initialization failure"; return ret; @@ -820,12 +824,13 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) ipaConfig.sensorControls = data->sensor_->controls(); - ret = data->ipa_->configure(ipaConfig, streamConfig, &data->controlInfo_); + ret = data->ipa_->configure(ipaConfig, streamConfig, &data->ipaControls_); if (ret) { LOG(RkISP1, Error) << "failed configuring IPA (" << ret << ")"; return ret; } - return 0; + + return updateControls(data); } int PipelineHandlerRkISP1::exportFrameBuffers([[maybe_unused]] Camera *camera, Stream *stream, @@ -1101,8 +1106,23 @@ int PipelineHandlerRkISP1::initLinks(Camera *camera, return 0; } +int PipelineHandlerRkISP1::updateControls(RkISP1CameraData *data) +{ + ControlInfoMap::Map rkisp1Controls; + + /* Add the IPA registered controls to list of camera controls. */ + for (const auto &ipaControl : data->ipaControls_) + rkisp1Controls[ipaControl.first] = ipaControl.second; + + data->controlInfo_ = ControlInfoMap(std::move(rkisp1Controls), + controls::controls); + + return 0; +} + int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) { + ControlInfoMap::Map rkisp1Controls; int ret; std::unique_ptr data = @@ -1137,6 +1157,8 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) if (ret) return ret; + updateControls(data.get()); + std::set streams{ &data->mainPathStream_, &data->selfPathStream_, From patchwork Wed Jul 17 10:09:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20693 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A938EC32CF for ; Wed, 17 Jul 2024 10:09:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C620A6338C; Wed, 17 Jul 2024 12:09:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MsyLz+Rp"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9CCC563369 for ; Wed, 17 Jul 2024 12:09:29 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AA471ABE; Wed, 17 Jul 2024 12:08:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210931; bh=HGfeITlBaKtg0VH/xr0q/ezPVZ9Co1kyC/qImRnnLEE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MsyLz+Rpu/UYz41jXikOJ+ckVMVJJNlVRFljzeY89arEdMi4rIcTRa6K/j4yz+5I7 onvpZKACMCJvyzyvgBS0K6PNWVeTdwc8CsSNOIQs5TesB7dSdLL5UuLE/sj1uxoccB tTaAUz1HiRhgHm7qdixV20uydChPh3KgXpRNkssE= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 7/9] libcamera: converter: Add DW100 converter class Date: Wed, 17 Jul 2024 12:09:10 +0200 Message-ID: <20240717100913.16640-8-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Umang Jain DW100 Dewarp engine is present on i.MX8MP SoC. This patch provides a converter class (inherited from V4L2M2MConverter). The DW100 dewarp engine has scaling capabilites and can be used to set crop rectangles in the rkisp1 pipeline handler. Plumbing in the RkISP1 pipeline-handler is done in the subsequent patch. The ConverterDW100 class can be extended later (as additional development) to support the dewarping by setting a dewarp vertex map as well. Signed-off-by: Umang Jain Signed-off-by: Kieran Bingham --- .../internal/converter/converter_dw100.h | 24 ++++++++++++ .../libcamera/internal/converter/meson.build | 1 + src/libcamera/converter/converter_dw100.cpp | 37 +++++++++++++++++++ src/libcamera/converter/meson.build | 1 + 4 files changed, 63 insertions(+) create mode 100644 include/libcamera/internal/converter/converter_dw100.h create mode 100644 src/libcamera/converter/converter_dw100.cpp diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h new file mode 100644 index 000000000000..dc41f365b5c7 --- /dev/null +++ b/include/libcamera/internal/converter/converter_dw100.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas On Board Oy + * + * i.MX8MP Dewarp Engine integration + */ + +#pragma once + +#include "libcamera/internal/converter/converter_v4l2_m2m.h" + +namespace libcamera { + +class MediaDevice; +class Rectangle; +class Stream; + +class ConverterDW100 : public V4L2M2MConverter +{ +public: + ConverterDW100(std::shared_ptr media); +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/converter/meson.build b/include/libcamera/internal/converter/meson.build index 891e79e7d493..85007a4b0f8b 100644 --- a/include/libcamera/internal/converter/meson.build +++ b/include/libcamera/internal/converter/meson.build @@ -1,5 +1,6 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_internal_headers += files([ + 'converter_dw100.h', 'converter_v4l2_m2m.h', ]) diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp new file mode 100644 index 000000000000..3061fc71dd80 --- /dev/null +++ b/src/libcamera/converter/converter_dw100.cpp @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas On Board Oy + * + * i.MX8MP Dewarp Engine integration + */ + +#include "libcamera/internal/converter/converter_dw100.h" + +#include + +#include + +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/v4l2_videodevice.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(Converter) + +/** + * \class libcamera::ConverterDW100 + * \brief The i.MX8MP dewarp converter implements the converter interface based + * on V4L2 M2M device. +*/ + +/** + * \fn ConverterDW100::ConverterDW100 + * \brief Construct a ConverterDW100 instance + * \param[in] media The media device implementing the converter + */ +ConverterDW100::ConverterDW100(std::shared_ptr media) + : V4L2M2MConverter(media.get(), Feature::Crop) +{ +} + +} /* namespace libcamera */ diff --git a/src/libcamera/converter/meson.build b/src/libcamera/converter/meson.build index 2aa72fe456a4..175581b8af92 100644 --- a/src/libcamera/converter/meson.build +++ b/src/libcamera/converter/meson.build @@ -1,5 +1,6 @@ # SPDX-License-Identifier: CC0-1.0 libcamera_sources += files([ + 'converter_dw100.cpp', 'converter_v4l2_m2m.cpp' ]) From patchwork Wed Jul 17 10:09:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20694 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 4DECAC3243 for ; Wed, 17 Jul 2024 10:09:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 736E56338D; Wed, 17 Jul 2024 12:09:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sNlV+8HQ"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 650676337E for ; Wed, 17 Jul 2024 12:09:30 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0B360B0B; Wed, 17 Jul 2024 12:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210932; bh=bBdgHxb/bKL2OPNxdQuIixlBev03dXKtpNPMIy6GDDc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sNlV+8HQQfC7LZ196grkUh8YC6yXytY91odhWLBPQkw1zs3Oi7V26fG0dFf/MOWKe RU26kPyMvo/uIsXn6XhwWtbY5unfslXt0PO5n4nbQpz3Jj3YVRoE+YtHzkYzb8gCII 0FIYnIXaMnP6AyNvz/U7mGHgqIeb1uMgfnUG6Tt8= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 8/9] dw100: fixup Date: Wed, 17 Jul 2024 12:09:11 +0200 Message-ID: <20240717100913.16640-9-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Jacopo Mondi --- .../libcamera/internal/converter/converter_dw100.h | 2 +- src/libcamera/converter/converter_dw100.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/libcamera/internal/converter/converter_dw100.h b/include/libcamera/internal/converter/converter_dw100.h index dc41f365b5c7..ee82b99e8d9d 100644 --- a/include/libcamera/internal/converter/converter_dw100.h +++ b/include/libcamera/internal/converter/converter_dw100.h @@ -18,7 +18,7 @@ class Stream; class ConverterDW100 : public V4L2M2MConverter { public: - ConverterDW100(std::shared_ptr media); + ConverterDW100(MediaDevice *media, Converter::Features features); }; } /* namespace libcamera */ diff --git a/src/libcamera/converter/converter_dw100.cpp b/src/libcamera/converter/converter_dw100.cpp index 3061fc71dd80..09ede8d0c216 100644 --- a/src/libcamera/converter/converter_dw100.cpp +++ b/src/libcamera/converter/converter_dw100.cpp @@ -29,9 +29,16 @@ LOG_DECLARE_CATEGORY(Converter) * \brief Construct a ConverterDW100 instance * \param[in] media The media device implementing the converter */ -ConverterDW100::ConverterDW100(std::shared_ptr media) - : V4L2M2MConverter(media.get(), Feature::Crop) +ConverterDW100::ConverterDW100(MediaDevice *media, Converter::Features features) + : V4L2M2MConverter(media, features) { } +static std::initializer_list compatibles = { + "dw100", +}; + +REGISTER_CONVERTER("dw100", ConverterDW100, compatibles, + Converter::Feature::Crop) + } /* namespace libcamera */ From patchwork Wed Jul 17 10:09:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 20695 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id E57E9C32D0 for ; Wed, 17 Jul 2024 10:09:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id AFB9C6336F; Wed, 17 Jul 2024 12:09:43 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="AX0kBNjc"; dkim-atps=neutral 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 A4DE56337F for ; Wed, 17 Jul 2024 12:09:30 +0200 (CEST) Received: from uno.LocalDomain (93-61-96-190.ip145.fastwebnet.it [93.61.96.190]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 60DE2836; Wed, 17 Jul 2024 12:08:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1721210932; bh=jGBBD9zdt7TPK8CWkbvM3ZXWd/FX/89I8R5ur/Hs7ag=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AX0kBNjcRCMiQNtsZDlnT0bUYIkhemv4qoZCPIeA9c05o/72mutAnc+XlZkGb16Z8 Q+dWWeeRUbxJFuE4qI4tjMgzYK12YCa4Q/pdiJi+6wPVNe2exCzLtiWjtczdFcrjIk WC7NyWXgwHKGgj6wMnlxUpNLWUXRqg5MkVE/Ne2I= From: Jacopo Mondi To: Umang Jain , libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi Subject: [RFC 9/9] libcamera: rkisp1: Plumb the ConverterDW100 converter Date: Wed, 17 Jul 2024 12:09:12 +0200 Message-ID: <20240717100913.16640-10-jacopo.mondi@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> References: <20240717100913.16640-1-jacopo.mondi@ideasonboard.com> MIME-Version: 1.0 X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" From: Umang Jain Plumb the ConverterDW100 converter in the rkisp1 pipeline handler. If the dewarper is found, it is instantiated and buffers are exported from it, instead of RkISP1Path. Internal buffers are allocated for the RkISP1Path in case where dewarper is going to be used. The RKISP1 pipeline handler now supports scaler crop control through ConverterDW100. Register the ScalerCrop control for the cameras created in the RKISP1 pipeline handler. Signed-off-by: Umang Jain Signed-off-by: Kieran Bingham --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 148 +++++++++++++++++- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 12 +- src/libcamera/pipeline/rkisp1/rkisp1_path.h | 14 ++ 3 files changed, 165 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index bfc44239dc3d..881e10e19baa 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -33,6 +35,7 @@ #include "libcamera/internal/camera.h" #include "libcamera/internal/camera_sensor.h" +#include "libcamera/internal/converter/converter_dw100.h" #include "libcamera/internal/delayed_controls.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/framebuffer.h" @@ -62,6 +65,8 @@ struct RkISP1FrameInfo { bool paramDequeued; bool metadataProcessed; + + std::optional scalerCrop; }; class RkISP1Frames @@ -181,6 +186,7 @@ private: void bufferReady(FrameBuffer *buffer); void paramReady(FrameBuffer *buffer); void statReady(FrameBuffer *buffer); + void dewarpBufferReady(FrameBuffer *buffer); void frameStart(uint32_t sequence); int allocateBuffers(Camera *camera); @@ -200,6 +206,13 @@ private: RkISP1MainPath mainPath_; RkISP1SelfPath selfPath_; + std::unique_ptr dewarper_; + bool useDewarper_; + + /* Internal buffers used when dewarper is being used */ + std::vector> mainPathBuffers_; + std::queue availableMainPathBuffers_; + std::vector> paramBuffers_; std::vector> statBuffers_; std::queue availableParamBuffers_; @@ -222,6 +235,8 @@ RkISP1FrameInfo *RkISP1Frames::create(const RkISP1CameraData *data, Request *req FrameBuffer *paramBuffer = nullptr; FrameBuffer *statBuffer = nullptr; + FrameBuffer *mainPathBuffer = nullptr; + FrameBuffer *selfPathBuffer = nullptr; if (!isRaw) { if (pipe_->availableParamBuffers_.empty()) { @@ -239,10 +254,16 @@ RkISP1FrameInfo *RkISP1Frames::create(const RkISP1CameraData *data, Request *req statBuffer = pipe_->availableStatBuffers_.front(); pipe_->availableStatBuffers_.pop(); + + if (pipe_->useDewarper_) { + mainPathBuffer = pipe_->availableMainPathBuffers_.front(); + pipe_->availableMainPathBuffers_.pop(); + } } - FrameBuffer *mainPathBuffer = request->findBuffer(&data->mainPathStream_); - FrameBuffer *selfPathBuffer = request->findBuffer(&data->selfPathStream_); + if (!mainPathBuffer) + mainPathBuffer = request->findBuffer(&data->mainPathStream_); + selfPathBuffer = request->findBuffer(&data->selfPathStream_); RkISP1FrameInfo *info = new RkISP1FrameInfo; @@ -268,6 +289,7 @@ int RkISP1Frames::destroy(unsigned int frame) pipe_->availableParamBuffers_.push(info->paramBuffer); pipe_->availableStatBuffers_.push(info->statBuffer); + pipe_->availableMainPathBuffers_.push(info->mainPathBuffer); frameInfo_.erase(info->frame); @@ -283,6 +305,7 @@ void RkISP1Frames::clear() pipe_->availableParamBuffers_.push(info->paramBuffer); pipe_->availableStatBuffers_.push(info->statBuffer); + pipe_->availableMainPathBuffers_.push(info->mainPathBuffer); delete info; } @@ -607,7 +630,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() */ PipelineHandlerRkISP1::PipelineHandlerRkISP1(CameraManager *manager) - : PipelineHandler(manager), hasSelfPath_(true) + : PipelineHandler(manager), hasSelfPath_(true), useDewarper_(false) { } @@ -785,12 +808,19 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) << " crop " << rect; std::map streamConfig; + std::vector> outputCfgs; for (const StreamConfiguration &cfg : *config) { if (cfg.stream() == &data->mainPathStream_) { ret = mainPath_.configure(cfg, format); streamConfig[0] = IPAStream(cfg.pixelFormat, cfg.size); + /* Configure dewarp */ + if (dewarper_ && !isRaw_) { + outputCfgs.push_back(const_cast(cfg)); + ret = dewarper_->configure(cfg, outputCfgs); + useDewarper_ = ret ? false : true; + } } else if (hasSelfPath_) { ret = selfPath_.configure(cfg, format); streamConfig[1] = IPAStream(cfg.pixelFormat, @@ -839,6 +869,9 @@ int PipelineHandlerRkISP1::exportFrameBuffers([[maybe_unused]] Camera *camera, S RkISP1CameraData *data = cameraData(camera); unsigned int count = stream->configuration().bufferCount; + if (useDewarper_) + return dewarper_->exportBuffers(&data->mainPathStream_, count, buffers); + if (stream == &data->mainPathStream_) return mainPath_.exportBuffers(count, buffers); else if (hasSelfPath_ && stream == &data->selfPathStream_) @@ -866,6 +899,16 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) ret = stat_->allocateBuffers(maxCount, &statBuffers_); if (ret < 0) goto error; + + /* If the dewarper is being used, allocate internal buffers for ISP */ + if (useDewarper_) { + ret = mainPath_.allocateBuffers(maxCount, &mainPathBuffers_); + if (ret < 0) + goto error; + + for (std::unique_ptr &buffer : mainPathBuffers_) + availableMainPathBuffers_.push(buffer.get()); + } } for (std::unique_ptr &buffer : paramBuffers_) { @@ -889,6 +932,7 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) error: paramBuffers_.clear(); statBuffers_.clear(); + mainPathBuffers_.clear(); return ret; } @@ -903,8 +947,12 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) while (!availableParamBuffers_.empty()) availableParamBuffers_.pop(); + while (!availableMainPathBuffers_.empty()) + availableMainPathBuffers_.pop(); + paramBuffers_.clear(); statBuffers_.clear(); + mainPathBuffers_.clear(); std::vector ids; for (IPABuffer &ipabuf : data->ipaBuffers_) @@ -919,6 +967,9 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) if (stat_->releaseBuffers()) LOG(RkISP1, Error) << "Failed to release stat buffers"; + if (useDewarper_) + mainPath_.releaseBuffers(); + return 0; } @@ -961,6 +1012,14 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL << "Failed to start statistics " << camera->id(); return ret; } + + if (useDewarper_) { + ret = dewarper_->start(); + if (ret) { + LOG(RkISP1, Error) << "Failed to start dewarper"; + return ret; + } + } } if (data->mainPath_->isEnabled()) { @@ -1015,6 +1074,9 @@ void PipelineHandlerRkISP1::stopDevice(Camera *camera) if (ret) LOG(RkISP1, Warning) << "Failed to stop parameters for " << camera->id(); + + if (useDewarper_) + dewarper_->stop(); } ASSERT(data->queuedRequests_.empty()); @@ -1045,6 +1107,25 @@ int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request) info->paramBuffer->cookie()); } + const auto &crop = request->controls().get(controls::ScalerCrop); + if (crop && useDewarper_) { + Rectangle appliedRect = crop.value(); + int ret = dewarper_->setCrop(&data->mainPathStream_, &appliedRect); + if (!ret) { + if (appliedRect != crop.value()) { + /* + * \todo How to handle these case? + * Do we aim for pixel perfect set rectangles? + */ + LOG(RkISP1, Warning) + << "Applied rectangle " << appliedRect.toString() + << " differs from requested " << crop.value().toString(); + } + + info->scalerCrop = appliedRect; + } + } + data->frame_++; return 0; @@ -1110,6 +1191,12 @@ int PipelineHandlerRkISP1::updateControls(RkISP1CameraData *data) { ControlInfoMap::Map rkisp1Controls; + if (dewarper_) { + auto [minCrop, maxCrop] = dewarper_->getCropBounds(&data->mainPathStream_); + + rkisp1Controls[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop); + } + /* Add the IPA registered controls to list of camera controls. */ for (const auto &ipaControl : data->ipaControls_) rkisp1Controls[ipaControl.first] = ipaControl.second; @@ -1173,6 +1260,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) { + std::shared_ptr dwpMediaDevice; const MediaPad *pad; DeviceMatch dm("rkisp1"); @@ -1237,6 +1325,26 @@ bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) stat_->bufferReady.connect(this, &PipelineHandlerRkISP1::statReady); param_->bufferReady.connect(this, &PipelineHandlerRkISP1::paramReady); + /* If dewarper is present, create its instance. */ + DeviceMatch dwp("dw100"); + dwp.add("dw100-source"); + dwp.add("dw100-sink"); + + dwpMediaDevice = enumerator->search(dwp); + if (dwpMediaDevice) { + dewarper_ = std::make_unique(std::move(dwpMediaDevice)); + if (dewarper_->isValid()) { + dewarper_->outputBufferReady.connect( + this, &PipelineHandlerRkISP1::dewarpBufferReady); + + LOG(RkISP1, Info) << "Using DW100 dewarper " << dewarper_->deviceNode(); + } else { + LOG(RkISP1, Debug) << "Found DW100 dewarper " << dewarper_->deviceNode() + << " but invalid"; + dewarper_.reset(); + } + } + /* * Enumerate all sensors connected to the ISP and create one * camera instance for each of them. @@ -1283,7 +1391,7 @@ void PipelineHandlerRkISP1::bufferReady(FrameBuffer *buffer) return; const FrameMetadata &metadata = buffer->metadata(); - Request *request = buffer->request(); + Request *request = info->request; if (metadata.status != FrameMetadata::FrameCancelled) { /* @@ -1300,11 +1408,43 @@ void PipelineHandlerRkISP1::bufferReady(FrameBuffer *buffer) data->delayedCtrls_->get(metadata.sequence); data->ipa_->processStatsBuffer(info->frame, 0, ctrls); } + } else { if (isRaw_) info->metadataProcessed = true; } + if (useDewarper_) { + /* + * Queue input and output buffers to the dewarper. The output + * buffers for the dewarper are the buffers of the request, supplied + * by the application. + */ + int ret = dewarper_->queueBuffers(buffer, request->buffers()); + if (ret < 0) + LOG(RkISP1, Error) << "Cannot queue buffers to dewarper: " + << strerror(-ret); + + return; + } + + completeBuffer(request, buffer); + tryCompleteRequest(info); +} + +void PipelineHandlerRkISP1::dewarpBufferReady(FrameBuffer *buffer) +{ + ASSERT(activeCamera_); + RkISP1CameraData *data = cameraData(activeCamera_); + Request *request = buffer->request(); + + RkISP1FrameInfo *info = data->frameInfo_.find(buffer->request()); + if (!info) + return; + + if (info->scalerCrop) + request->metadata().set(controls::ScalerCrop, info->scalerCrop.value()); + completeBuffer(request, buffer); tryCompleteRequest(info); } diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp index c49017d1fb29..c96ec1d6648a 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp @@ -56,7 +56,7 @@ const std::map formatToMediaBus = { RkISP1Path::RkISP1Path(const char *name, const Span &formats, const Size &minResolution, const Size &maxResolution) - : name_(name), running_(false), formats_(formats), + : name_(name), running_(false), internalBufs_(false), formats_(formats), minResolution_(minResolution), maxResolution_(maxResolution), link_(nullptr) { @@ -402,10 +402,12 @@ int RkISP1Path::start() if (running_) return -EBUSY; - /* \todo Make buffer count user configurable. */ - ret = video_->importBuffers(RKISP1_BUFFER_COUNT); - if (ret) - return ret; + if (!internalBufs_) { + /* \todo Make buffer count user configurable. */ + ret = video_->importBuffers(RKISP1_BUFFER_COUNT); + if (ret) + return ret; + } ret = video_->streamOn(); if (ret) { diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h index 08edefecaa00..b7fa82d03f56 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h @@ -55,6 +55,19 @@ public: return video_->exportBuffers(bufferCount, buffers); } + int allocateBuffers(unsigned int bufferCount, + std::vector> *buffers) + { + internalBufs_ = true; + return video_->allocateBuffers(bufferCount, buffers); + } + + int releaseBuffers() + { + ASSERT(internalBufs_); + return video_->releaseBuffers(); + } + int start(); void stop(); @@ -68,6 +81,7 @@ private: const char *name_; bool running_; + bool internalBufs_; const Span formats_; std::set streamFormats_;