Show a patch.

GET /api/patches/21916/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 21916,
    "url": "https://patchwork.libcamera.org/api/patches/21916/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/21916/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20241115101334.453104-15-dan.scally@ideasonboard.com>",
    "date": "2024-11-15T10:13:34",
    "name": "[v6,14/14] libcamera: mali-c55: implement support for ScalerCrop",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "4240fcb02d118e25a78cc4679d75c7f55a3ec994",
    "submitter": {
        "id": 156,
        "url": "https://patchwork.libcamera.org/api/people/156/?format=api",
        "name": "Dan Scally",
        "email": "dan.scally@ideasonboard.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/21916/mbox/",
    "series": [
        {
            "id": 4793,
            "url": "https://patchwork.libcamera.org/api/series/4793/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4793",
            "date": "2024-11-15T10:13:20",
            "name": "Miscellaneous Mali-C55 Pipeline Fixes",
            "version": 6,
            "mbox": "https://patchwork.libcamera.org/series/4793/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/21916/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/21916/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "<libcamera-devel-bounces@lists.libcamera.org>",
        "X-Original-To": "parsemail@patchwork.libcamera.org",
        "Delivered-To": "parsemail@patchwork.libcamera.org",
        "Received": [
            "from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 49BD7C330D\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 15 Nov 2024 10:14:24 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 4E6E16589B;\n\tFri, 15 Nov 2024 11:14:23 +0100 (CET)",
            "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id ECADB65876\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 15 Nov 2024 11:13:52 +0100 (CET)",
            "from mail.ideasonboard.com\n\t(cpc141996-chfd3-2-0-cust928.12-3.cable.virginm.net [86.13.91.161])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 59BDE15D2;\n\tFri, 15 Nov 2024 11:13:38 +0100 (CET)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"liVdqd3G\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1731665618;\n\tbh=aeGAhW1AW3dO2WH6PyXxomXS0mwwEiltIZLIZ0J/5kk=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=liVdqd3GFzOBXqbmbu6Jhl1U42LlmaCtAqF7rSJPE7SUtcCdaS9+p6OIZXBaSBaMR\n\t9Jhn6DtJ8WICoEeMby5/Ubx0bUOKdy9lMNkMYQb3InBexA8YfRrODRQQXOd7LaYA8U\n\t6tTv458T3496bQm7M1dlo9POBZYmzFn2GauCLWEw=",
        "From": "Daniel Scally <dan.scally@ideasonboard.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Anthony.McGivern@arm.com, Jacopo Mondi <jacopo.mondi@ideasonboard.com>, \n\tKieran Bingham <kieran.bingham@ideasonboard.com>,\n\tDaniel Scally <dan.scally@ideasonboard.com>",
        "Subject": "[PATCH v6 14/14] libcamera: mali-c55: implement support for\n\tScalerCrop",
        "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",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "libcamera-devel@lists.libcamera.org",
        "X-Mailman-Version": "2.1.29",
        "Precedence": "list",
        "List-Id": "<libcamera-devel.lists.libcamera.org>",
        "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>",
        "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>",
        "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>",
        "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>",
        "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>",
        "Errors-To": "libcamera-devel-bounces@lists.libcamera.org",
        "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"
    },
    "content": "From: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\n\nImplement support for the ScalerCrop control that allows to apply a\ndigital zoom to the captured streams.\n\nInitialize the camera controls at camera registration time and update\nthem at configure time as the sensor's analogue crop size might change\ndepending on the desired Camera configuration.\n\nReviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\nReviewed-by: Daniel Scally <dan.scally@ideasonboard.com>\nSigned-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>\nSigned-off-by: Daniel Scally <dan.scally@ideasonboard.com>\n---\nChanges in v6:\n\n\t- None\n\nChanges in v5:\n\n\t- None\n\n src/libcamera/pipeline/mali-c55/mali-c55.cpp | 135 +++++++++++++++++++\n 1 file changed, 135 insertions(+)",
    "diff": "diff --git a/src/libcamera/pipeline/mali-c55/mali-c55.cpp b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\nindex d0218349..3fc07a5d 100644\n--- a/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n+++ b/src/libcamera/pipeline/mali-c55/mali-c55.cpp\n@@ -22,6 +22,8 @@\n #include <libcamera/geometry.h>\n #include <libcamera/stream.h>\n \n+#include <libcamera/ipa/core_ipa_interface.h>\n+\n #include \"libcamera/internal/bayer_format.h\"\n #include \"libcamera/internal/camera.h\"\n #include \"libcamera/internal/camera_sensor.h\"\n@@ -85,6 +87,8 @@ public:\n \tint pixfmtToMbusCode(const PixelFormat &pixFmt) const;\n \tconst PixelFormat &bestRawFormat() const;\n \n+\tvoid updateControls();\n+\n \tPixelFormat adjustRawFormat(const PixelFormat &pixFmt) const;\n \tSize adjustRawSizes(const PixelFormat &pixFmt, const Size &rawSize) const;\n \n@@ -266,6 +270,27 @@ const PixelFormat &MaliC55CameraData::bestRawFormat() const\n \treturn invalidPixFmt;\n }\n \n+void MaliC55CameraData::updateControls()\n+{\n+\tif (!sensor_)\n+\t\treturn;\n+\n+\tIPACameraSensorInfo sensorInfo;\n+\tint ret = sensor_->sensorInfo(&sensorInfo);\n+\tif (ret) {\n+\t\tLOG(MaliC55, Error) << \"Failed to retrieve sensor info\";\n+\t\treturn;\n+\t}\n+\n+\tControlInfoMap::Map controls;\n+\tRectangle ispMinCrop{ 0, 0, 640, 480 };\n+\tcontrols[&controls::ScalerCrop] =\n+\t\tControlInfo(ispMinCrop, sensorInfo.analogCrop,\n+\t\t\t    sensorInfo.analogCrop);\n+\n+\tcontrolInfo_ = ControlInfoMap(std::move(controls), controls::controls);\n+}\n+\n /*\n  * Make sure the provided raw pixel format is supported and adjust it to\n  * one of the supported ones if it's not.\n@@ -553,6 +578,8 @@ private:\n \t\t\t\t     const StreamConfiguration &config,\n \t\t\t\t     V4L2SubdeviceFormat &subdevFormat);\n \n+\tvoid applyScalerCrop(Camera *camera, const ControlList &controls);\n+\n \tvoid registerMaliCamera(std::unique_ptr<MaliC55CameraData> data,\n \t\t\t\tconst std::string &name);\n \tbool registerTPGCamera(MediaLink *link);\n@@ -880,6 +907,8 @@ int PipelineHandlerMaliC55::configure(Camera *camera,\n \t\tpipe->stream = stream;\n \t}\n \n+\tdata->updateControls();\n+\n \treturn 0;\n }\n \n@@ -927,6 +956,102 @@ void PipelineHandlerMaliC55::stopDevice([[maybe_unused]] Camera *camera)\n \t}\n }\n \n+void PipelineHandlerMaliC55::applyScalerCrop(Camera *camera,\n+\t\t\t\t\t     const ControlList &controls)\n+{\n+\tMaliC55CameraData *data = cameraData(camera);\n+\n+\tconst auto &scalerCrop = controls.get<Rectangle>(controls::ScalerCrop);\n+\tif (!scalerCrop)\n+\t\treturn;\n+\n+\tif (!data->sensor_) {\n+\t\tLOG(MaliC55, Error) << \"ScalerCrop not supported for TPG\";\n+\t\treturn;\n+\t}\n+\n+\tRectangle nativeCrop = *scalerCrop;\n+\n+\tIPACameraSensorInfo sensorInfo;\n+\tint ret = data->sensor_->sensorInfo(&sensorInfo);\n+\tif (ret) {\n+\t\tLOG(MaliC55, Error) << \"Failed to retrieve sensor info\";\n+\t\treturn;\n+\t}\n+\n+\t/*\n+\t * The ScalerCrop rectangle re-scaling in the ISP crop rectangle\n+\t * comes straight from the RPi pipeline handler.\n+\t *\n+\t * Create a version of the crop rectangle aligned to the analogue crop\n+\t * rectangle top-left coordinates and scaled in the [analogue crop to\n+\t * output frame] ratio to take into account binning/skipping on the\n+\t * sensor.\n+\t */\n+\tRectangle ispCrop = nativeCrop.translatedBy(-sensorInfo.analogCrop\n+\t\t\t\t\t\t\t       .topLeft());\n+\tispCrop.scaleBy(sensorInfo.outputSize, sensorInfo.analogCrop.size());\n+\n+\t/*\n+\t * The crop rectangle should be:\n+\t * 1. At least as big as ispMinCropSize_, once that's been\n+\t *    enlarged to the same aspect ratio.\n+\t * 2. With the same mid-point, if possible.\n+\t * 3. But it can't go outside the sensor area.\n+\t */\n+\tRectangle ispMinCrop{ 0, 0, 640, 480 };\n+\tSize minSize = ispMinCrop.size().expandedToAspectRatio(nativeCrop.size());\n+\tSize size = ispCrop.size().expandedTo(minSize);\n+\tispCrop = size.centeredTo(ispCrop.center())\n+\t\t      .enclosedIn(Rectangle(sensorInfo.outputSize));\n+\n+\t/*\n+\t * As the resizer can't upscale, the crop rectangle has to be larger\n+\t * than the larger stream output size.\n+\t */\n+\tSize maxYuvSize;\n+\tfor (MaliC55Pipe &pipe : pipes_) {\n+\t\tif (!pipe.stream)\n+\t\t\tcontinue;\n+\n+\t\tconst StreamConfiguration &config = pipe.stream->configuration();\n+\t\tif (isFormatRaw(config.pixelFormat)) {\n+\t\t\tLOG(MaliC55, Debug) << \"Cannot crop with a RAW stream\";\n+\t\t\treturn;\n+\t\t}\n+\n+\t\tSize streamSize = config.size;\n+\t\tif (streamSize.width > maxYuvSize.width)\n+\t\t\tmaxYuvSize.width = streamSize.width;\n+\t\tif (streamSize.height > maxYuvSize.height)\n+\t\t\tmaxYuvSize.height = streamSize.height;\n+\t}\n+\n+\tispCrop.size().expandTo(maxYuvSize);\n+\n+\t/*\n+\t * Now apply the scaler crop to each enabled output. This overrides the\n+\t * crop configuration performed at configure() time and can cause\n+\t * square pixels if the crop rectangle and scaler output FOV ratio are\n+\t * different.\n+\t */\n+\tfor (MaliC55Pipe &pipe : pipes_) {\n+\t\tif (!pipe.stream)\n+\t\t\tcontinue;\n+\n+\t\t/* Create a copy to avoid setSelection() to modify ispCrop. */\n+\t\tRectangle pipeCrop = ispCrop;\n+\t\tret = pipe.resizer->setSelection(0, V4L2_SEL_TGT_CROP, &pipeCrop);\n+\t\tif (ret) {\n+\t\t\tLOG(MaliC55, Error)\n+\t\t\t\t<< \"Failed to apply crop to \"\n+\t\t\t\t<< (pipe.stream == &data->frStream_ ?\n+\t\t\t\t    \"FR\" : \"DS\") << \" pipe\";\n+\t\t\treturn;\n+\t\t}\n+\t}\n+}\n+\n int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request)\n {\n \tint ret;\n@@ -939,6 +1064,15 @@ int PipelineHandlerMaliC55::queueRequestDevice(Camera *camera, Request *request)\n \t\t\treturn ret;\n \t}\n \n+\t/*\n+\t * Some controls need to be applied immediately, as in example,\n+\t * the ScalerCrop one.\n+\t *\n+\t * \\todo Move it buffer queue time (likely after the IPA has filled in\n+\t * the parameters buffer) once we have plumbed the IPA loop in.\n+\t */\n+\tapplyScalerCrop(camera, request->controls());\n+\n \treturn 0;\n }\n \n@@ -1014,6 +1148,7 @@ bool PipelineHandlerMaliC55::registerSensorCamera(MediaLink *ispLink)\n \t\t\treturn false;\n \n \t\tdata->properties_ = data->sensor_->properties();\n+\t\tdata->updateControls();\n \n \t\tregisterMaliCamera(std::move(data), sensor->name());\n \t}\n",
    "prefixes": [
        "v6",
        "14/14"
    ]
}