From patchwork Thu Jun 27 13:46:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20431 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 36CA8BDB1D for ; Thu, 27 Jun 2024 13:47:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id CC27362E20; Thu, 27 Jun 2024 15:47:07 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="r8e1ZNJt"; 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 236A862C95 for ; Thu, 27 Jun 2024 15:47:04 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:c173:4b:4a04:3a21]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8C46C7E0; Thu, 27 Jun 2024 15:46:39 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1719496000; bh=kiCxZt+YqR+hG9uR+z4YXAuDO2nPQ/QHvxVq3kaAD2Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r8e1ZNJtVaeoJxg/hCRcSoh5YB94j/faliQsjnxBFPSHDxrQQA9ZjW7gXgP4eAF2o 26+1OcczuA7lEg6MMC1cYRqdsvS2ujjDTVqzrSkw17evwWYcUSsp99aMc8rkEbOn+B WBrB/HrRkxoBVn2biUACJ6m29UTIackmR5ATs1zs= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v4 1/5] libcamera: converter: Add interface for feature flags Date: Thu, 27 Jun 2024 19:16:52 +0530 Message-ID: <20240627134656.582462-2-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240627134656.582462-1-umang.jain@ideasonboard.com> References: <20240627134656.582462-1-umang.jain@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" 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 --- 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 b51563d7..15bc7dca 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 = (1 << 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 b9e59899..91701dbe 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 c5e38937..2dc7d984 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 2e77872e..4aeb7dd9 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 Thu Jun 27 13:46:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20432 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 2BF0EBDB1D for ; Thu, 27 Jun 2024 13:47:10 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6EB3862E22; Thu, 27 Jun 2024 15:47:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="IS5vXVLE"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E56062C98 for ; Thu, 27 Jun 2024 15:47:05 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:c173:4b:4a04:3a21]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D04EE593; Thu, 27 Jun 2024 15:46:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1719496001; bh=sZqqtOY9dkVPh0SxU93GnQMq6s6m2kQMbOUPb+cU5Sc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IS5vXVLEEFTgabm2oIa5YLfXhX2PNM/YmCHe6NSlji8NTQ59PouNCVpS26/2Oxc/h RCXoRY70KqBZR+9gZGtRCS/HYoHUG+wwuDX2BfSyHqcg+aN7+rqGQ8YnMnF7rnbWM9 UK2LwfBdSsm4li0uHJhvR8Nf3UqyaZNcSA0cTFLo= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v4 2/5] libcamera: converter: Add interface to support cropping capability Date: Thu, 27 Jun 2024 19:16:53 +0530 Message-ID: <20240627134656.582462-3-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240627134656.582462-1-umang.jain@ideasonboard.com> References: <20240627134656.582462-1-umang.jain@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" 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. For implementing the getCropBounds(), V4L2VideoDevice needs to be extended to support VIDIOC_G_SELECTION via V4L2VideoDevice::getSelection(). Signed-off-by: Umang Jain --- include/libcamera/internal/converter.h | 5 ++ .../internal/converter/converter_v4l2_m2m.h | 7 ++ include/libcamera/internal/v4l2_videodevice.h | 1 + src/libcamera/converter.cpp | 35 ++++++++ .../converter/converter_v4l2_m2m.cpp | 85 +++++++++++++++++++ src/libcamera/v4l2_videodevice.cpp | 32 +++++++ 6 files changed, 165 insertions(+) diff --git a/include/libcamera/internal/converter.h b/include/libcamera/internal/converter.h index 15bc7dca..deba75e3 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 = (1 << 0), + Crop = (1 << 1), }; 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 91701dbe..e97fbdd2 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,9 @@ private: int queueBuffers(FrameBuffer *input, FrameBuffer *output); + int getSelection(unsigned int target, Rectangle *rect); + int setSelection(unsigned int target, Rectangle *rect); + protected: std::string logPrefix() const override; diff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h index 9057be08..506d6a65 100644 --- a/include/libcamera/internal/v4l2_videodevice.h +++ b/include/libcamera/internal/v4l2_videodevice.h @@ -209,6 +209,7 @@ public: Formats formats(uint32_t code = 0); int setSelection(unsigned int target, Rectangle *rect); + int getSelection(unsigned int target, Rectangle *rect); int allocateBuffers(unsigned int count, std::vector> *buffers); diff --git a/src/libcamera/converter.cpp b/src/libcamera/converter.cpp index 2dc7d984..19634e1c 100644 --- a/src/libcamera/converter.cpp +++ b/src/libcamera/converter.cpp @@ -39,6 +39,9 @@ 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 +164,38 @@ 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) +{ + 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) +{ + Rectangle rect; + + 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 4aeb7dd9..4bb625e9 100644 --- a/src/libcamera/converter/converter_v4l2_m2m.cpp +++ b/src/libcamera/converter/converter_v4l2_m2m.cpp @@ -155,6 +155,24 @@ 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; +} + +int V4L2M2MConverter::V4L2M2MStream::getSelection(unsigned int target, Rectangle *rect) +{ + int ret = m2m_->output()->getSelection(target, rect); + if (ret < 0) + return ret; + + return 0; +} + std::string V4L2M2MConverter::V4L2M2MStream::logPrefix() const { return stream_->configuration().toString(); @@ -375,6 +393,69 @@ 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; + + auto iter = streams_.find(stream); + if (iter == streams_.end()) + return {}; + + if (!(getFeatures() & Feature::Crop)) { + LOG(Converter, Error) << "Crop functionality is not supported"; + return {}; + } + + /* Get the maximum crop bound */ + ret = iter->second->getSelection(V4L2_SEL_TGT_CROP_BOUNDS, &maxCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query maximum crop bound"; + return {}; + } + + /* + * Get the minimum crop bound by setting 1x1 crop rectangle. The returned + * rectangle should be them minimum crop supported by the driver. + */ + minCrop.width = 1; + minCrop.height = 1; + ret = setCrop(stream, &minCrop); + if (ret) { + LOG(Converter, Error) << "Failed to query minimum crop bound"; + return {}; + } + + /* Reset the crop rectangle to maximum */ + ret = setCrop(stream, &maxCrop); + if (ret) { + LOG(Converter, Error) << "Failed to reset the crop to " << maxCrop.toString(); + return {}; + } + + return { minCrop, maxCrop }; +} + /** * \copydoc libcamera::Converter::start */ @@ -448,6 +529,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", diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index 4947aa3d..dfbfae2c 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -1226,6 +1226,38 @@ int V4L2VideoDevice::setSelection(unsigned int target, Rectangle *rect) return 0; } +/** + * \brief Get the selection rectangle \a rect for \a target + * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags + * \param[inout] rect The selection rectangle that has been queried + * + * \todo Define a V4L2SelectionTarget enum for the selection target + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2VideoDevice::getSelection(unsigned int target, Rectangle *rect) +{ + struct v4l2_selection sel = {}; + + sel.type = bufferType_; + sel.target = target; + sel.flags = 0; + + int ret = ioctl(VIDIOC_G_SELECTION, &sel); + if (ret < 0) { + LOG(V4L2, Error) << "Unable to get rectangle " << target + << ": " << strerror(-ret); + return ret; + } + + rect->x = sel.r.left; + rect->y = sel.r.top; + rect->width = sel.r.width; + rect->height = sel.r.height; + + return 0; +} + int V4L2VideoDevice::requestBuffers(unsigned int count, enum v4l2_memory memoryType) { From patchwork Thu Jun 27 13:46:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20433 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 A13E8BDB1D for ; Thu, 27 Jun 2024 13:47:11 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 82F9462E1D; Thu, 27 Jun 2024 15:47:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="oCnrbBkg"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ABF2D62C95 for ; Thu, 27 Jun 2024 15:47:06 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:c173:4b:4a04:3a21]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1F795593; Thu, 27 Jun 2024 15:46:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1719496002; bh=2+kYukOip1BdN6eD6IxERRI+4LAeFi+tEqRISU70gFY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oCnrbBkgYQ28R9edCctr+JT2gkINKiVlGLwYj4yFc0kwQx6W5/KBXUlXgERForN52 kes83uz8hhU7ISQwJzhIZTiHdDORL6GwIIJUQdtKIaFkOnEQy3razum8XmrQpA5M4d MDHjiiB2mKrsinfikm4KD6Kqe13opjk4lHYFE/3E= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v4 3/5] libcamera: rkisp1: Prepare for additional camera controls Date: Thu, 27 Jun 2024 19:16:54 +0530 Message-ID: <20240627134656.582462-4-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240627134656.582462-1-umang.jain@ideasonboard.com> References: <20240627134656.582462-1-umang.jain@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" 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 --- 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 4cbf105d..bfc44239 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 Thu Jun 27 13:46:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20434 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 A4201BDB1D for ; Thu, 27 Jun 2024 13:47:13 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4A04562E24; Thu, 27 Jun 2024 15:47:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="juxIVLUF"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1A35A62E21 for ; Thu, 27 Jun 2024 15:47:08 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:c173:4b:4a04:3a21]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 62BF1E22; Thu, 27 Jun 2024 15:46:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1719496004; bh=rtc+XKK2E9dpQ3FsmYfg0icv2NuEtEcKOmw2drO1eUQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=juxIVLUFbZb+KpAIBZ38IWEzWwyrJgD0eHRBPZAZDrD5ayUmYSoiUwvSWUkDX9KUa WmsHszaEvjTr+5kosxBzZx5VD/NeyCJ2pHP0ciawEkKODiR/qiGCxQmP33enzoXFGF zsYgD78s0Pbj3eOxR0XGpIkvdGZ6LYj2Btw5pwTU= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v4 4/5] libcamera: converter: Add DW100 converter class Date: Thu, 27 Jun 2024 19:16:55 +0530 Message-ID: <20240627134656.582462-5-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240627134656.582462-1-umang.jain@ideasonboard.com> References: <20240627134656.582462-1-umang.jain@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" DW100 Dewarp engine is present on i.MX8MP SoC. This patch provides a converter class (inherited from V4L2M2MConverter). The DW100 converter will be used for scaling capabilites hence, has a helper to set scaler crop rectangles. 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. Signed-off-by: Umang Jain --- .../internal/converter/converter_dw100.h | 26 ++++++++ .../libcamera/internal/converter/meson.build | 1 + src/libcamera/converter/converter_dw100.cpp | 64 +++++++++++++++++++ src/libcamera/converter/meson.build | 1 + 4 files changed, 92 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 00000000..dbd39e08 --- /dev/null +++ b/include/libcamera/internal/converter/converter_dw100.h @@ -0,0 +1,26 @@ +/* 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); + + int setScalerCrop(const Stream *stream, Rectangle *rect); +}; + +} /* namespace libcamera */ diff --git a/include/libcamera/internal/converter/meson.build b/include/libcamera/internal/converter/meson.build index 891e79e7..85007a4b 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 00000000..78802615 --- /dev/null +++ b/src/libcamera/converter/converter_dw100.cpp @@ -0,0 +1,64 @@ +/* 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) +{ +} + +/** + * \brief Set the scaler crop rectangle \a rect on \a stream + * \param[in] stream Pointer to output stream + * \param[inout] rect The selection rectangle to be applied + * + * \return 0 on success or a negative error code otherwise + */ +int ConverterDW100::setScalerCrop(const Stream *stream, Rectangle *rect) +{ + Rectangle apply = *rect; + int ret; + + ret = setCrop(stream, &apply); + if (ret < 0) + LOG(Converter, Error) << "Failed to set scaler crop " + << apply.toString() << " on dewarper " + << strerror(-ret); + + if (*rect != apply) { + /* \todo This case needs proper after handling. */ + LOG(Converter, Warning) << "Applied rectangle " << apply.toString() + << " differs from requested " << rect->toString(); + } + + return ret; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/converter/meson.build b/src/libcamera/converter/meson.build index 2aa72fe4..175581b8 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 Thu Jun 27 13:46:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20435 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 EF899BDB1D for ; Thu, 27 Jun 2024 13:47:14 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A2E2962E21; Thu, 27 Jun 2024 15:47:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XACrueiO"; 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 4979662C9D for ; Thu, 27 Jun 2024 15:47:09 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:c173:4b:4a04:3a21]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A5E0D593; Thu, 27 Jun 2024 15:46:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1719496005; bh=A1asNAFfgSypoXAvynChoO2lxM0uxhyj8lGtDEjXguQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XACrueiO9gLG+weyWCEum/7IELXk9B70/NqEEL+xXDeyfP1Y5NYZ7aebAy0psTbeS mmuBqcBXyYNMYA6UhSM41wEypbIpxOhZqK1go85zvqdZAWL+FA+z9GjHH0uk5uExOh 7pQkY/VzxBVyIhO/p9a7qR0QBPQnE0BjFa6PKfZc= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v4 5/5] libcamera: rkisp1: Plumb the ConverterDW100 converter Date: Thu, 27 Jun 2024 19:16:56 +0530 Message-ID: <20240627134656.582462-6-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240627134656.582462-1-umang.jain@ideasonboard.com> References: <20240627134656.582462-1-umang.jain@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" 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 --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 144 +++++++++++++++++- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 12 +- src/libcamera/pipeline/rkisp1/rkisp1_path.h | 14 ++ 3 files changed, 161 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index bfc44239..eb373be4 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,26 @@ 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_) { + /* + * \todo Converter::configure() API should be changed + * to use std::vector> ? + */ + outputCfgs.push_back(const_cast(cfg)); + dewarper_->configure(cfg, outputCfgs); + useDewarper_ = true; + } else { + useDewarper_ = false; + } + } else if (hasSelfPath_) { ret = selfPath_.configure(cfg, format); streamConfig[1] = IPAStream(cfg.pixelFormat, @@ -839,6 +876,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 +906,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 +939,7 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) error: paramBuffers_.clear(); statBuffers_.clear(); + mainPathBuffers_.clear(); return ret; } @@ -903,8 +954,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 +974,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 +1019,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 +1081,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 +1114,14 @@ int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request) info->paramBuffer->cookie()); } + const auto &crop = request->controls().get(controls::ScalerCrop); + if (crop && useDewarper_) { + Rectangle rect = crop.value(); + int ret = dewarper_->setScalerCrop(&data->mainPathStream_, &rect); + if (!ret) + info->scalerCrop = crop; + } + data->frame_++; return 0; @@ -1110,6 +1187,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 +1256,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) { + std::shared_ptr dwpMediaDevice; const MediaPad *pad; DeviceMatch dm("rkisp1"); @@ -1237,6 +1321,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 +1387,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 +1404,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 c49017d1..c96ec1d6 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 08edefec..b7fa82d0 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_;