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",