From patchwork Fri Nov 15 10:13:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dan Scally X-Patchwork-Id: 21916 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 49BD7C330D for ; Fri, 15 Nov 2024 10:14:24 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4E6E16589B; Fri, 15 Nov 2024 11:14:23 +0100 (CET) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="liVdqd3G"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id ECADB65876 for ; Fri, 15 Nov 2024 11:13:52 +0100 (CET) Received: from mail.ideasonboard.com (cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 59BDE15D2; Fri, 15 Nov 2024 11:13:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1731665618; bh=aeGAhW1AW3dO2WH6PyXxomXS0mwwEiltIZLIZ0J/5kk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=liVdqd3GFzOBXqbmbu6Jhl1U42LlmaCtAqF7rSJPE7SUtcCdaS9+p6OIZXBaSBaMR 9Jhn6DtJ8WICoEeMby5/Ubx0bUOKdy9lMNkMYQb3InBexA8YfRrODRQQXOd7LaYA8U 6tTv458T3496bQm7M1dlo9POBZYmzFn2GauCLWEw= From: Daniel Scally To: libcamera-devel@lists.libcamera.org Cc: Anthony.McGivern@arm.com, Jacopo Mondi , Kieran Bingham , Daniel Scally Subject: [PATCH v6 14/14] libcamera: mali-c55: implement support for ScalerCrop Date: Fri, 15 Nov 2024 10:13:34 +0000 Message-Id: <20241115101334.453104-15-dan.scally@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20241115101334.453104-1-dan.scally@ideasonboard.com> References: <20241115101334.453104-1-dan.scally@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" From: Jacopo Mondi Implement support for the ScalerCrop control that allows to apply a digital zoom to the captured streams. Initialize the camera controls at camera registration time and update them at configure time as the sensor's analogue crop size might change depending on the desired Camera configuration. Reviewed-by: Kieran Bingham Reviewed-by: Daniel Scally Signed-off-by: Jacopo Mondi Signed-off-by: Daniel Scally --- Changes in v6: - None Changes in v5: - None src/libcamera/pipeline/mali-c55/mali-c55.cpp | 135 +++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp index d0218349..3fc07a5d 100644 --- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp +++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp @@ -22,6 +22,8 @@ #include #include +#include + #include "libcamera/internal/bayer_format.h" #include "libcamera/internal/camera.h" #include "libcamera/internal/camera_sensor.h" @@ -85,6 +87,8 @@ public: int pixfmtToMbusCode(const PixelFormat &pixFmt) const; const PixelFormat &bestRawFormat() const; + void updateControls(); + PixelFormat adjustRawFormat(const PixelFormat &pixFmt) const; Size adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const; @@ -266,6 +270,27 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const return invalidPixFmt; } +void MaliC55CameraData::updateControls() +{ + if (!sensor_) + return; + + IPACameraSensorInfo sensorInfo; + int ret = sensor_->sensorInfo(&sensorInfo); + if (ret) { + LOG(MaliC55, Error) << "Failed to retrieve sensor info"; + return; + } + + ControlInfoMap::Map controls; + Rectangle ispMinCrop{ 0, 0, 640, 480 }; + controls[&controls::ScalerCrop] = + ControlInfo(ispMinCrop, sensorInfo.analogCrop, + sensorInfo.analogCrop); + + controlInfo_ = ControlInfoMap(std::move(controls), controls::controls); +} + /* * Make sure the provided raw pixel format is supported and adjust it to * one of the supported ones if it's not. @@ -553,6 +578,8 @@ private: const StreamConfiguration &config, V4L2SubdeviceFormat &subdevFormat); + void applyScalerCrop(Camera *camera, const ControlList &controls); + void registerMaliCamera(std::unique_ptr data, const std::string &name); bool registerTPGCamera(MediaLink *link); @@ -880,6 +907,8 @@ int PipelineHandlerMaliC55::configure(Camera *camera, pipe->stream = stream; } + data->updateControls(); + return 0; } @@ -927,6 +956,102 @@ void PipelineHandlerMaliC55::stopDevice([[maybe_unused]] Camera *camera) } } +void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera, + const ControlList &controls) +{ + MaliC55CameraData *data = cameraData(camera); + + const auto &scalerCrop = controls.get(controls::ScalerCrop); + if (!scalerCrop) + return; + + if (!data->sensor_) { + LOG(MaliC55, Error) << "ScalerCrop not supported for TPG"; + return; + } + + Rectangle nativeCrop = *scalerCrop; + + IPACameraSensorInfo sensorInfo; + int ret = data->sensor_->sensorInfo(&sensorInfo); + if (ret) { + LOG(MaliC55, Error) << "Failed to retrieve sensor info"; + return; + } + + /* + * The ScalerCrop rectangle re-scaling in the ISP crop rectangle + * comes straight from the RPi pipeline handler. + * + * Create a version of the crop rectangle aligned to the analogue crop + * rectangle top-left coordinates and scaled in the [analogue crop to + * output frame] ratio to take into account binning/skipping on the + * sensor. + */ + Rectangle ispCrop = nativeCrop.translatedBy(-sensorInfo.analogCrop + .topLeft()); + ispCrop.scaleBy(sensorInfo.outputSize, sensorInfo.analogCrop.size()); + + /* + * The crop rectangle should be: + * 1. At least as big as ispMinCropSize_, once that's been + * enlarged to the same aspect ratio. + * 2. With the same mid-point, if possible. + * 3. But it can't go outside the sensor area. + */ + Rectangle ispMinCrop{ 0, 0, 640, 480 }; + Size minSize = ispMinCrop.size().expandedToAspectRatio(nativeCrop.size()); + Size size = ispCrop.size().expandedTo(minSize); + ispCrop = size.centeredTo(ispCrop.center()) + .enclosedIn(Rectangle(sensorInfo.outputSize)); + + /* + * As the resizer can't upscale, the crop rectangle has to be larger + * than the larger stream output size. + */ + Size maxYuvSize; + for (MaliC55Pipe &pipe : pipes_) { + if (!pipe.stream) + continue; + + const StreamConfiguration &config = pipe.stream->configuration(); + if (isFormatRaw(config.pixelFormat)) { + LOG(MaliC55, Debug) << "Cannot crop with a RAW stream"; + return; + } + + Size streamSize = config.size; + if (streamSize.width > maxYuvSize.width) + maxYuvSize.width = streamSize.width; + if (streamSize.height > maxYuvSize.height) + maxYuvSize.height = streamSize.height; + } + + ispCrop.size().expandTo(maxYuvSize); + + /* + * Now apply the scaler crop to each enabled output. This overrides the + * crop configuration performed at configure() time and can cause + * square pixels if the crop rectangle and scaler output FOV ratio are + * different. + */ + for (MaliC55Pipe &pipe : pipes_) { + if (!pipe.stream) + continue; + + /* Create a copy to avoid setSelection() to modify ispCrop. */ + Rectangle pipeCrop = ispCrop; + ret = pipe.resizer->setSelection(0, V4L2_SEL_TGT_CROP, &pipeCrop); + if (ret) { + LOG(MaliC55, Error) + << "Failed to apply crop to " + << (pipe.stream == &data->frStream_ ? + "FR" : "DS") << " pipe"; + return; + } + } +} + int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) { int ret; @@ -939,6 +1064,15 @@ int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request) return ret; } + /* + * Some controls need to be applied immediately, as in example, + * the ScalerCrop one. + * + * \todo Move it buffer queue time (likely after the IPA has filled in + * the parameters buffer) once we have plumbed the IPA loop in. + */ + applyScalerCrop(camera, request->controls()); + return 0; } @@ -1014,6 +1148,7 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink) return false; data->properties_ = data->sensor_->properties(); + data->updateControls(); registerMaliCamera(std::move(data), sensor->name()); }