[RFC,6/7] apps: cam: Track sink streams
diff mbox series

Message ID 20250314202943.112109-7-mzamazal@redhat.com
State New
Headers show
Series
  • Support different outputs for cam streams
Related show

Commit Message

Milan Zamazal March 14, 2025, 8:29 p.m. UTC
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@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(-)

Patch
diff mbox series

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;