From 94d828d880492617c936434a5ca93ee83366a31b Mon Sep 17 00:00:00 2001
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Date: Mon, 5 Jul 2021 06:40:19 +0300
Subject: cam: Rename Capture to CameraSession

Rename the Capture class to CameraSession, to prepare for multi-camera
support that will gather more camera-related operations than capture in
that class.

While at it, remove an unneeded blank line.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 src/cam/camera_session.cpp | 240 ++++++++++++++++++++++++++++++++++++++++++++
 src/cam/camera_session.h   |  55 +++++++++++
 src/cam/capture.cpp        | 241 ---------------------------------------------
 src/cam/capture.h          |  55 -----------
 src/cam/main.cpp           |   6 +-
 src/cam/meson.build        |   2 +-
 6 files changed, 299 insertions(+), 300 deletions(-)
 create mode 100644 src/cam/camera_session.cpp
 create mode 100644 src/cam/camera_session.h
 delete mode 100644 src/cam/capture.cpp
 delete mode 100644 src/cam/capture.h

(limited to 'src/cam')

diff --git a/src/cam/camera_session.cpp b/src/cam/camera_session.cpp
new file mode 100644
index 00000000..439dcdb2
--- /dev/null
+++ b/src/cam/camera_session.cpp
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * camera_session.cpp - Camera capture session
+ */
+
+#include <iomanip>
+#include <iostream>
+#include <limits.h>
+#include <sstream>
+
+#include <libcamera/control_ids.h>
+
+#include "camera_session.h"
+#include "main.h"
+
+using namespace libcamera;
+
+CameraSession::CameraSession(std::shared_ptr<Camera> camera,
+			     CameraConfiguration *config, EventLoop *loop)
+	: camera_(camera), config_(config), writer_(nullptr), last_(0), loop_(loop),
+	  queueCount_(0), captureCount_(0), captureLimit_(0),
+	  printMetadata_(false)
+{
+}
+
+int CameraSession::run(const OptionsParser::Options &options)
+{
+	int ret;
+
+	queueCount_ = 0;
+	captureCount_ = 0;
+	captureLimit_ = options[OptCapture].toInteger();
+	printMetadata_ = options.isSet(OptMetadata);
+
+	if (!camera_) {
+		std::cout << "Can't capture without a camera" << std::endl;
+		return -ENODEV;
+	}
+
+	ret = camera_->configure(config_);
+	if (ret < 0) {
+		std::cout << "Failed to configure camera" << std::endl;
+		return ret;
+	}
+
+	streamName_.clear();
+	for (unsigned int index = 0; index < config_->size(); ++index) {
+		StreamConfiguration &cfg = config_->at(index);
+		streamName_[cfg.stream()] = "stream" + std::to_string(index);
+	}
+
+	camera_->requestCompleted.connect(this, &CameraSession::requestComplete);
+
+	if (options.isSet(OptFile)) {
+		if (!options[OptFile].toString().empty())
+			writer_ = new BufferWriter(options[OptFile]);
+		else
+			writer_ = new BufferWriter();
+	}
+
+	FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_);
+
+	ret = capture(allocator);
+
+	if (options.isSet(OptFile)) {
+		delete writer_;
+		writer_ = nullptr;
+	}
+
+	requests_.clear();
+
+	delete allocator;
+
+	return ret;
+}
+
+int CameraSession::capture(FrameBufferAllocator *allocator)
+{
+	int ret;
+
+	/* Identify the stream with the least number of buffers. */
+	unsigned int nbuffers = UINT_MAX;
+	for (StreamConfiguration &cfg : *config_) {
+		ret = allocator->allocate(cfg.stream());
+		if (ret < 0) {
+			std::cerr << "Can't allocate buffers" << std::endl;
+			return -ENOMEM;
+		}
+
+		unsigned int allocated = allocator->buffers(cfg.stream()).size();
+		nbuffers = std::min(nbuffers, allocated);
+	}
+
+	/*
+	 * TODO: make cam tool smarter to support still capture by for
+	 * example pushing a button. For now run all streams all the time.
+	 */
+
+	for (unsigned int i = 0; i < nbuffers; i++) {
+		std::unique_ptr<Request> request = camera_->createRequest();
+		if (!request) {
+			std::cerr << "Can't create request" << std::endl;
+			return -ENOMEM;
+		}
+
+		for (StreamConfiguration &cfg : *config_) {
+			Stream *stream = cfg.stream();
+			const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
+				allocator->buffers(stream);
+			const std::unique_ptr<FrameBuffer> &buffer = buffers[i];
+
+			ret = request->addBuffer(stream, buffer.get());
+			if (ret < 0) {
+				std::cerr << "Can't set buffer for request"
+					  << std::endl;
+				return ret;
+			}
+
+			if (writer_)
+				writer_->mapBuffer(buffer.get());
+		}
+
+		requests_.push_back(std::move(request));
+	}
+
+	ret = camera_->start();
+	if (ret) {
+		std::cout << "Failed to start capture" << std::endl;
+		return ret;
+	}
+
+	for (std::unique_ptr<Request> &request : requests_) {
+		ret = queueRequest(request.get());
+		if (ret < 0) {
+			std::cerr << "Can't queue request" << std::endl;
+			camera_->stop();
+			return ret;
+		}
+	}
+
+	if (captureLimit_)
+		std::cout << "Capture " << captureLimit_ << " frames" << std::endl;
+	else
+		std::cout << "Capture until user interrupts by SIGINT" << std::endl;
+
+	ret = loop_->exec();
+	if (ret)
+		std::cout << "Failed to run capture loop" << std::endl;
+
+	ret = camera_->stop();
+	if (ret)
+		std::cout << "Failed to stop capture" << std::endl;
+
+	return ret;
+}
+
+int CameraSession::queueRequest(Request *request)
+{
+	if (captureLimit_ && queueCount_ >= captureLimit_)
+		return 0;
+
+	queueCount_++;
+
+	return camera_->queueRequest(request);
+}
+
+void CameraSession::requestComplete(Request *request)
+{
+	if (request->status() == Request::RequestCancelled)
+		return;
+
+	/*
+	 * Defer processing of the completed request to the event loop, to avoid
+	 * blocking the camera manager thread.
+	 */
+	loop_->callLater([=]() { processRequest(request); });
+}
+
+void CameraSession::processRequest(Request *request)
+{
+	const Request::BufferMap &buffers = request->buffers();
+
+	/*
+	 * Compute the frame rate. The timestamp is arbitrarily retrieved from
+	 * the first buffer, as all buffers should have matching timestamps.
+	 */
+	uint64_t ts = buffers.begin()->second->metadata().timestamp;
+	double fps = ts - last_;
+	fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0;
+	last_ = ts;
+
+	std::stringstream info;
+	info << ts / 1000000000 << "."
+	     << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000
+	     << " (" << std::fixed << std::setprecision(2) << fps << " fps)";
+
+	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
+		     << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence
+		     << " bytesused: ";
+
+		unsigned int nplane = 0;
+		for (const FrameMetadata::Plane &plane : metadata.planes) {
+			info << plane.bytesused;
+			if (++nplane < metadata.planes.size())
+				info << "/";
+		}
+
+		if (writer_)
+			writer_->write(buffer, name);
+	}
+
+	std::cout << info.str() << std::endl;
+
+	if (printMetadata_) {
+		const ControlList &requestMetadata = request->metadata();
+		for (const auto &ctrl : requestMetadata) {
+			const ControlId *id = controls::controls.at(ctrl.first);
+			std::cout << "\t" << id->name() << " = "
+				  << ctrl.second.toString() << std::endl;
+		}
+	}
+
+	captureCount_++;
+	if (captureLimit_ && captureCount_ >= captureLimit_) {
+		loop_->exit(0);
+		return;
+	}
+
+	request->reuse(Request::ReuseBuffers);
+	queueRequest(request);
+}
diff --git a/src/cam/camera_session.h b/src/cam/camera_session.h
new file mode 100644
index 00000000..ef8a11c3
--- /dev/null
+++ b/src/cam/camera_session.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2019, Google Inc.
+ *
+ * camera_session.h - Camera capture session
+ */
+#ifndef __CAM_CAMERA_SESSION_H__
+#define __CAM_CAMERA_SESSION_H__
+
+#include <memory>
+#include <stdint.h>
+#include <vector>
+
+#include <libcamera/camera.h>
+#include <libcamera/framebuffer.h>
+#include <libcamera/framebuffer_allocator.h>
+#include <libcamera/request.h>
+#include <libcamera/stream.h>
+
+#include "buffer_writer.h"
+#include "event_loop.h"
+#include "options.h"
+
+class CameraSession
+{
+public:
+	CameraSession(std::shared_ptr<libcamera::Camera> camera,
+		      libcamera::CameraConfiguration *config,
+		      EventLoop *loop);
+
+	int run(const OptionsParser::Options &options);
+private:
+	int capture(libcamera::FrameBufferAllocator *allocator);
+
+	int queueRequest(libcamera::Request *request);
+	void requestComplete(libcamera::Request *request);
+	void processRequest(libcamera::Request *request);
+
+	std::shared_ptr<libcamera::Camera> camera_;
+	libcamera::CameraConfiguration *config_;
+
+	std::map<const libcamera::Stream *, std::string> streamName_;
+	BufferWriter *writer_;
+	uint64_t last_;
+
+	EventLoop *loop_;
+	unsigned int queueCount_;
+	unsigned int captureCount_;
+	unsigned int captureLimit_;
+	bool printMetadata_;
+
+	std::vector<std::unique_ptr<libcamera::Request>> requests_;
+};
+
+#endif /* __CAM_CAMERA_SESSION_H__ */
diff --git a/src/cam/capture.cpp b/src/cam/capture.cpp
deleted file mode 100644
index 3c3e3a53..00000000
--- a/src/cam/capture.cpp
+++ /dev/null
@@ -1,241 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * capture.cpp - Cam capture
- */
-
-#include <iomanip>
-#include <iostream>
-#include <limits.h>
-#include <sstream>
-
-#include <libcamera/control_ids.h>
-
-#include "capture.h"
-#include "main.h"
-
-using namespace libcamera;
-
-Capture::Capture(std::shared_ptr<Camera> camera, CameraConfiguration *config,
-		 EventLoop *loop)
-	: camera_(camera), config_(config), writer_(nullptr), last_(0), loop_(loop),
-	  queueCount_(0), captureCount_(0), captureLimit_(0),
-	  printMetadata_(false)
-{
-}
-
-int Capture::run(const OptionsParser::Options &options)
-{
-	int ret;
-
-	queueCount_ = 0;
-	captureCount_ = 0;
-	captureLimit_ = options[OptCapture].toInteger();
-	printMetadata_ = options.isSet(OptMetadata);
-
-	if (!camera_) {
-		std::cout << "Can't capture without a camera" << std::endl;
-		return -ENODEV;
-	}
-
-	ret = camera_->configure(config_);
-	if (ret < 0) {
-		std::cout << "Failed to configure camera" << std::endl;
-		return ret;
-	}
-
-	streamName_.clear();
-	for (unsigned int index = 0; index < config_->size(); ++index) {
-		StreamConfiguration &cfg = config_->at(index);
-		streamName_[cfg.stream()] = "stream" + std::to_string(index);
-	}
-
-	camera_->requestCompleted.connect(this, &Capture::requestComplete);
-
-	if (options.isSet(OptFile)) {
-		if (!options[OptFile].toString().empty())
-			writer_ = new BufferWriter(options[OptFile]);
-		else
-			writer_ = new BufferWriter();
-	}
-
-
-	FrameBufferAllocator *allocator = new FrameBufferAllocator(camera_);
-
-	ret = capture(allocator);
-
-	if (options.isSet(OptFile)) {
-		delete writer_;
-		writer_ = nullptr;
-	}
-
-	requests_.clear();
-
-	delete allocator;
-
-	return ret;
-}
-
-int Capture::capture(FrameBufferAllocator *allocator)
-{
-	int ret;
-
-	/* Identify the stream with the least number of buffers. */
-	unsigned int nbuffers = UINT_MAX;
-	for (StreamConfiguration &cfg : *config_) {
-		ret = allocator->allocate(cfg.stream());
-		if (ret < 0) {
-			std::cerr << "Can't allocate buffers" << std::endl;
-			return -ENOMEM;
-		}
-
-		unsigned int allocated = allocator->buffers(cfg.stream()).size();
-		nbuffers = std::min(nbuffers, allocated);
-	}
-
-	/*
-	 * TODO: make cam tool smarter to support still capture by for
-	 * example pushing a button. For now run all streams all the time.
-	 */
-
-	for (unsigned int i = 0; i < nbuffers; i++) {
-		std::unique_ptr<Request> request = camera_->createRequest();
-		if (!request) {
-			std::cerr << "Can't create request" << std::endl;
-			return -ENOMEM;
-		}
-
-		for (StreamConfiguration &cfg : *config_) {
-			Stream *stream = cfg.stream();
-			const std::vector<std::unique_ptr<FrameBuffer>> &buffers =
-				allocator->buffers(stream);
-			const std::unique_ptr<FrameBuffer> &buffer = buffers[i];
-
-			ret = request->addBuffer(stream, buffer.get());
-			if (ret < 0) {
-				std::cerr << "Can't set buffer for request"
-					  << std::endl;
-				return ret;
-			}
-
-			if (writer_)
-				writer_->mapBuffer(buffer.get());
-		}
-
-		requests_.push_back(std::move(request));
-	}
-
-	ret = camera_->start();
-	if (ret) {
-		std::cout << "Failed to start capture" << std::endl;
-		return ret;
-	}
-
-	for (std::unique_ptr<Request> &request : requests_) {
-		ret = queueRequest(request.get());
-		if (ret < 0) {
-			std::cerr << "Can't queue request" << std::endl;
-			camera_->stop();
-			return ret;
-		}
-	}
-
-	if (captureLimit_)
-		std::cout << "Capture " << captureLimit_ << " frames" << std::endl;
-	else
-		std::cout << "Capture until user interrupts by SIGINT" << std::endl;
-
-	ret = loop_->exec();
-	if (ret)
-		std::cout << "Failed to run capture loop" << std::endl;
-
-	ret = camera_->stop();
-	if (ret)
-		std::cout << "Failed to stop capture" << std::endl;
-
-	return ret;
-}
-
-int Capture::queueRequest(Request *request)
-{
-	if (captureLimit_ && queueCount_ >= captureLimit_)
-		return 0;
-
-	queueCount_++;
-
-	return camera_->queueRequest(request);
-}
-
-void Capture::requestComplete(Request *request)
-{
-	if (request->status() == Request::RequestCancelled)
-		return;
-
-	/*
-	 * Defer processing of the completed request to the event loop, to avoid
-	 * blocking the camera manager thread.
-	 */
-	loop_->callLater([=]() { processRequest(request); });
-}
-
-void Capture::processRequest(Request *request)
-{
-	const Request::BufferMap &buffers = request->buffers();
-
-	/*
-	 * Compute the frame rate. The timestamp is arbitrarily retrieved from
-	 * the first buffer, as all buffers should have matching timestamps.
-	 */
-	uint64_t ts = buffers.begin()->second->metadata().timestamp;
-	double fps = ts - last_;
-	fps = last_ != 0 && fps ? 1000000000.0 / fps : 0.0;
-	last_ = ts;
-
-	std::stringstream info;
-	info << ts / 1000000000 << "."
-	     << std::setw(6) << std::setfill('0') << ts / 1000 % 1000000
-	     << " (" << std::fixed << std::setprecision(2) << fps << " fps)";
-
-	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
-		     << " seq: " << std::setw(6) << std::setfill('0') << metadata.sequence
-		     << " bytesused: ";
-
-		unsigned int nplane = 0;
-		for (const FrameMetadata::Plane &plane : metadata.planes) {
-			info << plane.bytesused;
-			if (++nplane < metadata.planes.size())
-				info << "/";
-		}
-
-		if (writer_)
-			writer_->write(buffer, name);
-	}
-
-	std::cout << info.str() << std::endl;
-
-	if (printMetadata_) {
-		const ControlList &requestMetadata = request->metadata();
-		for (const auto &ctrl : requestMetadata) {
-			const ControlId *id = controls::controls.at(ctrl.first);
-			std::cout << "\t" << id->name() << " = "
-				  << ctrl.second.toString() << std::endl;
-		}
-	}
-
-	captureCount_++;
-	if (captureLimit_ && captureCount_ >= captureLimit_) {
-		loop_->exit(0);
-		return;
-	}
-
-	request->reuse(Request::ReuseBuffers);
-	queueRequest(request);
-}
diff --git a/src/cam/capture.h b/src/cam/capture.h
deleted file mode 100644
index de478c98..00000000
--- a/src/cam/capture.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Copyright (C) 2019, Google Inc.
- *
- * capture.h - Cam capture
- */
-#ifndef __CAM_CAPTURE_H__
-#define __CAM_CAPTURE_H__
-
-#include <memory>
-#include <stdint.h>
-#include <vector>
-
-#include <libcamera/camera.h>
-#include <libcamera/framebuffer.h>
-#include <libcamera/framebuffer_allocator.h>
-#include <libcamera/request.h>
-#include <libcamera/stream.h>
-
-#include "buffer_writer.h"
-#include "event_loop.h"
-#include "options.h"
-
-class Capture
-{
-public:
-	Capture(std::shared_ptr<libcamera::Camera> camera,
-		libcamera::CameraConfiguration *config,
-		EventLoop *loop);
-
-	int run(const OptionsParser::Options &options);
-private:
-	int capture(libcamera::FrameBufferAllocator *allocator);
-
-	int queueRequest(libcamera::Request *request);
-	void requestComplete(libcamera::Request *request);
-	void processRequest(libcamera::Request *request);
-
-	std::shared_ptr<libcamera::Camera> camera_;
-	libcamera::CameraConfiguration *config_;
-
-	std::map<const libcamera::Stream *, std::string> streamName_;
-	BufferWriter *writer_;
-	uint64_t last_;
-
-	EventLoop *loop_;
-	unsigned int queueCount_;
-	unsigned int captureCount_;
-	unsigned int captureLimit_;
-	bool printMetadata_;
-
-	std::vector<std::unique_ptr<libcamera::Request>> requests_;
-};
-
-#endif /* __CAM_CAPTURE_H__ */
diff --git a/src/cam/main.cpp b/src/cam/main.cpp
index 70e9f62c..f71b65a2 100644
--- a/src/cam/main.cpp
+++ b/src/cam/main.cpp
@@ -13,7 +13,7 @@
 #include <libcamera/libcamera.h>
 #include <libcamera/property_ids.h>
 
-#include "capture.h"
+#include "camera_session.h"
 #include "event_loop.h"
 #include "main.h"
 #include "options.h"
@@ -363,8 +363,8 @@ int CamApp::run()
 	}
 
 	if (options_.isSet(OptCapture)) {
-		Capture capture(camera_, config_.get(), &loop_);
-		return capture.run(options_);
+		CameraSession session(camera_, config_.get(), &loop_);
+		return session.run(options_);
 	}
 
 	if (options_.isSet(OptMonitor)) {
diff --git a/src/cam/meson.build b/src/cam/meson.build
index 6234ed0a..1e90ee52 100644
--- a/src/cam/meson.build
+++ b/src/cam/meson.build
@@ -11,7 +11,7 @@ cam_enabled = true
 
 cam_sources = files([
     'buffer_writer.cpp',
-    'capture.cpp',
+    'camera_session.cpp',
     'event_loop.cpp',
     'main.cpp',
     'options.cpp',
-- 
cgit v1.2.1