From patchwork Mon Aug 4 16:38:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Zamazal X-Patchwork-Id: 24051 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id BE06EBDCC1 for ; Mon, 4 Aug 2025 16:38:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7BC5B69222; Mon, 4 Aug 2025 18:38:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="eMg3vOil"; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D665A6921A for ; Mon, 4 Aug 2025 18:38:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1754325524; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=4g9Ccmh7piaYCtomDUi/3Vc8f39//YnbWrG7uEkgyPk=; b=eMg3vOilLvN/Zl+zgeAs0mJWeZOGg9rnGrDwaFYF3WjkYFwc0GB7POZ7yYfcicEIKr4Ot6 lQUmSKb5/4qAzMWyGHukJ0sRajdZ0hIctVSn4PVK9Rfccc0ymhxOWoCmJR2GXqy3NmqNpe HBNTNh450qV5T8bF/MQgkeEloIJNdzw= Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-443-KKs8NfYpNk2g6R41s6vgzg-1; Mon, 04 Aug 2025 12:38:39 -0400 X-MC-Unique: KKs8NfYpNk2g6R41s6vgzg-1 X-Mimecast-MFC-AGG-ID: KKs8NfYpNk2g6R41s6vgzg_1754325518 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1442019774D9; Mon, 4 Aug 2025 16:38:38 +0000 (UTC) Received: from mzamazal-thinkpadp1gen7.tpbc.com (unknown [10.44.32.17]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 60E261800D8A; Mon, 4 Aug 2025 16:38:35 +0000 (UTC) From: Milan Zamazal To: libcamera-devel@lists.libcamera.org Cc: Milan Zamazal , Laurent Pinchart , Kieran Bingham , =?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= , Paul Elder , Umang Jain Subject: [PATCH v12 4/8] libcamera: simple: Validate raw stream configurations 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-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: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" SimpleCameraConfiguration::validate() looks for the best configuration. As part of enabling raw stream support, the method must consider raw streams in addition to the processed streams. Raw streams are adjusted from the capture format and size. Note that with both processed and raw streams, the requested sizes must be mutually matching, including resizing due to debayer requirements. For example, the following `cam' setup is valid for imx219 cam -s role=viewfinder,width=1920,height=1080 \ -s role=raw,width=3280,height=2464 rather than cam -s role=viewfinder,width=1920,height=1080 \ -s role=raw,width=1920,height=1080 due to the resolution of 1924x1080 actually selected for debayering to 1920x1080. If the resolutions don't match mutually or don't match the available sizes, validation adjusts them. Setting up the right configurations is still not enough to make the raw streams working. Buffer handling must be changed in the simple pipeline, which is addressed in followup patches. Signed-off-by: Milan Zamazal --- src/libcamera/pipeline/simple/simple.cpp | 86 +++++++++++++++++------- 1 file changed, 62 insertions(+), 24 deletions(-) diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index bc4d7bd41..1ad982a4c 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1134,22 +1136,39 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() << "Largest stream size is " << maxStreamSize; /* - * Find the best configuration for the pipeline using a heuristic. - * First select the pixel format based on the streams (which are - * considered ordered from highest to lowest priority). Default to the - * first pipeline configuration if no streams request a supported pixel - * format. + * Find the best configuration for the pipeline using a heuristic. First + * select the pixel format based on the streams. If there is a raw stream, + * its format has precedence. If there is no raw stream, the streams are + * considered ordered from highest to lowest priority. Default to the first + * pipeline configuration if no streams request a supported pixel format. */ - const std::vector *configs = - &data_->formats_.begin()->second; + std::optional rawFormat; + for (const auto &cfg : config_) + if (isRaw(cfg)) { + if (rawFormat) { + LOG(SimplePipeline, Error) + << "Can't capture multiple raw streams"; + return Invalid; + } + rawFormat = cfg.pixelFormat; + } - for (const StreamConfiguration &cfg : config_) { - auto it = data_->formats_.find(cfg.pixelFormat); - if (it != data_->formats_.end()) { + const std::vector *configs = nullptr; + if (rawFormat) { + auto it = data_->formats_.find(rawFormat.value()); + if (it != data_->formats_.end()) configs = &it->second; - break; - } } + if (!configs) + for (const StreamConfiguration &cfg : config_) { + auto it = data_->formats_.find(cfg.pixelFormat); + if (it != data_->formats_.end()) { + configs = &it->second; + break; + } + } + if (!configs) + configs = &data_->formats_.begin()->second; /* * \todo Pick the best sensor output media bus format when the @@ -1206,17 +1225,27 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() for (unsigned int i = 0; i < config_.size(); ++i) { StreamConfiguration &cfg = config_[i]; + const bool raw = isRaw(cfg); - /* Adjust the pixel format and size. */ - auto it = std::find(pipeConfig_->outputFormats.begin(), - pipeConfig_->outputFormats.end(), - cfg.pixelFormat); - if (it == pipeConfig_->outputFormats.end()) - it = pipeConfig_->outputFormats.begin(); + /* Adjust the pixel format, colour space and size. */ - PixelFormat pixelFormat = *it; + PixelFormat pixelFormat; + if (raw) { + pixelFormat = pipeConfig_->captureFormat; + } else { + auto it = std::find(pipeConfig_->outputFormats.begin(), + pipeConfig_->outputFormats.end(), + cfg.pixelFormat); + if (it == pipeConfig_->outputFormats.end()) + it = pipeConfig_->outputFormats.begin(); + pixelFormat = *it; + } if (cfg.pixelFormat != pixelFormat) { - LOG(SimplePipeline, Debug) << "Adjusting pixel format"; + LOG(SimplePipeline, Debug) + << "Adjusting pixel format of a " + << (raw ? "raw" : "processed") + << " stream from " << cfg.pixelFormat + << " to " << pixelFormat; cfg.pixelFormat = pixelFormat; status = Adjusted; } @@ -1252,7 +1281,7 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() status = Adjusted; } - if (!pipeConfig_->outputSizes.contains(cfg.size)) { + if (!raw && !pipeConfig_->outputSizes.contains(cfg.size)) { Size adjustedSize = pipeConfig_->captureSize; /* * The converter (when present) may not be able to output @@ -1271,11 +1300,20 @@ CameraConfiguration::Status SimpleCameraConfiguration::validate() /* \todo Create a libcamera core class to group format and size */ if (cfg.pixelFormat != pipeConfig_->captureFormat || - cfg.size != pipeConfig_->captureSize) - needConversion_ = true; + cfg.size != pipeConfig_->captureSize) { + if (raw) { + cfg.pixelFormat = pipeConfig_->captureFormat; + cfg.size = pipeConfig_->captureSize; + LOG(SimplePipeline, Debug) + << "Adjusting raw configuration to " << cfg; + status = Adjusted; + } else { + needConversion_ = true; + } + } /* Set the stride, frameSize and bufferCount. */ - if (needConversion_) { + if (needConversion_ && !raw) { std::tie(cfg.stride, cfg.frameSize) = data_->converter_ ? data_->converter_->strideAndFrameSize(cfg.pixelFormat,