[RFC PATCH 6/7] apps: cam: Track sink streams

Milan Zamazal mzamazal at redhat.com
Fri Mar 14 21:29:34 CET 2025


In order to support different sinks for different streams, we must track
the relationship between sinks and streams.  Let's track the
corresponding streams in FrameSink.  Different kinds of sinks use
different approaches to multiple streams; keeping the sinks to handle
that this way is the simplest.

Let's add FrameSink class member and some utility methods for the
purpose.

We still create only one, the default, sink, so all the streams are
added to the default sink unconditionally.  This will be changed in
a followup patch.

Operations on each given sink are applied only for streams the sink
contains.

Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
---
 src/apps/cam/camera_session.cpp |  9 ++++++++-
 src/apps/cam/file_sink.cpp      |  3 ++-
 src/apps/cam/frame_sink.cpp     | 14 ++++++++++++++
 src/apps/cam/frame_sink.h       | 26 ++++++++++++++++++++++++++
 src/apps/cam/kms_sink.cpp       |  8 +++++++-
 src/apps/cam/sdl_sink.cpp       | 15 ++++++++-------
 6 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp
index b1f5209d..5124029b 100644
--- a/src/apps/cam/camera_session.cpp
+++ b/src/apps/cam/camera_session.cpp
@@ -292,6 +292,12 @@ int CameraSession::start()
 		defaultSink = std::move(sink);
 	}
 
+	for (unsigned int i = 0; i < config_->size(); i++) {
+		const StreamConfiguration &cfg = config_->at(i);
+		if (defaultSink)
+			defaultSink->addStream(cfg.stream());
+	}
+
 	if (defaultSink)
 		sinks_.push_back(std::move(defaultSink));
 
@@ -374,7 +380,8 @@ int CameraSession::startCapture()
 			}
 
 			for (auto &sink : sinks_)
-				sink->mapBuffer(buffer.get());
+				if (sink->assignedStream(stream))
+					sink->mapBuffer(buffer.get());
 		}
 
 		requests_.push_back(std::move(request));
diff --git a/src/apps/cam/file_sink.cpp b/src/apps/cam/file_sink.cpp
index 76e21db9..9ef4011b 100644
--- a/src/apps/cam/file_sink.cpp
+++ b/src/apps/cam/file_sink.cpp
@@ -96,7 +96,8 @@ void FileSink::mapBuffer(FrameBuffer *buffer)
 bool FileSink::processRequest(Request *request)
 {
 	for (auto [stream, buffer] : request->buffers())
-		writeBuffer(stream, buffer, request->metadata());
+		if (assignedStream(stream))
+			writeBuffer(stream, buffer, request->metadata());
 
 	return true;
 }
diff --git a/src/apps/cam/frame_sink.cpp b/src/apps/cam/frame_sink.cpp
index 68d6f2c1..51c85124 100644
--- a/src/apps/cam/frame_sink.cpp
+++ b/src/apps/cam/frame_sink.cpp
@@ -7,6 +7,8 @@
 
 #include "frame_sink.h"
 
+#include <iostream>
+
 /**
  * \class FrameSink
  * \brief Abstract class to model a consumer of frames
@@ -65,3 +67,15 @@ int FrameSink::stop()
  * \return True if the request has been processed synchronously, false if
  * processing has been queued
  */
+
+const libcamera::StreamConfiguration &FrameSink::findConfiguration(
+	const libcamera::CameraConfiguration &config)
+{
+	for (unsigned int i = 0; i < config.size(); i++)
+		if (assignedStream(config.at(i).stream()))
+			return config.at(i);
+
+	/* This should never happen. */
+	std::cerr << "No camera configuration for frame sink" << std::endl;
+	return config.at(0);
+}
diff --git a/src/apps/cam/frame_sink.h b/src/apps/cam/frame_sink.h
index 11105c6c..c51db775 100644
--- a/src/apps/cam/frame_sink.h
+++ b/src/apps/cam/frame_sink.h
@@ -7,8 +7,13 @@
 
 #pragma once
 
