From patchwork Sun May 19 11:56:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20071 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 29D32BDE6B for ; Sun, 19 May 2024 11:56:37 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 691AA63483; Sun, 19 May 2024 13:56:34 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="tvEM9i5S"; 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 65E7063469 for ; Sun, 19 May 2024 13:56:32 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:9278:2c85:fd02:c5f5]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 28421581; Sun, 19 May 2024 13:56:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716119781; bh=zonpV5yh7yW12jhROt0tMfSy7Ygdogs3gdRByuInMDo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tvEM9i5SetPfjOVlV8y8zqmWgvDoA1V0cP9s00J58UF8riY5NdVfqqLLHzdqv4Bmc knBPl7EpuHxK4/nVj3KtzmKD/kUsMIdp6vfnFC3IPhbmAQFfkCSOLy3H1L6HClUhmO LwyFJluk9tIqyWBg1q6KqqMi56luRWIMtkH2ICqY= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v2 1/4] libcamera: rkisp1: Prepare for additional camera controls Date: Sun, 19 May 2024 17:26:19 +0530 Message-ID: <20240519115622.32170-2-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240519115622.32170-1-umang.jain@ideasonboard.com> References: <20240519115622.32170-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 might 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 registeration of the camera. This is similar to what IPU3 pipeline handler handles its controls. Signed-off-by: Umang Jain --- 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 Sun May 19 11:56:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20072 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 53964C322E for ; Sun, 19 May 2024 11:56:39 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9102A6347F; Sun, 19 May 2024 13:56:37 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ZowIMKQ5"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E4B663469 for ; Sun, 19 May 2024 13:56:33 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:9278:2c85:fd02:c5f5]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 61B2A49E; Sun, 19 May 2024 13:56:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716119783; bh=ZyOTc94RM3gN+8FzYyzXlDr4n2wQ/pw8HRPfwnqXfvo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZowIMKQ5WdOAVtQEZK996VUEnKU11PdlHLZeNVgm0F70z0HPFycEyiGxw9eMBszEp snOEvC7LFitiicFsAmqBl0McfvI1NSxKJdKXhDGdp6MmTobICj+kkL7lFh5gYF0xDg SkOwv0CB2krJv8cxMiSSJjxaSGqH5LcAS2ZWfudw= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v2 2/4] libcamera: converter_v4l2_m2m: Support crop selection Date: Sun, 19 May 2024 17:26:20 +0530 Message-ID: <20240519115622.32170-3-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240519115622.32170-1-umang.jain@ideasonboard.com> References: <20240519115622.32170-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" Add a helper to set selection rectangle on the video node to support cropping and scaling capabilites. Signed-off-by: Umang Jain --- .../internal/converter/converter_v4l2_m2m.h | 5 ++++ .../converter/converter_v4l2_m2m.cpp | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/include/libcamera/internal/converter/converter_v4l2_m2m.h b/include/libcamera/internal/converter/converter_v4l2_m2m.h index 1126050c..acc6424c 100644 --- a/include/libcamera/internal/converter/converter_v4l2_m2m.h +++ b/include/libcamera/internal/converter/converter_v4l2_m2m.h @@ -29,6 +29,7 @@ class MediaDevice; class Size; class SizeRange; struct StreamConfiguration; +class Rectangle; class V4L2M2MDevice; class V4L2M2MConverter : public Converter @@ -56,6 +57,8 @@ public: int queueBuffers(FrameBuffer *input, const std::map &outputs); + int setSelection(unsigned int output, unsigned int target, Rectangle *rect); + private: class Stream : protected Loggable { @@ -74,6 +77,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/converter_v4l2_m2m.cpp b/src/libcamera/converter/converter_v4l2_m2m.cpp index d8929fc5..2d3ee257 100644 --- a/src/libcamera/converter/converter_v4l2_m2m.cpp +++ b/src/libcamera/converter/converter_v4l2_m2m.cpp @@ -155,6 +155,15 @@ int V4L2M2MConverter::Stream::queueBuffers(FrameBuffer *input, FrameBuffer *outp return 0; } +int V4L2M2MConverter::Stream::setSelection(unsigned int target, Rectangle *rect) +{ + int ret = m2m_->output()->setSelection(target, rect); + if (ret < 0) + return ret; + + return 0; +} + std::string V4L2M2MConverter::Stream::logPrefix() const { return "stream" + std::to_string(index_); @@ -370,6 +379,23 @@ int V4L2M2MConverter::exportBuffers(unsigned int output, unsigned int count, return streams_[output].exportBuffers(count, buffers); } +/** + * \brief Set a selection rectangle \a rect for \a target + * \param[in] output Index of the output stream + * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags + * \param[inout] rect The selection rectangle to be applied + * + * \return 0 on success or a negative error code otherwise + */ +int V4L2M2MConverter::setSelection(unsigned int output, unsigned int target, + Rectangle *rect) +{ + if (output >= streams_.size()) + return -EINVAL; + + return streams_[output].setSelection(target, rect); +} + /** * \copydoc libcamera::Converter::start */ From patchwork Sun May 19 11:56:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20073 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 571D2BDE6B for ; Sun, 19 May 2024 11:56:40 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D68E063485; Sun, 19 May 2024 13:56:38 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FSjnzaSj"; 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 2611B6347F for ; Sun, 19 May 2024 13:56:35 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:9278:2c85:fd02:c5f5]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7EBAB49E; Sun, 19 May 2024 13:56:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716119784; bh=PtQWX2WM8kD2tTj/2w3Z0x26CvwoXAMHITfpkjO/VkI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FSjnzaSjcwOmYhM4qLHtww7UBPBqp0HQSd+RgoNWM3IqQkGy8iQZYQiujbvlphwU8 1YSrXQ1aEhwH+EKWzYg4UaOAoB1dB0EQ9zZBF3sRySWHj/gXGuWEpDsaKi88pfrxqX nqCOYZOUbvlc2Cfk30CDoSInV5+4/xeOL7a6+S9o= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v2 3/4] libcamera: rkisp1: Add base class DW100 dewarper Date: Sun, 19 May 2024 17:26:21 +0530 Message-ID: <20240519115622.32170-4-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240519115622.32170-1-umang.jain@ideasonboard.com> References: <20240519115622.32170-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 base RkISP1Dewarper class (inherited from V4L2M2MConverter) which then can be used to load a dewarp config file and scaling capabilites. \todo: Add plumbing to load a vertex map on top Signed-off-by: Umang Jain --- src/libcamera/pipeline/rkisp1/meson.build | 1 + .../pipeline/rkisp1/rkisp1_dewarper.cpp | 38 +++++++++++++++++++ .../pipeline/rkisp1/rkisp1_dewarper.h | 25 ++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 src/libcamera/pipeline/rkisp1/rkisp1_dewarper.cpp create mode 100644 src/libcamera/pipeline/rkisp1/rkisp1_dewarper.h diff --git a/src/libcamera/pipeline/rkisp1/meson.build b/src/libcamera/pipeline/rkisp1/meson.build index cad66535..e8a989b1 100644 --- a/src/libcamera/pipeline/rkisp1/meson.build +++ b/src/libcamera/pipeline/rkisp1/meson.build @@ -2,5 +2,6 @@ libcamera_sources += files([ 'rkisp1.cpp', + 'rkisp1_dewarper.cpp', 'rkisp1_path.cpp', ]) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.cpp new file mode 100644 index 00000000..0bd72497 --- /dev/null +++ b/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.cpp @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024, Ideas On Board Oy + * + * i.MX8MP Dewarp Engine integration + */ + +#include "rkisp1_dewarper.h" + +#include + +#include + +#include "libcamera/internal/media_device.h" +#include "libcamera/internal/v4l2_videodevice.h" + +namespace libcamera { + +LOG_DECLARE_CATEGORY(RkISP1) + +RkISP1Dewarper::RkISP1Dewarper(std::shared_ptr media) + : V4L2M2MConverter(media.get()) +{ +} + +int RkISP1Dewarper::setScalerCrop(unsigned int output, Rectangle rect) +{ + int ret; + + ret = setSelection(output, V4L2_SEL_TGT_CROP, &rect); + if (ret < 0) + LOG(RkISP1, Error) << "Failed to set scaler crop on dewarper " + << strerror(-ret); + + return ret; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.h b/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.h new file mode 100644 index 00000000..600e35bd --- /dev/null +++ b/src/libcamera/pipeline/rkisp1/rkisp1_dewarper.h @@ -0,0 +1,25 @@ +/* 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 Rectangle; +struct MediaDevice; + +class RkISP1Dewarper : public V4L2M2MConverter +{ +public: + RkISP1Dewarper(std::shared_ptr media); + + int setScalerCrop(unsigned int output, Rectangle rect); +}; + +} /* namespace libcamera */ From patchwork Sun May 19 11:56:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 20074 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 639DEC32C9 for ; Sun, 19 May 2024 11:56:42 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D0EDC6348C; Sun, 19 May 2024 13:56:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="nuEMpAln"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1023163469 for ; Sun, 19 May 2024 13:56:36 +0200 (CEST) Received: from fedora.local (unknown [IPv6:2405:201:2015:f873:9278:2c85:fd02:c5f5]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id D1021581; Sun, 19 May 2024 13:56:24 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1716119785; bh=ZbCQ4nzEFPfOeGNoDzV5NIc4tAIqpRTRQ9OTv3m1M7Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nuEMpAlniyrq4z5419QeM/diRvCEerRglo4bTw6XLutQy/GHhwX827/EfaOUidVIG 2k9xlXSfhvpgWGHu75wgjUDW3zxYYXEiwioC4FCZXVBOo6BPUhgp28vdrV3FJGtIXP EjW3/KmgSlF7epen/JZFUoJsn27RzhHkAnGoTezY= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Umang Jain Subject: [PATCH v2 4/4] libcamera: rkisp1: Plumb through RkISP1Dewarper Date: Sun, 19 May 2024 17:26:22 +0530 Message-ID: <20240519115622.32170-5-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240519115622.32170-1-umang.jain@ideasonboard.com> References: <20240519115622.32170-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 DW100 RkISP1Dewarper 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 dewarper. Register the ScalerCrop control for the cameras created in the RKISP1 pipeline handler. Signed-off-by: Umang Jain --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 137 +++++++++++++++++- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 12 +- src/libcamera/pipeline/rkisp1/rkisp1_path.h | 14 ++ 3 files changed, 155 insertions(+), 8 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index bfc44239..aa4c9aa2 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 @@ -42,6 +44,7 @@ #include "libcamera/internal/v4l2_subdevice.h" #include "libcamera/internal/v4l2_videodevice.h" +#include "rkisp1_dewarper.h" #include "rkisp1_path.h" namespace libcamera { @@ -62,6 +65,8 @@ struct RkISP1FrameInfo { bool paramDequeued; bool metadataProcessed; + + std::optional scalerCrop; }; class RkISP1Frames @@ -165,6 +170,8 @@ public: private: static constexpr Size kRkISP1PreviewSize = { 1920, 1080 }; + static constexpr Size kMinDewarpSize = { 176, 144 }; + static constexpr Size kMaxDewarpSize = { 4096, 3072 }; RkISP1CameraData *cameraData(Camera *camera) { @@ -181,6 +188,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 +208,13 @@ private: RkISP1MainPath mainPath_; RkISP1SelfPath selfPath_; + std::unique_ptr dewarper_; + std::map dewarpOutputBufs_; + + /* 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 +237,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 +256,16 @@ RkISP1FrameInfo *RkISP1Frames::create(const RkISP1CameraData *data, Request *req statBuffer = pipe_->availableStatBuffers_.front(); pipe_->availableStatBuffers_.pop(); + + if (pipe_->dewarper_) { + 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 +291,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 +307,7 @@ void RkISP1Frames::clear() pipe_->availableParamBuffers_.push(info->paramBuffer); pipe_->availableStatBuffers_.push(info->statBuffer); + pipe_->availableMainPathBuffers_.push(info->mainPathBuffer); delete info; } @@ -785,12 +810,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); + } else if (dewarper_ && isRaw_) { + LOG(RkISP1, Debug) << "Dewarper disabled on RAW configuration"; + dewarper_.reset(); + } + } else if (hasSelfPath_) { ret = selfPath_.configure(cfg, format); streamConfig[1] = IPAStream(cfg.pixelFormat, @@ -839,6 +878,9 @@ int PipelineHandlerRkISP1::exportFrameBuffers([[maybe_unused]] Camera *camera, S RkISP1CameraData *data = cameraData(camera); unsigned int count = stream->configuration().bufferCount; + if (!isRaw_ && dewarper_) + return dewarper_->exportBuffers(0, count, buffers); + if (stream == &data->mainPathStream_) return mainPath_.exportBuffers(count, buffers); else if (hasSelfPath_ && stream == &data->selfPathStream_) @@ -866,6 +908,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 (dewarper_) { + 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 +941,7 @@ int PipelineHandlerRkISP1::allocateBuffers(Camera *camera) error: paramBuffers_.clear(); statBuffers_.clear(); + mainPathBuffers_.clear(); return ret; } @@ -903,8 +956,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 +976,9 @@ int PipelineHandlerRkISP1::freeBuffers(Camera *camera) if (stat_->releaseBuffers()) LOG(RkISP1, Error) << "Failed to release stat buffers"; + if (dewarper_) + mainPath_.releaseBuffers(); + return 0; } @@ -961,6 +1021,14 @@ int PipelineHandlerRkISP1::start(Camera *camera, [[maybe_unused]] const ControlL << "Failed to start statistics " << camera->id(); return ret; } + + if (dewarper_) { + ret = dewarper_->start(); + if (ret) { + LOG(RkISP1, Error) << "Failed to start dewarper"; + return ret; + } + } } if (data->mainPath_->isEnabled()) { @@ -1015,6 +1083,9 @@ void PipelineHandlerRkISP1::stopDevice(Camera *camera) if (ret) LOG(RkISP1, Warning) << "Failed to stop parameters for " << camera->id(); + + if (dewarper_) + dewarper_->stop(); } ASSERT(data->queuedRequests_.empty()); @@ -1045,6 +1116,13 @@ int PipelineHandlerRkISP1::queueRequestDevice(Camera *camera, Request *request) info->paramBuffer->cookie()); } + const auto &crop = request->controls().get(controls::ScalerCrop); + if (crop && !isRaw_) { + int ret = dewarper_->setScalerCrop(0, crop.value()); + if (!ret) + info->scalerCrop = crop; + } + data->frame_++; return 0; @@ -1110,6 +1188,13 @@ int PipelineHandlerRkISP1::updateControls(RkISP1CameraData *data) { ControlInfoMap::Map rkisp1Controls; + if (dewarper_) { + Rectangle maxCrop(kMaxDewarpSize); + Rectangle minCrop = kMinDewarpSize.centeredTo(maxCrop.center()); + + 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 +1258,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) bool PipelineHandlerRkISP1::match(DeviceEnumerator *enumerator) { + std::shared_ptr dwpMediaDevice; const MediaPad *pad; DeviceMatch dm("rkisp1"); @@ -1237,6 +1323,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 +1389,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 +1406,36 @@ void PipelineHandlerRkISP1::bufferReady(FrameBuffer *buffer) data->delayedCtrls_->get(metadata.sequence); data->ipa_->processStatsBuffer(info->frame, 0, ctrls); } + } else { if (isRaw_) info->metadataProcessed = true; } + if (dewarper_) { + dewarpOutputBufs_[0] = request->findBuffer(&data->mainPathStream_); + + dewarper_->queueBuffers(buffer, dewarpOutputBufs_); + 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_;