[libcamera-devel] [PATCH v3 3/8] cam: Turn BufferWriter into a FrameSink

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Aug 4 14:43:09 CEST 2021


Make the BufferWriter class inherit from FrameSink, and use the
FrameSink API to manage it. This makes the code more generic, and will
allow usage of other sinks.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain at ideasonboard.com>
---
Changes since v2:

- Write all buffers
- Fix errno printing in writeBuffer()

Changes since v1:

- Print message if the file can't be opened
---
 src/cam/buffer_writer.cpp  | 39 +++++++++++++++++++----
 src/cam/buffer_writer.h    | 17 +++++++---
 src/cam/camera_session.cpp | 64 ++++++++++++++++++++++++++++++++------
 src/cam/camera_session.h   |  6 ++--
 4 files changed, 104 insertions(+), 22 deletions(-)

diff --git a/src/cam/buffer_writer.cpp b/src/cam/buffer_writer.cpp
index a7648a92fc92..2f4b2b02d3cb 100644
--- a/src/cam/buffer_writer.cpp
+++ b/src/cam/buffer_writer.cpp
@@ -13,6 +13,8 @@
 #include <sys/mman.h>
 #include <unistd.h>
 
+#include <libcamera/camera.h>
+
 #include "buffer_writer.h"
 
 using namespace libcamera;
@@ -32,6 +34,21 @@ BufferWriter::~BufferWriter()
 	mappedBuffers_.clear();
 }
 
+int BufferWriter::configure(const libcamera::CameraConfiguration &config)
+{
+	int ret = FrameSink::configure(config);
+	if (ret < 0)
+		return ret;
+
+	streamNames_.clear();
+	for (unsigned int index = 0; index < config.size(); ++index) {
+		const StreamConfiguration &cfg = config.at(index);
+		streamNames_[cfg.stream()] = "stream" + std::to_string(index);
+	}
+
+	return 0;
+}
+
 void BufferWriter::mapBuffer(FrameBuffer *buffer)
 {
 	for (const FrameBuffer::Plane &plane : buffer->planes()) {
@@ -43,7 +60,15 @@ void BufferWriter::mapBuffer(FrameBuffer *buffer)
 	}
 }
 
-int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName)
+bool BufferWriter::processRequest(Request *request)
+{
+	for (auto [stream, buffer] : request->buffers())
+		writeBuffer(stream, buffer);
+
+	return true;
+}
+
+void BufferWriter::writeBuffer(const Stream *stream, FrameBuffer *buffer)
 {
 	std::string filename;
 	size_t pos;
@@ -58,7 +83,7 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName)
 	pos = filename.find_first_of('#');
 	if (pos != std::string::npos) {
 		std::stringstream ss;
-		ss << streamName << "-" << std::setw(6)
+		ss << streamNames_[stream] << "-" << std::setw(6)
 		   << std::setfill('0') << buffer->metadata().sequence;
 		filename.replace(pos, 1, ss.str());
 	}
@@ -66,8 +91,12 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName)
 	fd = open(filename.c_str(), O_CREAT | O_WRONLY |
 		  (pos == std::string::npos ? O_APPEND : O_TRUNC),
 		  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
-	if (fd == -1)
-		return -errno;
+	if (fd == -1) {
+		ret = -errno;
+		std::cerr << "failed to open file " << filename << ": "
+			  << strerror(-ret) << std::endl;
+		return;
+	}
 
 	for (unsigned int i = 0; i < buffer->planes().size(); ++i) {
 		const FrameBuffer::Plane &plane = buffer->planes()[i];
@@ -96,6 +125,4 @@ int BufferWriter::write(FrameBuffer *buffer, const std::string &streamName)
 	}
 
 	close(fd);
-
-	return ret;
 }
diff --git a/src/cam/buffer_writer.h b/src/cam/buffer_writer.h
index 7626de42d369..32bb6ed5e045 100644
--- a/src/cam/buffer_writer.h
+++ b/src/cam/buffer_writer.h
@@ -10,20 +10,27 @@
 #include <map>
 #include <string>
 
-#include <libcamera/framebuffer.h>
+#include <libcamera/stream.h>
 
-class BufferWriter
+#include "frame_sink.h"
+
+class BufferWriter : public FrameSink
 {
 public:
 	BufferWriter(const std::string &pattern = "");
 	~BufferWriter();
 
-	void mapBuffer(libcamera::FrameBuffer *buffer);
+	int configure(const libcamera::CameraConfiguration &config) override;
 
-	int write(libcamera::FrameBuffer *buffer,
-		  const std::string &streamName);
+	void mapBuffer(libcamera::FrameBuffer *buffer) override;
+
+	bool processRequest(libcamera::Request *request) override;
 
 private:
+	void writeBuffer(const libcamera::Stream *stream,
+			 libcamera::FrameBuffer *buffer);
+
+	std::map<const libcamera::Stream *, std::string> streamNames_;
 	std::string pattern_;
 	std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
 };
diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp
index 0d49fc1ade83..f91b5234a082 100644
--- a/src/cam/camera_session.cpp
+++ b/src/cam/camera_session.cpp
@@ -13,6 +13,7 @@
 #include <libcamera/control_ids.h>
 #include <libcamera/property_ids.h>
 
