[RFC,v2,08/13] libcamera: simple: Handle adjusted and raw configurations separately
diff mbox series

Message ID 20250124215806.158024-9-mzamazal@redhat.com
State New
Headers show
Series
  • Enable raw streams with software ISP
Related show

Commit Message

Milan Zamazal Jan. 24, 2025, 9:57 p.m. UTC
When using software ISP to produce both a processed and a raw stream at
the same time, we have to deal with two different output formats.

When generating stream configurations, consider only raw formats for raw
streams.  Also, mark raw configurations using
StreamConfiguration::colorSpace value, which is the only available place
in StreamConfiguration for the purpose.

When validating stream configurations, use separate check for sizes to
produce raw and processed pipe configurations.  Later, use the
corresponding pipe configurations for raw and processed stream
configurations.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 src/libcamera/pipeline/simple/simple.cpp | 90 ++++++++++++++++++++----
 1 file changed, 77 insertions(+), 13 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 87a2043f..beb11069 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -25,6 +25,7 @@ 
 #include <libcamera/base/log.h>
 
 #include <libcamera/camera.h>
+#include <libcamera/color_space.h>
 #include <libcamera/control_ids.h>
 #include <libcamera/pixel_format.h>
 #include <libcamera/request.h>
@@ -1062,7 +1063,9 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 	 * without upscaling.
 	 */
 	const SimpleCameraData::Configuration *maxPipeConfig = nullptr;
+	const SimpleCameraData::Configuration *maxPipeConfigRaw = nullptr;
 	pipeConfig_ = nullptr;
+	const SimpleCameraData::Configuration *pipeConfigRaw = nullptr;
 
 	for (const SimpleCameraData::Configuration *pipeConfig : *configs) {
 		const Size &size = pipeConfig->captureSize;
@@ -1075,6 +1078,17 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 
 		if (!maxPipeConfig || maxPipeConfig->captureSize < size)
 			maxPipeConfig = pipeConfig;
+
+		if (!pipeConfig->swisp) {
+			if (size.width >= maxStreamSize.width &&
+			    size.height >= maxStreamSize.height) {
+				if (!pipeConfigRaw || size < pipeConfigRaw->captureSize)
+					pipeConfigRaw = pipeConfig;
+			}
+
+			if (!maxPipeConfigRaw || maxPipeConfigRaw->captureSize < size)
+				maxPipeConfigRaw = pipeConfig;
+		}
 	}
 
 	/* If no configuration was large enough, select the largest one. */
@@ -1085,6 +1099,13 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 		}
 		pipeConfig_ = maxPipeConfig;
 	}
+	if (data_->rawRequested_ && !pipeConfigRaw) {
+		if (!maxPipeConfigRaw) {
+			LOG(SimplePipeline, Error) << "No valid configuration for raw found";
+			return Invalid;
+		}
+		pipeConfigRaw = maxPipeConfigRaw;
+	}
 
 	LOG(SimplePipeline, Debug)
 		<< "Picked "
@@ -1092,6 +1113,14 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 		<< " -> " << pipeConfig_->captureSize
 		<< "-" << pipeConfig_->captureFormat
 		<< " for max stream size " << maxStreamSize;
+	if (pipeConfigRaw) {
+		LOG(SimplePipeline, Info)
+			<< "Picked raw "
+			<< V4L2SubdeviceFormat{ pipeConfigRaw->code, pipeConfigRaw->sensorSize, {} }
+			<< " -> " << pipeConfigRaw->captureSize
+			<< "-" << pipeConfigRaw->captureFormat
+			<< " for max stream size " << maxStreamSize;
+	}
 
 	/*
 	 * Adjust the requested streams.
@@ -1110,31 +1139,50 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 
 	for (unsigned int i = 0; i < config_.size(); ++i) {
 		StreamConfiguration &cfg = config_[i];
+		const SimpleCameraData::Configuration *pipeConfig =
+			(cfg.colorSpace == ColorSpace::Raw ? pipeConfigRaw : pipeConfig_);
+		if (!pipeConfig)
+			continue;
 
 		/* Adjust the pixel format and size. */
