From patchwork Thu Oct 3 13:57:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 21499 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 1DD49C3263 for ; Thu, 3 Oct 2024 13:57:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8DF2063524; Thu, 3 Oct 2024 15:57:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="TxUFZDfE"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 54A5562C92 for ; Thu, 3 Oct 2024 15:57:51 +0200 (CEST) Received: from umang.jain (unknown [IPv6:2405:201:2015:f873:55d7:c02e:b2eb:ee3f]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B27FB593; Thu, 3 Oct 2024 15:56:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1727963777; bh=jIhGs+F6oISbMbPQuV9fo+m7xKLJwScfPlhZ5AG+wsM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TxUFZDfEwJd6BJHo5BeKfD7usbGo3BM4N8+otWiLNbaTUwc39Ni24bQlLLIPP58D8 okIdxZzSHSRx+qLqneEzRAeccotO23kVIqOkaCU0bPrS5TbzlJw02K3y7UwWB67wLu WvzMdNtUbmdVxyl/uPhr/kA3p9/VbgKVqbFZ9ZVk= From: Umang Jain To: libcamera-devel@lists.libcamera.org Cc: Jacopo Mondi , Kieran Bingham , Laurent Pinchart , Paul Elder , Umang Jain Subject: [PATCH v2 2/2] libcamera: rkisp1: Integrate SensorConfiguration support Date: Thu, 3 Oct 2024 19:27:40 +0530 Message-ID: <20241003135741.60869-3-umang.jain@ideasonboard.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20241003135741.60869-1-umang.jain@ideasonboard.com> References: <20241003135741.60869-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" Integrate the RkISP1 pipeline handler to support sensor configuration provided by applications through CameraConfiguration::sensorConfig. The SensorConfiguration must be validated on both RkISP1Path (mainPath and selfPath), so the parameters of RkISP1Path::validate() have been updated to include sensorConfig. Finally, if the sensor configuration fails to apply, the camera configuration validation will be marked as invalid. Signed-off-by: Umang Jain --- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 68 ++++++++++++++++--- src/libcamera/pipeline/rkisp1/rkisp1_path.cpp | 45 ++++++++++-- src/libcamera/pipeline/rkisp1/rkisp1_path.h | 2 + 3 files changed, 100 insertions(+), 15 deletions(-) diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 6cee7893..95e70603 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -447,11 +447,12 @@ bool RkISP1CameraConfiguration::fitsAllPaths(const StreamConfiguration &cfg) StreamConfiguration config; config = cfg; - if (data_->mainPath_->validate(sensor, &config) != Valid) + if (data_->mainPath_->validate(sensor, sensorConfig, &config) != Valid) return false; config = cfg; - if (data_->selfPath_ && data_->selfPath_->validate(sensor, &config) != Valid) + if (data_->selfPath_ && + data_->selfPath_->validate(sensor, sensorConfig, &config) != Valid) return false; return true; @@ -468,6 +469,27 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() status = validateColorSpaces(ColorSpaceFlag::StreamsShareColorSpace); + /* + * Make sure that if a sensor configuration has been requested it + * is valid. + */ + if (sensorConfig && !sensorConfig->isValid()) { + LOG(RkISP1, Error) + << "Invalid sensor configuration request"; + + return Invalid; + } + + if (sensorConfig) { + std::optional bitDepth = sensorConfig->bitDepth; + if (bitDepth != 8 && bitDepth != 10 && bitDepth != 12) { + LOG(RkISP1, Error) + << "Invalid sensor configuration bit depth"; + + return Invalid; + } + } + /* Cap the number of entries to the available streams. */ if (config_.size() > pathCount) { config_.resize(pathCount); @@ -513,7 +535,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() /* Try to match stream without adjusting configuration. */ if (mainPathAvailable) { StreamConfiguration tryCfg = cfg; - if (data_->mainPath_->validate(sensor, &tryCfg) == Valid) { + if (data_->mainPath_->validate(sensor, sensorConfig, &tryCfg) == Valid) { mainPathAvailable = false; cfg = tryCfg; cfg.setStream(const_cast(&data_->mainPathStream_)); @@ -523,7 +545,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() if (selfPathAvailable) { StreamConfiguration tryCfg = cfg; - if (data_->selfPath_->validate(sensor, &tryCfg) == Valid) { + if (data_->selfPath_->validate(sensor, sensorConfig, &tryCfg) == Valid) { selfPathAvailable = false; cfg = tryCfg; cfg.setStream(const_cast(&data_->selfPathStream_)); @@ -534,7 +556,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() /* Try to match stream allowing adjusting configuration. */ if (mainPathAvailable) { StreamConfiguration tryCfg = cfg; - if (data_->mainPath_->validate(sensor, &tryCfg) == Adjusted) { + if (data_->mainPath_->validate(sensor, sensorConfig, &tryCfg) == Adjusted) { mainPathAvailable = false; cfg = tryCfg; cfg.setStream(const_cast(&data_->mainPathStream_)); @@ -545,7 +567,7 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() if (selfPathAvailable) { StreamConfiguration tryCfg = cfg; - if (data_->selfPath_->validate(sensor, &tryCfg) == Adjusted) { + if (data_->selfPath_->validate(sensor, sensorConfig, &tryCfg) == Adjusted) { selfPathAvailable = false; cfg = tryCfg; cfg.setStream(const_cast(&data_->selfPathStream_)); @@ -562,26 +584,47 @@ CameraConfiguration::Status RkISP1CameraConfiguration::validate() /* Select the sensor format. */ PixelFormat rawFormat; + Size rawSize; Size maxSize; for (const StreamConfiguration &cfg : config_) { - if (cfg.pixelFormat.isRaw()) + if (cfg.pixelFormat.isRaw()) { rawFormat = cfg.pixelFormat; + rawSize = cfg.size; + } maxSize = std::max(maxSize, cfg.size); } + if (rawFormat.isValid() && sensorConfig) { + const PixelFormatInfo &info = PixelFormatInfo::info(rawFormat); + if (sensorConfig->outputSize != rawSize || + sensorConfig->bitDepth != info.bitsPerPixel) + return Invalid; + } + std::vector mbusCodes; + Size sz = maxSize; if (rawFormat.isValid()) { mbusCodes = { rawFormats.at(rawFormat) }; + sz = rawSize; + } else if (sensorConfig) { + /* sensorConfig has been validated by RkISP1Path::validate(). */ + for (const auto &value : rawFormats) { + const PixelFormatInfo &info = PixelFormatInfo::info(value.first); + if (info.bitsPerPixel == sensorConfig->bitDepth) + mbusCodes.push_back(value.second); + } + + sz = sensorConfig->outputSize; } else { std::transform(rawFormats.begin(), rawFormats.end(), std::back_inserter(mbusCodes), [](const auto &value) { return value.second; }); } - sensorFormat_ = sensor->getFormat(mbusCodes, maxSize); + sensorFormat_ = sensor->getFormat(mbusCodes, sz); if (sensorFormat_.size.isNull()) sensorFormat_.size = sensor->resolution(); @@ -721,7 +764,14 @@ int PipelineHandlerRkISP1::configure(Camera *camera, CameraConfiguration *c) V4L2SubdeviceFormat format = config->sensorFormat(); LOG(RkISP1, Debug) << "Configuring sensor with " << format; - ret = sensor->setFormat(&format, config->combinedTransform()); + if (config->sensorConfig) { + ret = sensor->applyConfiguration(*config->sensorConfig, + config->combinedTransform(), + &format); + } else { + ret = sensor->setFormat(&format, config->combinedTransform()); + } + if (ret < 0) return ret; diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp index e7f1f12a..93c7c7dc 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.cpp @@ -250,8 +250,10 @@ RkISP1Path::generateConfiguration(const CameraSensor *sensor, const Size &size, return cfg; } -CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor, - StreamConfiguration *cfg) +CameraConfiguration::Status +RkISP1Path::validate(const CameraSensor *sensor, + std::optional &sensorConfig, + StreamConfiguration *cfg) { const std::vector &mbusCodes = sensor->mbusCodes(); @@ -278,11 +280,18 @@ CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor, continue; /* - * Store the raw format with the highest bits per pixel - * for later usage. + * If the bits per pixel is supplied from the sensor + * configuration, choose a raw format that complies with + * it. Otherwise, store the raw format with the highest + * bits per pixel for later usage. */ const PixelFormatInfo &info = PixelFormatInfo::info(format); - if (info.bitsPerPixel > rawBitsPerPixel) { + + if (sensorConfig && + info.bitsPerPixel == sensorConfig->bitDepth) { + rawFormat = format; + rawBitsPerPixel = info.bitsPerPixel; + } else if (info.bitsPerPixel > rawBitsPerPixel) { rawBitsPerPixel = info.bitsPerPixel; rawFormat = format; } @@ -315,11 +324,35 @@ CameraConfiguration::Status RkISP1Path::validate(const CameraSensor *sensor, * size. */ uint32_t mbusCode = formatToMediaBus.at(cfg->pixelFormat); + Size rawSize = sensorConfig ? sensorConfig->outputSize + : cfg->size; V4L2SubdeviceFormat sensorFormat = - sensor->getFormat({ mbusCode }, cfg->size); + sensor->getFormat({ mbusCode }, rawSize); + + if (sensorConfig && + sensorFormat.size != sensorConfig->outputSize) + return CameraConfiguration::Invalid; minResolution = sensorFormat.size; maxResolution = sensorFormat.size; + } else if (sensorConfig) { + /* + * We have already ensured 'rawFormat' has the matching bit + * depth with sensorConfig.bitDepth hence, only validate the + * sensorConfig's output size here. + * */ + uint32_t mbusCode = formatToMediaBus.at(rawFormat); + Size sensorSize = sensorConfig->outputSize; + + V4L2SubdeviceFormat sensorFormat = + sensor->getFormat({ mbusCode }, sensorSize); + + if (sensorFormat.size != sensorSize) + return CameraConfiguration::Invalid; + + minResolution = minResolution_.expandedToAspectRatio(sensorSize); + maxResolution = maxResolution_.boundedToAspectRatio(sensorSize) + .boundedTo(sensorSize); } else { Size resolution = filterSensorResolution(sensor); diff --git a/src/libcamera/pipeline/rkisp1/rkisp1_path.h b/src/libcamera/pipeline/rkisp1/rkisp1_path.h index 777fcae7..ce9a5666 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1_path.h +++ b/src/libcamera/pipeline/rkisp1/rkisp1_path.h @@ -27,6 +27,7 @@ namespace libcamera { class CameraSensor; class MediaDevice; class V4L2Subdevice; +class SensorConfiguration; struct StreamConfiguration; struct V4L2SubdeviceFormat; @@ -44,6 +45,7 @@ public: const Size &resolution, StreamRole role); CameraConfiguration::Status validate(const CameraSensor *sensor, + std::optional &sensorConfig, StreamConfiguration *cfg); int configure(const StreamConfiguration &config,