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>
This commit is contained in:
Laurent Pinchart 2020-03-22 17:17:42 +02:00
parent 8e7d1bbe9b
commit 77ea51820a
2 changed files with 62 additions and 1 deletions

View file

@ -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_;

View file

@ -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_;