[libcamera-devel] [PATCH 05/21] qcam: main_window: Move capture event processing to main thread
Kieran Bingham
kieran.bingham at ideasonboard.com
Mon Mar 23 18:31:31 CET 2020
Hi Laurent,
On 23/03/2020 16:52, Laurent Pinchart wrote:
> Hi Kieran,
>
> On Mon, Mar 23, 2020 at 02:59:08PM +0000, Kieran Bingham wrote:
>> On 23/03/2020 14:21, Laurent Pinchart wrote:
>>> 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.
>>
>> Is the 'queue' necessary?
>> Could the buffers not be passed through the event?
>
> I would then have no way in processCapture() to ignore the event after
> stopping the camera. I could check isCapturing_, but at least in theory,
> we could stop and restart and have the pending event generated before
> stopped delivered after the restart. I think a queue is cleaner as it
> gives us full control.
>
Ok, with minors resolved,
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
>>> 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();
>>> +
>>
>> Do we not need to lock mutex_ here?
>
> No, because at this point there can't be any call to
> MainWindow::requestComplete(), as the camera is stopped. This function,
> as well as MainWindow::processCapture(), run in the same thread, so they
> can't run concurrently.
>
>>> 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;
>>
>> This scoping is to ensure the locker unlocks after the dequeue right?
>
> Correct.
>
>> Perhaps a new line between the FrameBuffer declaration and the start of
>> the scope? It looks a bit like some sort of badly defined inline
>> function otherwise :-S
>
> OK.
>
>>> + {
>>> + 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
--
Kieran
More information about the libcamera-devel
mailing list