Patch Detail
Show a patch.
GET /api/1.1/patches/22647/?format=api
{ "id": 22647, "url": "https://patchwork.libcamera.org/api/1.1/patches/22647/?format=api", "web_url": "https://patchwork.libcamera.org/patch/22647/", "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": "<20250124215806.158024-9-mzamazal@redhat.com>", "date": "2025-01-24T21:57:59", "name": "[RFC,v2,08/13] libcamera: simple: Handle adjusted and raw configurations separately", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "e11ed254548a1eac656b3decf23d39cafb937aa2", "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/22647/mbox/", "series": [ { "id": 4970, "url": "https://patchwork.libcamera.org/api/1.1/series/4970/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=4970", "date": "2025-01-24T21:57:51", "name": "Enable raw streams with software ISP", "version": 2, "mbox": "https://patchwork.libcamera.org/series/4970/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/22647/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/22647/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 ECC64BD78E\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Jan 2025 21:58:51 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 14C0A6856E;\n\tFri, 24 Jan 2025 22:58:51 +0100 (CET)", "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 26E576856D\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jan 2025 22:58:44 +0100 (CET)", "from mx-prod-mc-06.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-55--_4ILZHBNQuxKSt4NA0W_Q-1;\n\tFri, 24 Jan 2025 16:58:41 -0500", "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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTPS\n\tid 9452F18009D9 for <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Jan 2025 21:58:40 +0000 (UTC)", "from mzamazal-thinkpadp1gen3.tpbc.com (unknown [10.39.192.49])\n\tby mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix)\n\twith ESMTP id E7EC11800358; Fri, 24 Jan 2025 21:58:38 +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=\"O+i1cG0/\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1737755923;\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=QzXrvRvq0gETsT/aE6TGKpFDvf1zyuilwiuvEJuWHJY=;\n\tb=O+i1cG0/l1n+TSACAJORz3XV79WpAPe0GqyRaI9ogK7gYxpQJ+FHiKHqBzayB8+vYOyVgC\n\tvrU4oA3uT61etbVoMI+GDZuJ8LKoworNpd7YUI9DRvUj17zHGmd0uvc46f5mwhYJmEWvBo\n\tFfKtpbks83JSMgcc8buHIikMs2mlNdc=", "X-MC-Unique": "-_4ILZHBNQuxKSt4NA0W_Q-1", "X-Mimecast-MFC-AGG-ID": "-_4ILZHBNQuxKSt4NA0W_Q", "From": "Milan Zamazal <mzamazal@redhat.com>", "To": "libcamera-devel@lists.libcamera.org", "Cc": "Milan Zamazal <mzamazal@redhat.com>", "Subject": "[RFC PATCH v2 08/13] libcamera: simple: Handle adjusted and raw\n\tconfigurations separately", "Date": "Fri, 24 Jan 2025 22:57:59 +0100", "Message-ID": "<20250124215806.158024-9-mzamazal@redhat.com>", "In-Reply-To": "<20250124215806.158024-1-mzamazal@redhat.com>", "References": "<20250124215806.158024-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": "dwzFz4kU25h9FciPU8ds-yigCD8_lBN5iOuUiDBmxG4_1737755920", "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": "When using software ISP to produce both a processed and a raw stream at\nthe same time, we have to deal with two different output formats.\n\nWhen generating stream configurations, consider only raw formats for raw\nstreams. Also, mark raw configurations using\nStreamConfiguration::colorSpace value, which is the only available place\nin StreamConfiguration for the purpose.\n\nWhen validating stream configurations, use separate check for sizes to\nproduce raw and processed pipe configurations. Later, use the\ncorresponding pipe configurations for raw and processed stream\nconfigurations.\n\nSigned-off-by: Milan Zamazal <mzamazal@redhat.com>\n---\n src/libcamera/pipeline/simple/simple.cpp | 90 ++++++++++++++++++++----\n 1 file changed, 77 insertions(+), 13 deletions(-)", "diff": "diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\nindex 87a2043f..beb11069 100644\n--- a/src/libcamera/pipeline/simple/simple.cpp\n+++ b/src/libcamera/pipeline/simple/simple.cpp\n@@ -25,6 +25,7 @@\n #include <libcamera/base/log.h>\n \n #include <libcamera/camera.h>\n+#include <libcamera/color_space.h>\n #include <libcamera/control_ids.h>\n #include <libcamera/pixel_format.h>\n #include <libcamera/request.h>\n@@ -1062,7 +1063,9 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t * without upscaling.\n \t */\n \tconst SimpleCameraData::Configuration *maxPipeConfig = nullptr;\n+\tconst SimpleCameraData::Configuration *maxPipeConfigRaw = nullptr;\n \tpipeConfig_ = nullptr;\n+\tconst SimpleCameraData::Configuration *pipeConfigRaw = nullptr;\n \n \tfor (const SimpleCameraData::Configuration *pipeConfig : *configs) {\n \t\tconst Size &size = pipeConfig->captureSize;\n@@ -1075,6 +1078,17 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \n \t\tif (!maxPipeConfig || maxPipeConfig->captureSize < size)\n \t\t\tmaxPipeConfig = pipeConfig;\n+\n+\t\tif (!pipeConfig->swisp) {\n+\t\t\tif (size.width >= maxStreamSize.width &&\n+\t\t\t size.height >= maxStreamSize.height) {\n+\t\t\t\tif (!pipeConfigRaw || size < pipeConfigRaw->captureSize)\n+\t\t\t\t\tpipeConfigRaw = pipeConfig;\n+\t\t\t}\n+\n+\t\t\tif (!maxPipeConfigRaw || maxPipeConfigRaw->captureSize < size)\n+\t\t\t\tmaxPipeConfigRaw = pipeConfig;\n+\t\t}\n \t}\n \n \t/* If no configuration was large enough, select the largest one. */\n@@ -1085,6 +1099,13 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t}\n \t\tpipeConfig_ = maxPipeConfig;\n \t}\n+\tif (data_->rawRequested_ && !pipeConfigRaw) {\n+\t\tif (!maxPipeConfigRaw) {\n+\t\t\tLOG(SimplePipeline, Error) << \"No valid configuration for raw found\";\n+\t\t\treturn Invalid;\n+\t\t}\n+\t\tpipeConfigRaw = maxPipeConfigRaw;\n+\t}\n \n \tLOG(SimplePipeline, Debug)\n \t\t<< \"Picked \"\n@@ -1092,6 +1113,14 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t<< \" -> \" << pipeConfig_->captureSize\n \t\t<< \"-\" << pipeConfig_->captureFormat\n \t\t<< \" for max stream size \" << maxStreamSize;\n+\tif (pipeConfigRaw) {\n+\t\tLOG(SimplePipeline, Info)\n+\t\t\t<< \"Picked raw \"\n+\t\t\t<< V4L2SubdeviceFormat{ pipeConfigRaw->code, pipeConfigRaw->sensorSize, {} }\n+\t\t\t<< \" -> \" << pipeConfigRaw->captureSize\n+\t\t\t<< \"-\" << pipeConfigRaw->captureFormat\n+\t\t\t<< \" for max stream size \" << maxStreamSize;\n+\t}\n \n \t/*\n \t * Adjust the requested streams.\n@@ -1110,31 +1139,50 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \n \tfor (unsigned int i = 0; i < config_.size(); ++i) {\n \t\tStreamConfiguration &cfg = config_[i];\n+\t\tconst SimpleCameraData::Configuration *pipeConfig =\n+\t\t\t(cfg.colorSpace == ColorSpace::Raw ? pipeConfigRaw : pipeConfig_);\n+\t\tif (!pipeConfig)\n+\t\t\tcontinue;\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\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\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\tif (isRawFormat(pixelFormat)) {\n+\t\t\t\tLOG(SimplePipeline, Error)\n+\t\t\t\t\t<< \"Cannot convert pixel format with raw output (from \"\n+\t\t\t\t\t<< cfg.pixelFormat << \" to \"\n+\t\t\t\t\t<< pixelFormat << \")\";\n+\t\t\t\treturn Invalid;\n+\t\t\t}\n \t\t\tLOG(SimplePipeline, Debug) << \"Adjusting pixel format\";\n \t\t\tcfg.pixelFormat = pixelFormat;\n \t\t\tstatus = Adjusted;\n \t\t}\n \n-\t\tif (!pipeConfig_->outputSizes.contains(cfg.size)) {\n-\t\t\tSize adjustedSize = pipeConfig_->captureSize;\n+\t\tif (!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 \t\t\t * a size identical to its input size. The capture size is thus\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\t\tadjustedSize = adjustSize(cfg.size, pipeConfig_->outputSizes);\n+\t\t\tif (!pipeConfig->outputSizes.contains(adjustedSize)) {\n+\t\t\t\tif (isRawFormat(pixelFormat)) {\n+\t\t\t\t\tLOG(SimplePipeline, Error)\n+\t\t\t\t\t\t<< \"Cannot adjust output size with raw output (from \"\n+\t\t\t\t\t\t<< cfg.pixelFormat << \" to \"\n+\t\t\t\t\t\t<< pixelFormat << \")\";\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@@ -1143,8 +1191,8 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate()\n \t\t}\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\tif (cfg.pixelFormat != pipeConfig->captureFormat ||\n+\t\t cfg.size != pipeConfig->captureSize)\n \t\t\tneedConversion_ = true;\n \n \t\t/* Set the stride, frameSize and bufferCount. */\n@@ -1246,10 +1294,26 @@ SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo\n \t *\n \t * \\todo Implement a better way to pick the default format\n \t */\n-\tfor ([[maybe_unused]] StreamRole role : roles) {\n+\tfor (StreamRole role : roles) {\n \t\tStreamConfiguration cfg{ StreamFormats{ formats } };\n-\t\tcfg.pixelFormat = formats.begin()->first;\n-\t\tcfg.size = formats.begin()->second[0].max;\n+\t\tif (role == StreamRole::Raw) {\n+\t\t\tbool found = false;\n+\t\t\tfor (auto &[format, sizes] : formats)\n+\t\t\t\tif (isRawFormat(format)) {\n+\t\t\t\t\tcfg.pixelFormat = format;\n+\t\t\t\t\tcfg.size = sizes[0].max;\n+\t\t\t\t\tfound = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\tif (!found) {\n+\t\t\t\tLOG(SimplePipeline, Error) << \"Raw stream requested but no raw format found \";\n+\t\t\t\treturn nullptr;\n+\t\t\t}\n+\t\t\tcfg.colorSpace = ColorSpace::Raw;\n+\t\t} else {\n+\t\t\tcfg.pixelFormat = formats.begin()->first;\n+\t\t\tcfg.size = formats.begin()->second[0].max;\n+\t\t}\n \n \t\tconfig->addConfiguration(cfg);\n \t}\n", "prefixes": [ "RFC", "v2", "08/13" ] }