+#include "buffer_writer.h"
 #include "camera_session.h"
 #include "event_loop.h"
 #include "main.h"
@@ -162,9 +163,20 @@ int CameraSession::start()
 
 	if (options_.isSet(OptFile)) {
 		if (!options_[OptFile].toString().empty())
-			writer_ = std::make_unique<BufferWriter>(options_[OptFile]);
+			sink_ = std::make_unique<BufferWriter>(options_[OptFile]);
 		else
-			writer_ = std::make_unique<BufferWriter>();
+			sink_ = std::make_unique<BufferWriter>();
+	}
+
+	if (sink_) {
+		ret = sink_->configure(*config_);
+		if (ret < 0) {
+			std::cout << "Failed to configure frame sink"
+				  << std::endl;
+			return ret;
+		}
+
+		sink_->requestProcessed.connect(this, &CameraSession::sinkRelease);
 	}
 
 	allocator_ = std::make_unique<FrameBufferAllocator>(camera_);
@@ -178,7 +190,13 @@ void CameraSession::stop()
 	if (ret)
 		std::cout << "Failed to stop capture" << std::endl;
 
-	writer_.reset();
+	if (sink_) {
+		ret = sink_->stop();
+		if (ret)
+			std::cout << "Failed to stop frame sink" << std::endl;
+	}
+
+	sink_.reset();
 
 	requests_.clear();
 
@@ -227,16 +245,26 @@ int CameraSession::startCapture()
 				return ret;
 			}
 
-			if (writer_)
-				writer_->mapBuffer(buffer.get());
+			if (sink_)
+				sink_->mapBuffer(buffer.get());
 		}
 
 		requests_.push_back(std::move(request));
 	}
 
+	if (sink_) {
+		ret = sink_->start();
+		if (ret) {
+			std::cout << "Failed to start frame sink" << std::endl;
+			return ret;
+		}
+	}
+
 	ret = camera_->start();
 	if (ret) {
 		std::cout << "Failed to start capture" << std::endl;
+		if (sink_)
+			sink_->stop();
 		return ret;
 	}
 
@@ -245,6 +273,8 @@ int CameraSession::startCapture()
 		if (ret < 0) {
 			std::cerr << "Can't queue request" << std::endl;
 			camera_->stop();
+			if (sink_)
+				sink_->stop();
 			return ret;
 		}
 	}
@@ -296,6 +326,8 @@ void CameraSession::processRequest(Request *request)
 	fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0;
 	last_ = ts;
 
+	bool requeue = true;
+
 	std::stringstream info;
 	info << ts / 1000000000 << "."
 	     << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000
@@ -304,11 +336,10 @@ void CameraSession::processRequest(Request *request)
 	for (auto it = buffers.begin(); it != buffers.end(); ++it) {
 		const Stream *stream = it->first;
 		FrameBuffer *buffer = it->second;
-		const std::string &name = streamName_[stream];
 
 		const FrameMetadata &metadata = buffer->metadata();
 
-		info << " " << name
+		info << " " << streamName_[stream]
 		     << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence
 		     << " bytesused: ";
 
@@ -318,9 +349,11 @@ void CameraSession::processRequest(Request *request)
 			if (++nplane < metadata.planes.size())
 				info << "/";
 		}
+	}
 
-		if (writer_)
-			writer_->write(buffer, name);
+	if (sink_) {
+		if (!sink_->processRequest(request))
+			requeue = false;
 	}
 
 	std::cout << info.str() << std::endl;
@@ -340,6 +373,19 @@ void CameraSession::processRequest(Request *request)
 		return;
 	}
 
+	/*
+	 * If the frame sink holds on the request, we'll requeue it later in the
+	 * complete handler.
+	 */
+	if (!requeue)
+		return;
+
+	request->reuse(Request::ReuseBuffers);
+	camera_->queueRequest(request);
+}
+
+void CameraSession::sinkRelease(Request *request)
+{
 	request->reuse(Request::ReuseBuffers);
 	queueRequest(request);
 }
diff --git a/src/cam/camera_session.h b/src/cam/camera_session.h
index b0f50e7f998e..2ccc71977a99 100644
--- a/src/cam/camera_session.h
+++ b/src/cam/camera_session.h
@@ -21,9 +21,10 @@
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
-#include "buffer_writer.h"
 #include "options.h"
 
+class FrameSink;
+
 class CameraSession
 {
 public:
@@ -53,13 +54,14 @@ private:
 	int queueRequest(libcamera::Request *request);
 	void requestComplete(libcamera::Request *request);
 	void processRequest(libcamera::Request *request);
+	void sinkRelease(libcamera::Request *request);
 
 	const OptionsParser::Options &options_;
 	std::shared_ptr<libcamera::Camera> camera_;
 	std::unique_ptr<libcamera::CameraConfiguration> config_;
 
 	std::map<const libcamera::Stream *, std::string> streamName_;
-	std::unique_ptr<BufferWriter> writer_;
+	std::unique_ptr<FrameSink> sink_;
 	unsigned int cameraIndex_;
 
 	uint64_t last_;
-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list