summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-22 17:17:42 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2020-03-24 10:33:44 +0200
commit77ea51820acccfcd3aebe6aa27ad26af21e82a7a (patch)
tree717d9b20c97cac88311de65db348659b1fbeb295
parent8e7d1bbe9b6d98a443da4982fe088321e6d4a583 (diff)
qcam: main_window: Move capture event processing to main thread
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@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
-rw-r--r--src/qcam/main_window.cpp55
-rw-r--r--src/qcam/main_window.h8
2 files changed, 62 insertions, 1 deletions
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 354a5336..805690d5 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,30 @@ 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 720a3393..c623120d 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_;