[{"id":36431,"web_url":"https://patchwork.libcamera.org/comment/36431/","msgid":"<4f2qwzroppc43pkkapmhys5m3wbna3uy2e7ad3a2ina5n3rph5@wmvlktsl6vcc>","date":"2025-10-24T11:47:18","subject":"Re: [PATCH v13 4/8] libcamera: simple: Validate raw stream\n\tconfigurations","submitter":{"id":232,"url":"https://patchwork.libcamera.org/api/people/232/","name":"Umang Jain","email":"uajain@igalia.com"},"content":"Hi Milan,\n\nOn Tue, Oct 21, 2025 at 08:27:11PM +0200, Milan Zamazal wrote:\n> SimpleCameraConfiguration::validate() looks for the best configuration.\n> As part of enabling raw stream support, the method must consider raw\n> streams in addition to the processed streams.\n> \n> Raw streams are adjusted from the capture format and size.\n> \n> Note that with both processed and raw streams, the requested sizes must\n> be mutually matching, including resizing due to debayer requirements.\n> For 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> \n> rather than\n> \n>   cam -s role=viewfinder,width=1920,height=1080 \\\n>       -s role=raw,width=1920,height=1080\n> \n> due to the resolution of 1924x1080 actually selected for debayering to\n> 1920x1080.  If the resolutions don't match mutually or don't match the\n> available sizes, validation adjusts them.\n> \n> Setting up the right configurations is still not enough to make the raw\n> streams working.  Buffer handling must be changed in the simple\n> pipeline, which is addressed in followup patches.\n> \n> Signed-off-by: Milan Zamazal <mzamazal@redhat.com>\n> ---\n>  src/libcamera/pipeline/simple/simple.cpp | 86 +++++++++++++++++-------\n>  1 file changed, 61 insertions(+), 25 deletions(-)\n> \n> diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp\n> index d7675538f..1943b6e72 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> @@ -1141,22 +1143,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> @@ -1213,19 +1232,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)\n> -\t\t\t\t<< \"Adjusting pixel format from \"\n> -\t\t\t\t<< cfg.pixelFormat << \" to \" << pixelFormat;\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\nI would really prefer if you can check for raw pixelformat and size here\nrather than splitting at two places (once here, and for size below). I\nthink it would reduce `if (raw)` nesting below where you check for\nsizes. That way we have only one place where the raw stream\nconfiguration is getting adjusted. Maybe take reference from the last\nhunk from:\n\nhttps://gitlab.freedesktop.org/uajain/libcamera/-/commit/692be89717723705ed62c83296365dfd72ded80e\n\n\n\n>  \t\t\tcfg.pixelFormat = pixelFormat;\n>  \t\t\tstatus = Adjusted;\n>  \t\t}\n> @@ -1261,7 +1288,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> @@ -1280,11 +1307,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 and frameSize. */\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> -- \n> 2.51.0\n>","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 1B89ABE080\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri, 24 Oct 2025 11:46:53 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 67A7B608D0;\n\tFri, 24 Oct 2025 13:46:52 +0200 (CEST)","from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A38A608BD\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri, 24 Oct 2025 13:46:50 +0200 (CEST)","from 62-244-186-53.cust.exponential-e.net ([62.244.186.53]\n\thelo=uajain) by fanzine2.igalia.com with esmtpsa \n\t(Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256)\n\t(Exim) id 1vCGFt-00Ek3G-2j; Fri, 24 Oct 2025 13:46:49 +0200"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=igalia.com header.i=@igalia.com\n\theader.b=\"l9PlWPvj\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com;\n\ts=20170329;\n\th=In-Reply-To:Content-Type:MIME-Version:References:Message-ID:\n\tSubject:Cc:To:From:Date:Sender:Reply-To:Content-Transfer-Encoding:Content-ID:\n\tContent-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc\n\t:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:\n\tList-Post:List-Owner:List-Archive;\n\tbh=m6QEsksh4qGFRuLwxySlXVbs9Vqf39IGe9M6F4ixoGs=;\n\tb=l9PlWPvjKvNjkYcxhGoTT9Z3RW\n\tQ+wj1dCWV2ZIgsitaoyM+xZk7VdoWPXsNqgKaFuURNraAO9YWQp3ZYz98UUPYKB0beTcLRJSrZU5Q\n\tEeZRCs/2wca4wJJz4Z9zMdlcSJJZgXiicppoc7oGlRstE07taSJn1bdG7tfWXge1WXVEBBQCQ3fNh\n\t2flaEbPvL9yMxdLme6gdNNnq6VSQV/2C6NiqIsgnuJdNF5gMh6EhuESrAcOoe+g+N4NKej5tsB7dM\n\tpMu81I9NsfaYIjCRC2mrG+gnJuzGeubAcLtC9d4Bwm7+TGWJaAVtQX9G4o+TKA4H51wQWtHs/RqJO\n\tZ8q6UjNg==;","Date":"Fri, 24 Oct 2025 12:47:18 +0100","From":"Umang Jain <uajain@igalia.com>","To":"Milan Zamazal <mzamazal@redhat.com>","Cc":"libcamera-devel@lists.libcamera.org, 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":"Re: [PATCH v13 4/8] libcamera: simple: Validate raw stream\n\tconfigurations","Message-ID":"<4f2qwzroppc43pkkapmhys5m3wbna3uy2e7ad3a2ina5n3rph5@wmvlktsl6vcc>","References":"<20251021182716.29274-1-mzamazal@redhat.com>\n\t<20251021182716.29274-5-mzamazal@redhat.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20251021182716.29274-5-mzamazal@redhat.com>","User-Agent":"NeoMutt/20250905-dirty","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>"}}]