-		auto it = std::find(pipeConfig_->outputFormats.begin(),
-				    pipeConfig_->outputFormats.end(),
+		auto it = std::find(pipeConfig->outputFormats.begin(),
+				    pipeConfig->outputFormats.end(),
 				    cfg.pixelFormat);
-		if (it == pipeConfig_->outputFormats.end())
-			it = pipeConfig_->outputFormats.begin();
+		if (it == pipeConfig->outputFormats.end())
+			it = pipeConfig->outputFormats.begin();
 
 		PixelFormat pixelFormat = *it;
 		if (cfg.pixelFormat != pixelFormat) {
+			if (isRawFormat(pixelFormat)) {
+				LOG(SimplePipeline, Error)
+					<< "Cannot convert pixel format with raw output (from "
+					<< cfg.pixelFormat << " to "
+					<< pixelFormat << ")";
+				return Invalid;
+			}
 			LOG(SimplePipeline, Debug) << "Adjusting pixel format";
 			cfg.pixelFormat = pixelFormat;
 			status = Adjusted;
 		}
 
-		if (!pipeConfig_->outputSizes.contains(cfg.size)) {
-			Size adjustedSize = pipeConfig_->captureSize;
+		if (!pipeConfig->outputSizes.contains(cfg.size)) {
+			Size adjustedSize = pipeConfig->captureSize;
 			/*
 			 * The converter (when present) may not be able to output
 			 * a size identical to its input size. The capture size is thus
 			 * not guaranteed to be a valid output size. In such cases, use
 			 * the smaller valid output size closest to the requested.
 			 */
-			if (!pipeConfig_->outputSizes.contains(adjustedSize))
-				adjustedSize = adjustSize(cfg.size, pipeConfig_->outputSizes);
+			if (!pipeConfig->outputSizes.contains(adjustedSize)) {
+				if (isRawFormat(pixelFormat)) {
+					LOG(SimplePipeline, Error)
+						<< "Cannot adjust output size with raw output (from "
+						<< cfg.pixelFormat << " to "
+						<< pixelFormat << ")";
+					return Invalid;
+				}
+				adjustedSize = adjustSize(cfg.size, pipeConfig->outputSizes);
+			}
 			LOG(SimplePipeline, Debug)
 				<< "Adjusting size from " << cfg.size
 				<< " to " << adjustedSize;
@@ -1143,8 +1191,8 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 		}
 
 		/* \todo Create a libcamera core class to group format and size */
-		if (cfg.pixelFormat != pipeConfig_->captureFormat ||
-		    cfg.size != pipeConfig_->captureSize)
+		if (cfg.pixelFormat != pipeConfig->captureFormat ||
+		    cfg.size != pipeConfig->captureSize)
 			needConversion_ = true;
 
 		/* Set the stride, frameSize and bufferCount. */
@@ -1246,10 +1294,26 @@  SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo
 	 *
 	 * \todo Implement a better way to pick the default format
 	 */
-	for ([[maybe_unused]] StreamRole role : roles) {
+	for (StreamRole role : roles) {
 		StreamConfiguration cfg{ StreamFormats{ formats } };
-		cfg.pixelFormat = formats.begin()->first;
-		cfg.size = formats.begin()->second[0].max;
+		if (role == StreamRole::Raw) {
+			bool found = false;
+			for (auto &[format, sizes] : formats)
+				if (isRawFormat(format)) {
+					cfg.pixelFormat = format;
+					cfg.size = sizes[0].max;
+					found = true;
+					break;
+				}
+			if (!found) {
+				LOG(SimplePipeline, Error) << "Raw stream requested but no raw format found ";
+				return nullptr;
+			}
+			cfg.colorSpace = ColorSpace::Raw;
+		} else {
+			cfg.pixelFormat = formats.begin()->first;
+			cfg.size = formats.begin()->second[0].max;
+		}
 
 		config->addConfiguration(cfg);
 	}