From patchwork Thu Oct 3 07:47:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Naushir Patuck X-Patchwork-Id: 21493 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 9509DC32DB for ; Thu, 3 Oct 2024 07:54:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 719A163530; Thu, 3 Oct 2024 09:54:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (2048-bit key; unprotected) header.d=raspberrypi.com header.i=@raspberrypi.com header.b="TS5R9rXD"; dkim-atps=neutral Received: from mail-wm1-x331.google.com (mail-wm1-x331.google.com [IPv6:2a00:1450:4864:20::331]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D089563530 for ; Thu, 3 Oct 2024 09:53:50 +0200 (CEST) Received: by mail-wm1-x331.google.com with SMTP id 5b1f17b1804b1-42ca4e0014dso949645e9.2 for ; Thu, 03 Oct 2024 00:53:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=raspberrypi.com; s=google; t=1727942030; x=1728546830; 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=LJAXZj7wiaO7Oa3XnUk7pfIlTYztCA94P+HfSdQLQC0=; b=TS5R9rXDgDsMMskVOO3InYtZrvI6b6ipUdWqKvW7giYvlx+mXBiu4PyCScP5/CKNwK 6I7ytxUem6/DrZaVfbIkBGIj7rpEG6g2lV0pWrXYpeLIPTxnkgM1ozZammmjcti2HDpI COetDdciwdjfHgzuBspMR0lamc18td8eVkmsKm6VrU8Tsgl0C8N7mX9cf6CxIeqZaX4q 8G4nWV3EgXv8wd7URwpttVUNtvZ8wvVlfyEpPI7KvaGhrsQwT5bFAYXEdAr9AysI/34B z3QXrMQR1oNqG2bw3XbnF2nfsGN6/aAyrCIt4JcKjSKN+IPIoQmScq7xP22uFX8xIm5Q CpGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1727942030; x=1728546830; 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=LJAXZj7wiaO7Oa3XnUk7pfIlTYztCA94P+HfSdQLQC0=; b=pQc1VX2B0wsB0BhxA8oh+PWeYVOQxM+pk1AjFuIUOz7kjD8z69win+LwgUQCdBF2Oc 3vB5m5xNhS3PKYgr87Zk86RsFQdyITDIwGQrLXuv9sHTVs3ftU+xI6VPmGCEtTFAHZjn NUeHprVytQIZFmpwenFJFeEDDq8lzocqFMq0txDJnP8vMGU4fFw8XlUGQus7z+QmOu9E zWq7xTWgNHrrOzFddogTXSJp2RdPvWQ/j4C1p647D7asOtLBs/KHldnghY4dJr48hrLD 75PzaX1fqzIz4fIGA+NyycmynKcV1OFnWW2isIwIWyr4MP1GOp8xr3X+ZlSFqCEpRTA2 zeEg== X-Gm-Message-State: AOJu0YwyVz3st4JQ/kN8sDB9AdJm4Jx+qY6uOr343tzz5GbMTBKCfCvi a9GX2WpXzp7X6UM8IxzSXKptnRejOKTOzlb2gJhCliskWvIi2NLc8UNzV94huZmYsQMBQH8Qc2b Z X-Google-Smtp-Source: AGHT+IGqKnJO7cDNKvE+rq+2a48gxIUnBho1u9T434peERQGuKb20WclxJqVo8hhP0E8bFC45jVS4Q== X-Received: by 2002:a05:600c:4f50:b0:42c:c59a:ac21 with SMTP id 5b1f17b1804b1-42f777b0b7fmr21661395e9.2.1727942029973; Thu, 03 Oct 2024 00:53:49 -0700 (PDT) Received: from naush-laptop.pitowers.org ([93.93.133.154]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-42f8025b583sm8740825e9.12.2024.10.03.00.53.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 03 Oct 2024 00:53:49 -0700 (PDT) From: Naushir Patuck To: libcamera-devel@lists.libcamera.org Cc: Naushir Patuck , Jacopo Mondi Subject: [PATCH v3 7/7] pipeline: rpi: Handler controls::rpi::ScalerCrops Date: Thu, 3 Oct 2024 08:47:20 +0100 Message-Id: <20241003074720.18882-8-naush@raspberrypi.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241003074720.18882-1-naush@raspberrypi.com> References: <20241003074720.18882-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 Reviewed-by: Jacopo Mondi --- .../pipeline/rpi/common/pipeline_base.cpp | 76 ++++++++++++++----- 1 file changed, 59 insertions(+), 17 deletions(-) diff --git a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp index 267e6bd9cd70..eba4dad6d212 100644 --- a/src/libcamera/pipeline/rpi/common/pipeline_base.cpp +++ b/src/libcamera/pipeline/rpi/common/pipeline_base.cpp @@ -181,12 +181,14 @@ CameraConfiguration::Status RPiCameraConfiguration::validate() rawStreams_.clear(); outStreams_.clear(); + unsigned int rawStreamIndex = 0; + unsigned int outStreamIndex = 0; - for (const auto &[index, cfg] : utils::enumerate(config_)) { + for (auto &cfg : config_) { if (PipelineHandlerBase::isRaw(cfg.pixelFormat)) - rawStreams_.emplace_back(index, &cfg); + rawStreams_.emplace_back(rawStreamIndex++, &cfg); else - outStreams_.emplace_back(index, &cfg); + outStreams_.emplace_back(outStreamIndex++, &cfg); } /* Sort the streams so the highest resolution is first. */ @@ -565,10 +567,24 @@ int PipelineHandlerBase::configure(Camera *camera, CameraConfiguration *config) const auto cropParamsIt = data->cropParams_.find(0); if (cropParamsIt != data->cropParams_.end()) { const CameraData::CropParams &cropParams = cropParamsIt->second; - /* Add the ScalerCrop control limits based on the current mode. */ + /* + * Add the ScalerCrop control limits based on the current mode and + * the first configured stream. + */ Rectangle ispMinCrop = data->scaleIspCrop(Rectangle(cropParams.ispMinCropSize)); ctrlMap[&controls::ScalerCrop] = ControlInfo(ispMinCrop, data->sensorInfo_.analogCrop, data->scaleIspCrop(cropParams.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_.at(0).ispCrop), + data->scaleIspCrop(data->cropParams_.at(1).ispCrop), + ctrlMap[&controls::ScalerCrop].def()); + } } data->controlInfo_ = ControlInfoMap(std::move(ctrlMap), result.controlInfo.idmap()); @@ -1295,11 +1311,29 @@ Rectangle CameraData::scaleIspCrop(const Rectangle &ispCrop) const void CameraData::applyScalerCrop(const ControlList &controls) { - const auto &scalerCrop = controls.get(controls::ScalerCrop); - const auto cropParamsIt = cropParams_.find(0); - if (scalerCrop && cropParamsIt != cropParams_.end()) { - Rectangle nativeCrop = *scalerCrop; - CropParams &cropParams = cropParamsIt->second; + 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 }; @@ -1315,13 +1349,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_.at(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_.at(i).ispCrop) { + cropParams_.at(i).ispCrop = ispCrop; + platformSetIspCrop(cropParams_.at(i).ispIndex, ispCrop); } } } @@ -1478,10 +1512,18 @@ void CameraData::fillRequestMetadata(const ControlList &bufferControls, Request request->metadata().set(controls::SensorTimestamp, bufferControls.get(controls::SensorTimestamp).value_or(0)); - const auto cropParamsIt = cropParams_.find(0); - if (cropParamsIt != cropParams_.end()) - request->metadata().set(controls::ScalerCrop, - scaleIspCrop(cropParamsIt->second.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]); + if (crops.size() > 1) { + request->metadata().set(controls::rpi::ScalerCrops, + Span(crops.data(), crops.size())); + } + } } } /* namespace libcamera */