From patchwork Thu Aug 8 10:23:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 20838 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 ADBCBC324E for ; Thu, 8 Aug 2024 10:24:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 79E1D633C4; Thu, 8 Aug 2024 12:24:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="B5BEjglt"; dkim-atps=neutral Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 71479633B4 for ; Thu, 8 Aug 2024 12:23:51 +0200 (CEST) Received: by mail-wr1-x436.google.com with SMTP id ffacd0b85a97d-369f68f63b1so420101f8f.2 for ; Thu, 08 Aug 2024 03:23:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1723112631; x=1723717431; darn=lists.libcamera.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FutAzOzdno63Zw2uUf3aHTsbgoCwqzcG1+IrkzQMZCA=; b=B5BEjglti5iYCcxCEvcfT/HjN5KGQzQBvzuHRQLkTOmQ6THpiZ3vC/H8K+gk06h2kR 5AsX5j5z8+qDFjKr+udrISZuQJVvgkYHGINGzAJ2GI5z2FjH2ZK/NOqIm5ukNf/1OKeZ N5lZaIJFU4w7Xn/0sXAiXa1WqTh0au1pnncfH5gzdm8ylDtgHQ+lyZANRMn/LACcBqwh JwYySHWSoUHq0D7O+ezvvjgdyrvJSURbsJlFS5YDI2r2gJiEV5LkcWg4zxFsvr5DlXKV xyieGFxrCoTFjT/qVHFYh8gwMD+nLPhK/er6XTnaTNucUlnarUINFFhUvvkdZDDOFrt3 adAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1723112631; x=1723717431; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FutAzOzdno63Zw2uUf3aHTsbgoCwqzcG1+IrkzQMZCA=; b=ftjNY/09a/AbgWhq0qKVuYwCQlySe0Ux6EfJsKrpgo13bkO4tt4ywM8WNZiQYrw2se Yuch6p1YVkdFFGPi7s7xTldZOrUBb9aQsEJwUpRTZIfeAu3pcLFQUaLisTkB0sMDOoC0 kdX9+XeVtxeD8X7xaue9ocZr8k9AU584YM7zYmFT3Eahj3rvoBXDtPYJld0Tmny3PZlO 4W+tXUyrJMmFN6Un7ekPrkH9EBncZjXQB2U7qLzo2QpJxsWNSp8Mda0WVhpDrc1Z4pp4 MdJfI+f2tJ04LB8K+FsDlh04ESaiValWLV1wjGjssubS7ZU9uU3VwxCYYFimzPcWsgfU qcuQ== X-Gm-Message-State: AOJu0YyApFtdPz237lJsnXXapFCVvhSk0hAGPuMBZbK1TqZ1ttVavI0N qyfJsoXZ9nBMSvbEQnwnZ/v8hesu/l8DTkFVZvETtGLpVRiemDEA6UP4m6Z0hWVWFhb+s9GMNBi R X-Google-Smtp-Source: AGHT+IHf8KONfa8fzGhfky3HDVP/MfpyOgsmFt+8bcW9H+Sewrl2QhY7uqNebMA2jCdxvpVzR7i1bw== X-Received: by 2002:adf:cf05:0:b0:36b:a3c8:12aa with SMTP id ffacd0b85a97d-36d274dcc2fmr931558f8f.26.1723112630516; Thu, 08 Aug 2024 03:23:50 -0700 (PDT) Received: from naush-laptop.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36d272290c2sm1404234f8f.92.2024.08.08.03.23.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Aug 2024 03:23:50 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Naushir Patuck Subject: [PATCH v1 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops Date: Thu, 8 Aug 2024 11:23:46 +0100 Message-Id: <20240808102346.13065-8-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240808102346.13065-1-naush@raspberrypi.com> References: <20240808102346.13065-1-naush@raspberrypi.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" Handle multiple scaler crops being set through the rpi::ScalerCrops control. We now populate the cropParams_ map in the loop where we handle the output stream configuration items. The key of this map is the index of the stream configuration structure set by the application. This will also be the same index used to specify the crop rectangles through the ScalerCrops control. CameraData::applyScalerCrop() has been adapted to look at either controls::ScalerCrop or controls::rpi::ScalerCrops. The former takes priority over the latter, and if present, will apply the same scaler crop to all output streams. Finally return all crops through the same ScalerCrops control via request metadata. The first configure stream's crop rectangle is also returned via the ScalerCrop control in the request metadata. Signed-off-by: Naushir Patuck --- .../pipeline/rpi/common/pipeline_base.cpp | 69 +++++++++++++++---- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index a6ea4e9c47dd..b9759b682f0d 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -561,11 +561,28 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config) for (auto const &c : result.controlInfo) ctrlMap.emplace(c.first, c.second); - if (data->cropParams_.count(0)) { - /* Add the ScalerCrop control limits based on the current mode. */ + if (data->cropParams_.size()) { + /* + * Add the ScalerCrop control limits based on the current mode and + * the first configured stream. + */ Rectangle ispMinCrop = data->scaleIspCrop(Rectangle(data->cropParams_[0].ispMinCropSize)); ctrlMap[&controls::ScalerCrop] = ControlInfo(ispMinCrop, data->sensorInfo_.analogCrop, data->scaleIspCrop(data->cropParams_[0].ispCrop)); + if (data->cropParams_.size() == 2) { + /* + * The control map for rpi::ScalerCrops has the min value + * as the default crop for stream 0, max value as the default + * value for stream 1. + */ + ctrlMap[&controls::rpi::ScalerCrops] = + ControlInfo(data->scaleIspCrop(data->cropParams_[0].ispCrop), + data->scaleIspCrop(data->cropParams_[1].ispCrop), + ctrlMap[&controls::ScalerCrop].def()); + } else { + /* Match the same ControlInfo for rpi::ScalerCrops. */ + ctrlMap[&controls::rpi::ScalerCrops] = ctrlMap[&controls::ScalerCrop]; + } } data->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap()); @@ -1292,10 +1309,29 @@ Rectangle CameraData::scaleIspCrop(const Rectangle &ispCrop) const void CameraData::applyScalerCrop(const ControlList &controls) { - const auto &scalerCrop = controls.get(controls::ScalerCrop); - if (scalerCrop && cropParams_.count(0)) { - CropParams &cropParams = cropParams_[0]; - Rectangle nativeCrop = *scalerCrop; + const auto &scalerCropRPi = controls.get>(controls::rpi::ScalerCrops); + const auto &scalerCropCore = controls.get(controls::ScalerCrop); + std::vector scalerCrops; + + /* + * First thing to do is create a vector of crops to apply to each ISP output + * based on either controls::ScalerCrop or controls::rpi::ScalerCrops if + * present. + * + * If controls::ScalerCrop is present, apply the same crop to all ISP output + * streams. Otherwise if controls::rpi::ScalerCrops, apply the given crops + * to the ISP output streams, indexed by the same order in which they had + * been configured. This is not the same as the ISP output index. + */ + for (unsigned int i = 0; i < cropParams_.size(); i++) { + if (scalerCropRPi && i < scalerCropRPi->size()) + scalerCrops.push_back(scalerCropRPi->data()[i]); + else if (scalerCropCore) + scalerCrops.push_back(*scalerCropCore); + } + + for (auto const &[i, scalerCrop] : utils::enumerate(scalerCrops)) { + Rectangle nativeCrop = scalerCrop; if (!nativeCrop.width || !nativeCrop.height) nativeCrop = { 0, 0, 1, 1 }; @@ -1311,13 +1347,13 @@ void CameraData::applyScalerCrop(const ControlList &controls) * 2. With the same mid-point, if possible. * 3. But it can't go outside the sensor area. */ - Size minSize = cropParams.ispMinCropSize.expandedToAspectRatio(nativeCrop.size()); + Size minSize = cropParams_[i].ispMinCropSize.expandedToAspectRatio(nativeCrop.size()); Size size = ispCrop.size().expandedTo(minSize); ispCrop = size.centeredTo(ispCrop.center()).enclosedIn(Rectangle(sensorInfo_.outputSize)); - if (ispCrop != cropParams.ispCrop) { - cropParams.ispCrop = ispCrop; - platformSetIspCrop(cropParams.ispIndex, ispCrop); + if (ispCrop != cropParams_[i].ispCrop) { + cropParams_[i].ispCrop = ispCrop; + platformSetIspCrop(cropParams_[i].ispIndex, ispCrop); } } } @@ -1474,9 +1510,16 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request request->metadata().set(controls::SensorTimestamp, bufferControls.get(controls::SensorTimestamp).value_or(0)); - if (cropParams_.count(0)) - request->metadata().set(controls::ScalerCrop, - scaleIspCrop(cropParams_[0].ispCrop)); + if (cropParams_.size()) { + std::vector crops; + + for (auto const &[k, v] : cropParams_) + crops.push_back(scaleIspCrop(v.ispCrop)); + + request->metadata().set(controls::ScalerCrop, crops[0]); + request->metadata().set(controls::rpi::ScalerCrops, + Span(crops.data(), crops.size())); + } } } /* namespace libcamera */