Show a patch.

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

{
    "id": 24051,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/24051/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/24051/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/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": "<20250804163812.126022-5-mzamazal@redhat.com>",
    "date": "2025-08-04T16:38:07",
    "name": "[v12,4/8] libcamera: simple: Validate raw stream configurations",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "15a19691006a7dbfd03c1e1f33dade9ebdd4cd2d",
    "submitter": {
        "id": 177,
        "url": "https://patchwork.libcamera.org/api/1.1/people/177/?format=api",
        "name": "Milan Zamazal",
        "email": "mzamazal@redhat.com"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/24051/mbox/",
    "series": [
        {
            "id": 5355,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5355/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5355",
            "date": "2025-08-04T16:38:03",
            "name": "Enable raw streams with software ISP",
            "version": 12,
            "mbox": "https://patchwork.libcamera.org/series/5355/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/24051/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/24051/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 BE06EBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon,  4 Aug 2025 16:38:47 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7BC5B69222;\n\tMon,  4 Aug 2025 18:38:47 +0200 (CEST)",
            "from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D665A6921A\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon,  4 Aug 2025 18:38:45 +0200 (CEST)",
            "from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com\n\t(ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-443-KKs8NfYpNk2g6R41s6vgzg-1;\n\tMon, 04 Aug 2025 12:38:39 -0400",
            "from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n\t[10.30.177.93])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\tkey-exchange X25519 server-signature RSA-PSS (2048 bits)\n\tserver-digest SHA256) (No client certificate requested)\n\tby mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 1442019774D9; Mon,  4 Aug 2025 16:38:38 +0000 (UTC)",
            "from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.17])\n\tby mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id 60E261800D8A; Mon,  4 Aug 2025 16:38:35 +0000 (UTC)"
        ],
        "Authentication-Results": "lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"eMg3vOil\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1754325524;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=4g9Ccmh7piaYCtomDUi/3Vc8f39//YnbWrG7uEkgyPk=;\n\tb=eMg3vOilLvN/Zl+zgeAs0mJWeZOGg9rnGrDwaFYF3WjkYFwc0GB7POZ7yYfcicEIKr4Ot6\n\tlQUmSKb5/4qAzMWyGHukJ0sRajdZ0hIctVSn4PVK9Rfccc0ymhxOWoCmJR2GXqy3NmqNpe\n\tHBNTNh450qV5T8bF/MQgkeEloIJNdzw=",
        "X-MC-Unique": "KKs8NfYpNk2g6R41s6vgzg-1",
        "X-Mimecast-MFC-AGG-ID": "KKs8NfYpNk2g6R41s6vgzg_1754325518",
        "From": "Milan Zamazal <mzamazal@redhat.com>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "Milan Zamazal <mzamazal@redhat.com>, Laurent Pinchart\n\t<laurent.pinchart@ideasonboard.com>, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>, =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?=\n\t<barnabas.pocze@ideasonboard.com>, Paul Elder\n\t<paul.elder@ideasonboard.com>, Umang Jain <uajain@igalia.com>",
        "Subject": "[PATCH v12 4/8] libcamera: simple: Validate raw stream\n\tconfigurations",
        "Date": "Mon,  4 Aug 2025 18:38:07 +0200",
        "Message-ID": "<20250804163812.126022-5-mzamazal@redhat.com>",
        "In-Reply-To": "<20250804163812.126022-1-mzamazal@redhat.com>",
        "References": "<20250804163812.126022-1-mzamazal@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.93",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "tJGyQF2ZPunryOC0fVdReTnC46f5GFgGMcgwGB5DZ58_1754325518",
        "X-Mimecast-Originator": "redhat.com",
        "Content-Transfer-Encoding": "8bit",
        "content-type": "text/plain; charset=\"US-ASCII\"; x-default=true",
        "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": "SimpleCameraConfiguration::validate() looks for the best configuration.\nAs part of enabling raw stream support, the method must consider raw\nstreams in addition to the processed streams.\n\nRaw streams are adjusted from the capture format and size.\n\nNote that with both processed and raw streams, the requested sizes must\nbe mutually matching, including resizing due to debayer requirements.\nFor example, the following `cam' setup is valid for imx219\n\n  cam -s role=viewfinder,width=1920,height=1080 \\\n      -s role=raw,width=3280,height=2464\n\nrather than\n\n  cam -s role=viewfinder,width=1920,height=1080 \\\n      -s role=raw,width=1920,height=1080\n\ndue to the resolution of 1924x1080 actually selected for debayering to\n1920x1080.  If the resolutions don't match mutually or don't match the\navailable sizes, validation adjusts them.\n\nSetting up the right configurations is still not enough to make the raw\nstreams working.  Buffer handling must be changed in the simple\npipeline, which is addressed in followup patches.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n src/libcamera/pipeline/simple/simple.cpp | 86 +++++++++++++++++-------\n 1 file changed, 62 insertions(+), 24 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex bc4d7bd41..1ad982a4c 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -11,6 +11,7 @@\n #include <list>\n #include <map>\n #include <memory>\n+#include <optional>\n #include <queue>\n #include <set>\n #include <stdint.h>\n@@ -27,6 +28,7 @@\n #include <libcamera/camera.h>\n #include <libcamera/color_space.h>\n #include <libcamera/control_ids.h>\n+#include <libcamera/geometry.h>\n #include <libcamera/pixel_format.h>\n #include <libcamera/request.h>\n #include <libcamera/stream.h>\n@@ -1134,22 +1136,39 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t<< \"Largest stream size is \" << maxStreamSize;\n \n \t/*\n-\t * Find the best configuration for the pipeline using a heuristic.\n-\t * First select the pixel format based on the streams (which are\n-\t * considered ordered from highest to lowest priority). Default to the\n-\t * first pipeline configuration if no streams request a supported pixel\n-\t * format.\n+\t * Find the best configuration for the pipeline using a heuristic. First\n+\t * select the pixel format based on the streams. If there is a raw stream,\n+\t * its format has precedence. If there is no raw stream, the streams are\n+\t * considered ordered from highest to lowest priority. Default to the first\n+\t * pipeline configuration if no streams request a supported pixel format.\n \t */\n-\tconst std::vector<const SimpleCameraData::Configuration *> *configs =\n-\t\t&data_->formats_.begin()->second;\n+\tstd::optional<PixelFormat> rawFormat;\n+\tfor (const auto &cfg : config_)\n+\t\tif (isRaw(cfg)) {\n+\t\t\tif (rawFormat) {\n+\t\t\t\tLOG(SimplePipeline, Error)\n+\t\t\t\t\t<< \"Can't capture multiple raw streams\";\n+\t\t\t\treturn Invalid;\n+\t\t\t}\n+\t\t\trawFormat = cfg.pixelFormat;\n+\t\t}\n \n-\tfor (const StreamConfiguration &cfg : config_) {\n-\t\tauto it = data_->formats_.find(cfg.pixelFormat);\n-\t\tif (it != data_->formats_.end()) {\n+\tconst std::vector<const SimpleCameraData::Configuration *> *configs = nullptr;\n+\tif (rawFormat) {\n+\t\tauto it = data_->formats_.find(rawFormat.value());\n+\t\tif (it != data_->formats_.end())\n \t\t\tconfigs = &it->second;\n-\t\t\tbreak;\n-\t\t}\n \t}\n+\tif (!configs)\n+\t\tfor (const StreamConfiguration &cfg : config_) {\n+\t\t\tauto it = data_->formats_.find(cfg.pixelFormat);\n+\t\t\tif (it != data_->formats_.end()) {\n+\t\t\t\tconfigs = &it->second;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\tif (!configs)\n+\t\tconfigs = &data_->formats_.begin()->second;\n \n \t/*\n \t * \\todo Pick the best sensor output media bus format when the\n@@ -1206,17 +1225,27 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \n \tfor (unsigned int i = 0; i < config_.size(); ++i) {\n \t\tStreamConfiguration &cfg = config_[i];\n+\t\tconst bool raw = isRaw(cfg);\n \n-\t\t/* Adjust the pixel format and size. */\n-\t\tauto it = std::find(pipeConfig_->outputFormats.begin(),\n-\t\t\t\t    pipeConfig_->outputFormats.end(),\n-\t\t\t\t    cfg.pixelFormat);\n-\t\tif (it == pipeConfig_->outputFormats.end())\n-\t\t\tit = pipeConfig_->outputFormats.begin();\n+\t\t/* Adjust the pixel format, colour space and size. */\n \n-\t\tPixelFormat pixelFormat = *it;\n+\t\tPixelFormat pixelFormat;\n+\t\tif (raw) {\n+\t\t\tpixelFormat = pipeConfig_->captureFormat;\n+\t\t} else {\n+\t\t\tauto it = std::find(pipeConfig_->outputFormats.begin(),\n+\t\t\t\t\t    pipeConfig_->outputFormats.end(),\n+\t\t\t\t\t    cfg.pixelFormat);\n+\t\t\tif (it == pipeConfig_->outputFormats.end())\n+\t\t\t\tit = pipeConfig_->outputFormats.begin();\n+\t\t\tpixelFormat = *it;\n+\t\t}\n \t\tif (cfg.pixelFormat != pixelFormat) {\n-\t\t\tLOG(SimplePipeline, Debug) << \"Adjusting pixel format\";\n+\t\t\tLOG(SimplePipeline, Debug)\n+\t\t\t\t<< \"Adjusting pixel format of a \"\n+\t\t\t\t<< (raw ? \"raw\" : \"processed\")\n+\t\t\t\t<< \" stream from \" << cfg.pixelFormat\n+\t\t\t\t<< \" to \" << pixelFormat;\n \t\t\tcfg.pixelFormat = pixelFormat;\n \t\t\tstatus = Adjusted;\n \t\t}\n@@ -1252,7 +1281,7 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t\tstatus = Adjusted;\n \t\t}\n \n-\t\tif (!pipeConfig_->outputSizes.contains(cfg.size)) {\n+\t\tif (!raw && !pipeConfig_->outputSizes.contains(cfg.size)) {\n \t\t\tSize adjustedSize = pipeConfig_->captureSize;\n \t\t\t/*\n \t\t\t * The converter (when present) may not be able to output\n@@ -1271,11 +1300,20 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \n \t\t/* \\todo Create a libcamera core class to group format and size */\n \t\tif (cfg.pixelFormat != pipeConfig_->captureFormat ||\n-\t\t    cfg.size != pipeConfig_->captureSize)\n-\t\t\tneedConversion_ = true;\n+\t\t    cfg.size != pipeConfig_->captureSize) {\n+\t\t\tif (raw) {\n+\t\t\t\tcfg.pixelFormat = pipeConfig_->captureFormat;\n+\t\t\t\tcfg.size = pipeConfig_->captureSize;\n+\t\t\t\tLOG(SimplePipeline, Debug)\n+\t\t\t\t\t<< \"Adjusting raw configuration to \" << cfg;\n+\t\t\t\tstatus = Adjusted;\n+\t\t\t} else {\n+\t\t\t\tneedConversion_ = true;\n+\t\t\t}\n+\t\t}\n \n \t\t/* Set the stride, frameSize and bufferCount. */\n-\t\tif (needConversion_) {\n+\t\tif (needConversion_ && !raw) {\n \t\t\tstd::tie(cfg.stride, cfg.frameSize) =\n \t\t\t\tdata_->converter_\n \t\t\t\t\t? data_->converter_->strideAndFrameSize(cfg.pixelFormat,\n",
    "prefixes": [
        "v12",
        "4/8"
    ]
}