[libcamera-devel] [PATCH 05/21] qcam: main_window: Move capture event processing to main thread

Laurent Pinchart laurent.pinchart at ideasonboard.com
Mon Mar 23 15:21:49 CET 2020


To avoid blocking the camera manager for a long amount of time, move
capture event processing to the main thread. Captured buffers are added
to a queue and an event is posted to the main window to signal
availability of a buffer.

Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
 src/qcam/main_window.cpp | 54 +++++++++++++++++++++++++++++++++++++++-
 src/qcam/main_window.h   |  8 ++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 354a53367d0f..afd8b9c413f5 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -19,6 +19,7 @@
 #include <QImage>
 #include <QImageWriter>
 #include <QInputDialog>
+#include <QMutexLocker>
 #include <QStandardPaths>
 #include <QTimer>
 #include <QToolBar>
@@ -31,6 +32,21 @@
 
 using namespace libcamera;
 
+class CaptureEvent : public QEvent
+{
+public:
+	CaptureEvent()
+		: QEvent(type())
+	{
+	}
+
+	static Type type()
+	{
+		static int type = QEvent::registerEventType();
+		return static_cast<Type>(type);
+	}
+};
+
 MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
 	: options_(options), cm_(cm), allocator_(nullptr), isCapturing_(false)
 {
@@ -63,6 +79,16 @@ MainWindow::~MainWindow()
 	}
 }
 
+bool MainWindow::event(QEvent *e)
+{
+	if (e->type() == CaptureEvent::type()) {
+		processCapture();
+		return true;
+	}
+
+	return QMainWindow::event(e);
+}
+
 int MainWindow::createToolbars()
 {
 	QAction *action;
@@ -343,6 +369,13 @@ void MainWindow::stopCapture()
 
 	config_.reset();
 
+	/*
+	 * A CaptureEvent may have been posted before we stopped the camera,
+	 * but not processed yet. Clear the queue of done buffers to avoid
+	 * racing with the event handler.
+	 */
+	doneQueue_.clear();
+
 	titleTimer_.stop();
 	setWindowTitle(title_);
 }
@@ -371,10 +404,29 @@ void MainWindow::requestComplete(Request *request)
 		return;
 
 	const std::map<Stream *, FrameBuffer *> &buffers = request->buffers();
+	FrameBuffer *buffer = buffers.begin()->second;
+
+	{
+		QMutexLocker locker(&mutex_);
+		doneQueue_.enqueue(buffer);
+	}
+
+	QCoreApplication::postEvent(this, new CaptureEvent);
+}
+
+void MainWindow::processCapture()
+{
+	FrameBuffer *buffer;
+	{
+		QMutexLocker locker(&mutex_);
+		if (doneQueue_.isEmpty())
+			return;
+
+		buffer = doneQueue_.dequeue();
+	}
 
 	framesCaptured_++;
 
-	FrameBuffer *buffer = buffers.begin()->second;
 	const FrameMetadata &metadata = buffer->metadata();
 
 	double fps = metadata.timestamp - lastBufferTime_;
diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
index 720a3393e3dc..c623120d5894 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -11,7 +11,9 @@
 
 #include <QElapsedTimer>
 #include <QMainWindow>
+#include <QMutex>
 #include <QObject>
+#include <QQueue>
 #include <QTimer>
 
 #include <libcamera/buffer.h>
@@ -40,6 +42,8 @@ public:
 	MainWindow(CameraManager *cm, const OptionsParser::Options &options);
 	~MainWindow();
 
+	bool event(QEvent *e) override;
+
 private Q_SLOTS:
 	void quit();
 	void updateTitle();
@@ -57,6 +61,7 @@ private:
 	int openCamera();
 
 	void requestComplete(Request *request);
+	void processCapture();
 	int display(FrameBuffer *buffer);
 	void queueRequest(FrameBuffer *buffer);
 
@@ -78,6 +83,9 @@ private:
 	uint32_t previousFrames_;
 	uint32_t framesCaptured_;
 
+	QMutex mutex_;
+	QQueue<FrameBuffer *> doneQueue_;
+
 	QToolBar *toolbar_;
 	ViewFinder *viewfinder_;
 	std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
-- 
Regards,

Laurent Pinchart



More information about the libcamera-devel mailing list