Show a patch.

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

{
    "id": 23440,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/23440/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/23440/",
    "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": "<20250526101536.29222-10-mzamazal@redhat.com>",
    "date": "2025-05-26T10:15:29",
    "name": "[v6,09/12] libcamera: simple: Validate raw stream configurations",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "e63e4cd8248d3e2576bcd24ddfa7104fe0f8ecae",
    "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/23440/mbox/",
    "series": [
        {
            "id": 5194,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5194/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5194",
            "date": "2025-05-26T10:15:20",
            "name": "Enable raw streams with software ISP",
            "version": 6,
            "mbox": "https://patchwork.libcamera.org/series/5194/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/23440/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/23440/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 1EFF5C31E9\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 26 May 2025 10:16:21 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id C105368DB5;\n\tMon, 26 May 2025 12:16:19 +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 C4E7868DB1\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 26 May 2025 12:16:16 +0200 (CEST)",
            "from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com\n\t(ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97])\n\tby relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n\tcipher=TLS_AES_256_GCM_SHA384) id us-mta-637-0sgk5gfUNiiiEE130Niztg-1;\n\tMon, 26 May 2025 06:16:10 -0400",
            "from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n\t(mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n\t[10.30.177.111])\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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS id 18C2C180087B; Mon, 26 May 2025 10:16:09 +0000 (UTC)",
            "from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.45.226.78])\n\tby mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id B5E22180045B; Mon, 26 May 2025 10:16:06 +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=\"YQcqWPWZ\"; dkim-atps=neutral",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1748254575;\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=ftzzOGb+ndbMwxrpqxmrG0nMkTfQPiVDHTj769EFm9Y=;\n\tb=YQcqWPWZYZU5M9RamYhXwOxPKp40xeFLfSB84AKpLv1tpWApabqzqOByTUH8Kn3Nv21fFb\n\tyDtdONGGv6WSQ37LW1E6/z4hstZ5i/+XdeTRdFGKfa6nQ5HLOoDoYxo955NmUtR6IZQnZH\n\thjLjH0IH92ECg43lld4oPwlwD+zCO1E=",
        "X-MC-Unique": "0sgk5gfUNiiiEE130Niztg-1",
        "X-Mimecast-MFC-AGG-ID": "0sgk5gfUNiiiEE130Niztg_1748254569",
        "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>",
        "Subject": "[PATCH v6 09/12] libcamera: simple: Validate raw stream\n\tconfigurations",
        "Date": "Mon, 26 May 2025 12:15:29 +0200",
        "Message-ID": "<20250526101536.29222-10-mzamazal@redhat.com>",
        "In-Reply-To": "<20250526101536.29222-1-mzamazal@redhat.com>",
        "References": "<20250526101536.29222-1-mzamazal@redhat.com>",
        "MIME-Version": "1.0",
        "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.111",
        "X-Mimecast-Spam-Score": "0",
        "X-Mimecast-MFC-PROC-ID": "bqC9LK3ZitL1A9K9b4C-YQIe8vx5qPgkd5mkRjGom9U_1748254569",
        "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\nIf only a processed stream is requested, nothing changes.\n\nIf only a raw stream is requested, the pixel format and output size may\nnot be adjusted.  The patch adds checks for this.\n\nIf both processed and raw streams are requested, things get more\ncomplicated.  The raw stream is expected to be passed through intact and\nall the adjustments are made for the processed streams.  We select a\npipe configuration for the processed streams.\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.  It is the application responsibility to select the right\nparameters for the raw stream.\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 | 115 +++++++++++++++++------\n 1 file changed, 86 insertions(+), 29 deletions(-)",
    "diff": "diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex 91fd4323..f914c271 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -27,6 +27,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@@ -1167,6 +1168,9 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \tpipeConfig_ = nullptr;\n \n \tfor (const SimpleCameraData::Configuration *pipeConfig : *configs) {\n+\t\tif (processedRequested_ && pipeConfig->raw)\n+\t\t\tcontinue;\n+\n \t\tconst Size &size = pipeConfig->captureSize;\n \n \t\tif (size.width >= maxStreamSize.width &&\n@@ -1190,6 +1194,18 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t<< \"-\" << pipeConfig_->captureFormat\n \t\t<< \" for max stream size \" << maxStreamSize;\n \n+\t/*\n+\t * Update raw/processed flags. If e.g. an application calls\n+\t * generateConfiguration() with an empty list of roles and adds\n+\t * configurations by calling addConfiguration(), the flags must be updated\n+\t * according to those configurations.\n+\t */\n+\tfor (const auto &cfg : config_)\n+\t\tif (cfg.colorSpace == ColorSpace::Raw)\n+\t\t\trawRequested_ = true;\n+\t\telse\n+\t\t\tprocessedRequested_ = true;\n+\n \t/*\n \t * Adjust the requested streams.\n \t *\n@@ -1208,37 +1224,60 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \tfor (unsigned int i = 0; i < config_.size(); ++i) {\n \t\tStreamConfiguration &cfg = config_[i];\n \n+\t\t/*\n+\t\t * If both processed and raw streams are requested, the pipe\n+\t\t * configuration is set up for the processed stream. The raw\n+\t\t * configuration needs to be compared against the capture format and\n+\t\t * size in such a case.\n+\t\t */\n+\t\tconst bool rawStream = cfg.colorSpace == ColorSpace::Raw;\n+\t\tconst bool sideRawStream = rawStream && processedRequested_;\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-\n-\t\tPixelFormat pixelFormat = *it;\n-\t\tif (cfg.pixelFormat != pixelFormat) {\n-\t\t\tLOG(SimplePipeline, Debug) << \"Adjusting pixel format\";\n-\t\t\tcfg.pixelFormat = pixelFormat;\n-\t\t\tif (cfg.colorSpace && cfg.colorSpace != ColorSpace::Raw)\n+\n+\t\tif (!sideRawStream) {\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+\n+\t\t\tPixelFormat pixelFormat = *it;\n+\n+\t\t\tif (cfg.pixelFormat != pixelFormat) {\n+\t\t\t\tif (rawStream) {\n+\t\t\t\t\tLOG(SimplePipeline, Info)\n+\t\t\t\t\t\t<< \"Raw pixel format \"\n+\t\t\t\t\t\t<< cfg.pixelFormat\n+\t\t\t\t\t\t<< \" doesn't match any of the pipe output formats\";\n+\t\t\t\t\treturn Invalid;\n+\t\t\t\t}\n+\t\t\t\tLOG(SimplePipeline, Debug)\n+\t\t\t\t\t<< \"Adjusting pixel format from \" << cfg.pixelFormat\n+\t\t\t\t\t<< \" to \" << pixelFormat;\n+\t\t\t\tcfg.pixelFormat = pixelFormat;\n+\t\t\t\tif (cfg.colorSpace && cfg.colorSpace != ColorSpace::Raw)\n+\t\t\t\t\tcfg.colorSpace->adjust(pixelFormat);\n+\t\t\t\tstatus = Adjusted;\n+\t\t\t}\n+\n+\t\t\tif (!cfg.colorSpace) {\n+\t\t\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);\n+\t\t\t\tswitch (info.colourEncoding) {\n+\t\t\t\tcase PixelFormatInfo::ColourEncodingRGB:\n+\t\t\t\t\tcfg.colorSpace = ColorSpace::Srgb;\n+\t\t\t\t\tbreak;\n+\t\t\t\tcase libcamera::PixelFormatInfo::ColourEncodingYUV:\n+\t\t\t\t\tcfg.colorSpace = ColorSpace::Sycc;\n+\t\t\t\t\tbreak;\n+\t\t\t\tdefault:\n+\t\t\t\t\tcfg.colorSpace = ColorSpace::Raw;\n+\t\t\t\t}\n \t\t\t\tcfg.colorSpace->adjust(pixelFormat);\n-\t\t\tstatus = Adjusted;\n-\t\t}\n-\t\tif (!cfg.colorSpace) {\n-\t\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(pixelFormat);\n-\t\t\tswitch (info.colourEncoding) {\n-\t\t\tcase PixelFormatInfo::ColourEncodingRGB:\n-\t\t\t\tcfg.colorSpace = ColorSpace::Srgb;\n-\t\t\t\tbreak;\n-\t\t\tcase libcamera::PixelFormatInfo::ColourEncodingYUV:\n-\t\t\t\tcfg.colorSpace = ColorSpace::Sycc;\n-\t\t\t\tbreak;\n-\t\t\tdefault:\n-\t\t\t\tcfg.colorSpace = ColorSpace::Raw;\n \t\t\t}\n-\t\t\tcfg.colorSpace->adjust(pixelFormat);\n \t\t}\n \n-\t\tif (!pipeConfig_->outputSizes.contains(cfg.size)) {\n+\t\tif (!sideRawStream && !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@@ -1246,8 +1285,17 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t\t * not guaranteed to be a valid output size. In such cases, use\n \t\t\t * the smaller valid output size closest to the requested.\n \t\t\t */\n-\t\t\tif (!pipeConfig_->outputSizes.contains(adjustedSize))\n+\t\t\tif (!pipeConfig_->outputSizes.contains(adjustedSize)) {\n+\t\t\t\tif (rawStream) {\n+\t\t\t\t\tLOG(SimplePipeline, Info)\n+\t\t\t\t\t\t<< \"Raw output size \"\n+\t\t\t\t\t\t<< cfg.size\n+\t\t\t\t\t\t<< \" doesn't match any of the pipe output sizes: \"\n+\t\t\t\t\t\t<< pipeConfig_->outputSizes;\n+\t\t\t\t\treturn Invalid;\n+\t\t\t\t}\n \t\t\t\tadjustedSize = adjustSize(cfg.size, pipeConfig_->outputSizes);\n+\t\t\t}\n \t\t\tLOG(SimplePipeline, Debug)\n \t\t\t\t<< \"Adjusting size from \" << cfg.size\n \t\t\t\t<< \" to \" << adjustedSize;\n@@ -1257,11 +1305,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    cfg.size != pipeConfig_->captureSize) {\n+\t\t\tif (rawStream) {\n+\t\t\t\tLOG(SimplePipeline, Info)\n+\t\t\t\t\t<< \"Raw output format \" << cfg.pixelFormat\n+\t\t\t\t\t<< \" and size \" << cfg.size\n+\t\t\t\t\t<< \" not matching pipe format \" << pipeConfig_->captureFormat\n+\t\t\t\t\t<< \" and size \" << pipeConfig_->captureSize;\n+\t\t\t\treturn Invalid;\n+\t\t\t}\n \t\t\tneedConversion_ = true;\n+\t\t}\n \n \t\t/* Set the stride, frameSize and bufferCount. */\n-\t\tif (needConversion_) {\n+\t\tif (needConversion_ && !rawStream) {\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": [
        "v6",
        "09/12"
    ]
}