[RFC,6/6] libcamera: simple: Enable capturing of raw streams
diff mbox series

Message ID 20250716142027.236277-8-uajain@igalia.com
State New
Headers show
Series
  • Untitled series #5290
Related show

Commit Message

Umang Jain July 16, 2025, 2:20 p.m. UTC
Enable capturing of raw streams (standalone or in combination with
a processed stream). Track the raw stream (if requested) in
SimpleCameraData and adapt the buffer handling management accordingly.

Signed-off-by: Umang Jain <uajain@igalia.com>
---
 src/libcamera/pipeline/simple/simple.cpp | 48 +++++++++++++++++-------
 1 file changed, 35 insertions(+), 13 deletions(-)

Patch
diff mbox series

diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 75469e3a..78c9758a 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -326,6 +326,7 @@  public:
 	};
 
 	std::vector<Stream> streams_;
+	Stream *rawStream_;
 
 	/*
 	 * All entities in the pipeline, from the camera sensor to the video
@@ -453,7 +454,7 @@  private:
 SimpleCameraData::SimpleCameraData(SimplePipelineHandler *pipe,
 				   unsigned int numStreams,
 				   MediaEntity *sensor)
-	: Camera::Private(pipe), streams_(numStreams)
+	: Camera::Private(pipe), streams_(numStreams), rawStream_(nullptr)
 {
 	/*
 	 * Find the shortest path from the camera sensor to a video capture
@@ -926,7 +927,8 @@  void SimpleCameraData::imageBufferReady(FrameBuffer *buffer)
 	 */
 	if (useConversion_) {
 		if (conversionQueue_.empty()) {
-			video_->queueBuffer(buffer);
+			if (!rawStream_)
+				video_->queueBuffer(buffer);
 			return;
 		}
 
@@ -979,7 +981,14 @@  void SimpleCameraData::tryCompleteRequest(Request *request)
 void SimpleCameraData::conversionInputDone(FrameBuffer *buffer)
 {
 	/* Queue the input buffer back for capture. */
-	video_->queueBuffer(buffer);
+	if (!rawStream_) {
+		video_->queueBuffer(buffer);
+	} else {
+		/* Complete the input buffer. */
+		Request *request = buffer->request();
+		if (pipe()->completeBuffer(request, buffer))
+			tryCompleteRequest(request);
+	}
 }
 
 void SimpleCameraData::conversionOutputDone(FrameBuffer *buffer)
@@ -1219,7 +1228,7 @@  CameraConfiguration::Status SimpleCameraConfiguration::validate()
 	 * require any conversion, similar to raw capture use cases). This is
 	 * left as a future improvement.
 	 */
-	needConversion_ = config_.size() > 1;
+	needConversion_ = config_.size() > 1 + rawCount;
 
 	for (unsigned int i = 0; i < config_.size(); ++i) {
 		StreamConfiguration &cfg = config_[i];
@@ -1448,11 +1457,15 @@  int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
 
 	for (unsigned int i = 0; i < config->size(); ++i) {
 		StreamConfiguration &cfg = config->at(i);
+		bool rawStream = isFormatRaw(cfg.pixelFormat);
 
 		cfg.setStream(&data->streams_[i]);
 
-		if (data->useConversion_ && !isFormatRaw(cfg.pixelFormat))
+		if (data->useConversion_ && !rawStream)
 			outputCfgs.push_back(cfg);
+
+		if (rawStream)
+			data->rawStream_ = &data->streams_[i];
 	}
 
 	if (outputCfgs.empty())
@@ -1483,7 +1496,7 @@  int SimplePipelineHandler::exportFrameBuffers(Camera *camera, Stream *stream,
 	 * Export buffers on the converter or capture video node, depending on
 	 * whether the converter is used or not.
 	 */
-	if (data->useConversion_)
+	if (data->useConversion_ && (stream != data->rawStream_))
 		return data->converter_
 			       ? data->converter_->exportBuffers(stream, count, buffers)
 			       : data->swIsp_->exportBuffers(stream, count, buffers);
@@ -1505,8 +1518,7 @@  int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
 			<< pad->entity()->name() << " in use";
 		return -EBUSY;
 	}
-
-	if (data->useConversion_) {
+	if (data->useConversion_ && !data->rawStream_) {
 		/*
 		 * When using the converter allocate a fixed number of internal
 		 * buffers.
@@ -1514,8 +1526,16 @@  int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
 		ret = video->allocateBuffers(kNumInternalBuffers,
 					     &data->conversionBuffers_);
 	} else {
-		/* Otherwise, prepare for using buffers from the only stream. */
-		Stream *stream = &data->streams_[0];
+		/*
+		 * Otherwise, prepare for using buffers from either the raw
+		 * stream((if requested) or the only stream configured.
+		 */
+		Stream *stream;
+		if (data->rawStream_)
+			stream = data->rawStream_;
+		else
+			stream = &data->streams_[0];
+
 		ret = video->importBuffers(stream->configuration().bufferCount);
 	}
 	if (ret < 0) {
@@ -1556,8 +1576,10 @@  int SimplePipelineHandler::start(Camera *camera, [[maybe_unused]] const ControlL
 		}
 
 		/* Queue all internal buffers for capture. */
-		for (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)
-			video->queueBuffer(buffer.get());
+		if (!data->rawStream_) {
+			for (std::unique_ptr<FrameBuffer> &buffer : data->conversionBuffers_)
+				video->queueBuffer(buffer.get());
+		}
 	}
 
 	return 0;
@@ -1608,7 +1630,7 @@  int SimplePipelineHandler::queueRequestDevice(Camera *camera, Request *request)
 		 * queue, it will be handed to the converter in the capture
 		 * completion handler.
 		 */
-		if (data->useConversion_) {
+		if (data->useConversion_ && (stream != data->rawStream_)) {
 			buffers.emplace(stream, buffer);
 			metadataRequired = !!data->swIsp_;
 		} else {