+#include <vector>
+
 #include <libcamera/base/signal.h>
 
+#include <libcamera/camera.h>
+#include <libcamera/stream.h>
+
 namespace libcamera {
 class CameraConfiguration;
 class FrameBuffer;
@@ -27,6 +32,27 @@ public:
 	virtual int start();
 	virtual int stop();
 
+	void addStream(libcamera::Stream *const stream)
+	{
+		streams_.push_back(stream);
+	}
+
+	bool assignedStream(const libcamera::Stream *const stream)
+	{
+		return std::find(streams_.begin(), streams_.end(), stream) != streams_.end();
+	}
+
+	bool empty()
+	{
+		return streams_.empty();
+	}
+
 	virtual bool processRequest(libcamera::Request *request) = 0;
 	libcamera::Signal<libcamera::Request *> requestProcessed;
+
+protected:
+	const libcamera::StreamConfiguration &findConfiguration(
+		const libcamera::CameraConfiguration &config);
+
+	std::vector<libcamera::Stream *> streams_;
 };
diff --git a/src/apps/cam/kms_sink.cpp b/src/apps/cam/kms_sink.cpp
index 6490a5c0..1fc559ed 100644
--- a/src/apps/cam/kms_sink.cpp
+++ b/src/apps/cam/kms_sink.cpp
@@ -110,7 +110,7 @@ int KMSSink::configure(const libcamera::CameraConfiguration &config)
 	plane_ = nullptr;
 	mode_ = nullptr;
 
-	const libcamera::StreamConfiguration &cfg = config.at(0);
+	const libcamera::StreamConfiguration &cfg = findConfiguration(config);
 
 	/* Find the best mode for the stream size. */
 	const std::vector<DRM::Mode> &modes = connector_->modes();
@@ -456,6 +456,12 @@ bool KMSSink::processRequest(libcamera::Request *camRequest)
 		return true;
 
 	libcamera::FrameBuffer *buffer = camRequest->buffers().begin()->second;
+	for (auto [stream, buf] : camRequest->buffers()) {
+		if (assignedStream(stream)) {
+			buffer = buf;
+			break;
+		}
+	}
 	auto iter = buffers_.find(buffer);
 	if (iter == buffers_.end())
 		return true;
diff --git a/src/apps/cam/sdl_sink.cpp b/src/apps/cam/sdl_sink.cpp
index e8a54f7a..8a7df372 100644
--- a/src/apps/cam/sdl_sink.cpp
+++ b/src/apps/cam/sdl_sink.cpp
@@ -44,18 +44,17 @@ int SDLSink::configure(const libcamera::CameraConfiguration &config)
 	if (ret < 0)
 		return ret;
 
-	if (config.size() > 1) {
+	if (streams_.size() > 1) {
 		std::cerr
-			<< "SDL sink only supports one camera stream at present, streaming first camera stream"
+			<< "SDL sink only supports one camera stream at present, streaming first stream"
 			<< std::endl;
-	} else if (config.empty()) {
+	} else if (streams_.empty()) {
 		std::cerr << "Require at least one camera stream to process"
 			  << std::endl;
 		return -EINVAL;
 	}
 
-	const libcamera::StreamConfiguration &cfg = config.at(0);
-	rect_.w = cfg.size.width;
+	const libcamera::StreamConfiguration &cfg = findConfiguration(config);
 	rect_.h = cfg.size.height;
 
 	switch (cfg.pixelFormat) {
@@ -163,8 +162,10 @@ void SDLSink::mapBuffer(FrameBuffer *buffer)
 bool SDLSink::processRequest(Request *request)
 {
 	for (auto [stream, buffer] : request->buffers()) {
-		renderBuffer(buffer);
-		break; /* to be expanded to launch SDL window per buffer */
+		if (assignedStream(stream)) {
+			renderBuffer(buffer);
+			break; /* to be expanded to launch SDL window per buffer */
+		}
 	}
 
 	return true;
-- 
2.48.1



More information about the libcamera-devel mailing list