[RFC,4/7] apps: cam: Add support for multiple sinks
diff mbox series

Message ID 20250314202943.112109-5-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
It would be useful if cam supported output to different sinks when run
with multiple streams.  For example, a processed stream could be
displayed while a raw stream would be sent to files.  Or a processed
stream could be output to PPM files while a raw stream to raw files.

Let's start with replacing the single CameraSession::sink_ with a vector
of sinks_.  We put just the default sink there for now, more
functionality will be added in followup patches.

Signed-off-by: Milan Zamazal <mzamazal@redhat.com>
---
 src/apps/cam/camera_session.cpp | 51 +++++++++++++++++++++------------
 src/apps/cam/camera_session.h   |  2 +-
 2 files changed, 33 insertions(+), 20 deletions(-)

Patch
diff mbox series

diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp
index 937a56b5..54073cdf 100644
--- a/src/apps/cam/camera_session.cpp
+++ b/src/apps/cam/camera_session.cpp
@@ -20,6 +20,7 @@ 
 
 #include "capture_script.h"
 #include "file_sink.h"
+#include "frame_sink.h"
 #ifdef HAVE_KMS
 #include "kms_sink.h"
 #endif
@@ -255,14 +256,17 @@  int CameraSession::start()
 
 	camera_->requestCompleted.connect(this, &CameraSession::requestComplete);
 
+	sinks_.clear();
+	std::unique_ptr<FrameSink> defaultSink;
 #ifdef HAVE_KMS
 	if (options_.isSet(OptDisplay))
-		sink_ = std::make_unique<KMSSink>(options_[OptDisplay].toString());
+		defaultSink =
+			std::make_unique<KMSSink>(options_[OptDisplay].toString());
 #endif
 
 #ifdef HAVE_SDL
 	if (options_.isSet(OptSDL))
-		sink_ = std::make_unique<SDLSink>();
+		defaultSink = std::make_unique<SDLSink>();
 #endif
 
 	if (options_.isSet(OptFile)) {
@@ -275,18 +279,21 @@  int CameraSession::start()
 				return ret;
 		}
 
-		sink_ = std::move(sink);
+		defaultSink = std::move(sink);
 	}
 
-	if (sink_) {
-		ret = sink_->configure(*config_);
+	if (defaultSink)
+		sinks_.push_back(std::move(defaultSink));
+
+	for (auto &sink : sinks_) {
+		ret = sink->configure(*config_);
 		if (ret < 0) {
 			std::cout << "Failed to configure frame sink"
 				  << std::endl;
 			return ret;
 		}
 
-		sink_->requestProcessed.connect(this, &CameraSession::sinkRelease);
+		sink->requestProcessed.connect(this, &CameraSession::sinkRelease);
 	}
 
 	allocator_ = std::make_unique<FrameBufferAllocator>(camera_);
@@ -300,13 +307,14 @@  void CameraSession::stop()
 	if (ret)
 		std::cout << "Failed to stop capture" << std::endl;
 
-	if (sink_) {
-		ret = sink_->stop();
+	for (auto &sink : sinks_) {
+		ret = sink->stop();
 		if (ret)
 			std::cout << "Failed to stop frame sink" << std::endl;
 	}
 
-	sink_.reset();
+	for (auto &sink : sinks_)
+		sink.reset();
 
 	requests_.clear();
 
@@ -355,15 +363,15 @@  int CameraSession::startCapture()
 				return ret;
 			}
 
-			if (sink_)
-				sink_->mapBuffer(buffer.get());
+			for (auto &sink : sinks_)
+				sink->mapBuffer(buffer.get());
 		}
 
 		requests_.push_back(std::move(request));
 	}
 
-	if (sink_) {
-		ret = sink_->start();
+	for (auto &sink : sinks_) {
+		ret = sink->start();
 		if (ret) {
 			std::cout << "Failed to start frame sink" << std::endl;
 			return ret;
@@ -373,8 +381,8 @@  int CameraSession::startCapture()
 	ret = camera_->start();
 	if (ret) {
 		std::cout << "Failed to start capture" << std::endl;
-		if (sink_)
-			sink_->stop();
+		for (auto &sink : sinks_)
+			sink->stop();
 		return ret;
 	}
 
@@ -383,8 +391,8 @@  int CameraSession::startCapture()
 		if (ret < 0) {
 			std::cerr << "Can't queue request" << std::endl;
 			camera_->stop();
-			if (sink_)
-				sink_->stop();
+			for (auto &sink : sinks_)
+				sink->stop();
 			return ret;
 		}
 	}
@@ -471,9 +479,14 @@  void CameraSession::processRequest(Request *request)
 		}
 	}
 
-	if (sink_) {
-		if (!sink_->processRequest(request))
+	for (auto &sink : sinks_) {
+		if (!sink->processRequest(request)) {
+			/*
+			 * \todo What happens with the other sinks when the whole request
+			 * gets requeued?
+			 */
 			requeue = false;
+		}
 	}
 
 	std::cout << info.str() << std::endl;
diff --git a/src/apps/cam/camera_session.h b/src/apps/cam/camera_session.h
index 4442fd9b..056091e5 100644
--- a/src/apps/cam/camera_session.h
+++ b/src/apps/cam/camera_session.h
@@ -64,7 +64,7 @@  private:
 	std::unique_ptr<CaptureScript> script_;
 
 	std::map<const libcamera::Stream *, std::string> streamNames_;
-	std::unique_ptr<FrameSink> sink_;
+	std::vector<std::unique_ptr<FrameSink>> sinks_;
 	unsigned int cameraIndex_;
 
 	uint64_t last_;