[RFC,1/1] libcamera: simple: Fix raw output
diff mbox series

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

Commit Message

Milan Zamazal Nov. 22, 2024, 8:13 p.m. UTC
Simple pipeline was used to introduce software ISP.  If software ISP is
enabled, the pipeline always debayers the input and doesn't produce raw
output anymore, even when requested.

This patch fixes the problem and allows producing raw output if it is
requested, by specifying raw stream role.  When raw output is requested,
only single stream (raw or processed) is allowed.  This is not
necessarily an inherent property, it just simplifies the implementation
and is sufficient for the current needs.

If raw stream is requested, it means raw as it is and no pixel format or
size conversions are permitted.  This is not only logical but also
simplifying the changes because we don't have to check for raw when
conversion is used.

The patch must deal with the fact that software ISP and its output
configurations are arranged before we know whether a raw or a processed
stream will be requested.  This means that if software ISP is enabled
then it is always initialized and we store raw output configurations
together with software ISP ones.  We filter output configurations later
as needed.

The raw output may not be useful without exposure and gain adjustments,
it can be all black (or just noisy).  This will be handled in a separate
patch introducing manual gain and exposure controls.

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

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 41fdf84cc..ec7cd7123 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -265,6 +265,7 @@  public:
 		Size captureSize;
 		std::vector<PixelFormat> outputFormats;
 		SizeRange outputSizes;
+		bool swisp;
 	};
 
 	std::vector<Stream> streams_;
@@ -289,6 +290,7 @@  public:
 	};
 	std::queue<RequestOutputs> conversionQueue_;
 	bool useConversion_;
+	bool isRaw_;
 
 	std::unique_ptr<Converter> converter_;
 	std::unique_ptr<SoftwareIsp> swIsp_;
@@ -646,19 +648,24 @@  void SimpleCameraData::tryPipeline(unsigned int code, const Size &size)
 		config.sensorSize = size;
 		config.captureFormat = pixelFormat;
 		config.captureSize = format.size;
+		config.swisp = false;
 
 		if (converter_) {
 			config.outputFormats = converter_->formats(pixelFormat);
 			config.outputSizes = converter_->sizes(format.size);
-		} else if (swIsp_) {
-			config.outputFormats = swIsp_->formats(pixelFormat);
-			config.outputSizes = swIsp_->sizes(pixelFormat, format.size);
-			if (config.outputFormats.empty()) {
-				/* Do not use swIsp for unsupported pixelFormat's. */
-				config.outputFormats = { pixelFormat };
-				config.outputSizes = config.captureSize;
-			}
 		} else {
+			if (swIsp_) {
+				Configuration swispConfig = config;
+				swispConfig.outputFormats = swIsp_->formats(pixelFormat);
+				swispConfig.outputSizes = swIsp_->sizes(pixelFormat, format.size);
+				if (swispConfig.outputFormats.empty()) {
+					/* Do not use swIsp for unsupported pixelFormat's. */
+					swispConfig.outputFormats = { pixelFormat };
+					swispConfig.outputSizes = swispConfig.captureSize;
+				}
+				swispConfig.swisp = true;
+				configs_.push_back(swispConfig);
+			}
 			config.outputFormats = { pixelFormat };
 			config.outputSizes = config.captureSize;
 		}
@@ -859,7 +866,7 @@  void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 
 		if (converter_)
 			converter_->queueBuffers(buffer, conversionQueue_.front().outputs);
-		else
+		else if (!isRaw_) {
 			/*
 			 * request->sequence() cannot be retrieved from `buffer' inside
 			 * queueBuffers because unique_ptr's make buffer->request() invalid
@@ -867,6 +874,7 @@  void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 			 */
 			swIsp_->queueBuffers(request->sequence(), buffer,
 					     conversionQueue_.front().outputs);
+		}
 
 		conversionQueue_.pop();
 		return;
@@ -1049,6 +1057,8 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 	pipeConfig_ = nullptr;
 
 	for (const SimpleCameraData::Configuration *pipeConfig : *configs) {
+		if (pipeConfig->swisp == data_->isRaw_)
+			continue;
 		const Size &size = pipeConfig->captureSize;
 
 		if (size.width >= maxStreamSize.width &&
@@ -1099,6 +1109,13 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 
 		PixelFormat pixelFormat = *it;
 		if (cfg.pixelFormat != pixelFormat) {
+			if (data_->isRaw_) {
+				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;
@@ -1112,8 +1129,16 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 			 * 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))
+			if (!pipeConfig_->outputSizes.contains(adjustedSize)) {
+				if (data_->isRaw_) {
+					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;
@@ -1174,12 +1199,29 @@  SimplePipelineHandler::generateConfiguration(Camera *camera, Span<const StreamRo
 	if (roles.empty())
 		return config;
 
+	bool raw = false;
+	for (auto &role : roles) {
+		if (role == StreamRole::Raw) {
+			raw = true;
+			break;
+		}
+	}
+	if (raw && roles.size() > 1) {
+		LOG(SimplePipeline, Error)
+			<< "Can't capture multiple streams with a raw stream";
+		return nullptr;
+	}
+	data->isRaw_ = raw;
+	LOG(SimplePipeline, Debug) << "Raw stream requested: " << raw;
+
 	/* Create the formats map. */
 	std::map<PixelFormat, std::vector<SizeRange>> formats;
 
 	for (const SimpleCameraData::Configuration &cfg : data->configs_) {
-		for (PixelFormat format : cfg.outputFormats)
-			formats[format].push_back(cfg.outputSizes);
+		if (raw != cfg.swisp) {
+			for (PixelFormat format : cfg.outputFormats)
+				formats[format].push_back(cfg.outputSizes);
+		}
 	}
 
 	/* Sort the sizes and merge any consecutive overlapping ranges. */