From patchwork Mon Mar 23 17:35:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3267 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C904A60417 for ; Mon, 23 Mar 2020 18:36:16 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 68B04A31 for ; Mon, 23 Mar 2020 18:36:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984976; bh=TnPSnCbjQeF7XKN3+DusUtKMbfyZQsZ9rRHhgh+WbUg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=qt90/3T5hs/8Qk4SeFmJ/Vy4ilFE8ls4JmQxxxMlsRXCMYMzDmfqCw5pdQqPiAs90 SMF5eMSFu5ZsgqDqQpSyFE3IEpXb6NEZU5b16Nb7scVWPppj+cH9vyHlExtMKoV7fm yrEuePwC7nsozpiMyhUJo6yVwmFetnAN/isaIFus= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:39 +0200 Message-Id: <20200323173559.21109-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 01/21] qcam: Remove custom event dispatcher X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:17 -0000 The qcam application installs a custom event dispatcher based on the Qt event loop. As the camera manager now creates an internal thread, it doesn't use that event dispatcher of the application thread at all. Furthermore, the custom event dispatcher is buggy, as it doesn't dispatch messages posted to the main thread's event loop. This isn't an issue as no messages are posted there in the first place, but would cause incorrect behaviour if we were to use that feature (for instance to deliver signals from the camera manager thread to the application thread). Fixing the event dispatcher requires a change in the libcamera public API, as there's currently no way to dispatch messages using the public API (Thread::dispatchMessages() is not exposed). This isn't worth it at the moment, so just remove the custom event dispatcher. If qcam later needs the libcamera request and buffer completion signals to be delivered in the application thread, it will need to handle that internally, using Qt's cross-thread signal delivery. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main.cpp | 3 - src/qcam/meson.build | 1 - src/qcam/qt_event_dispatcher.cpp | 152 ------------------------------- src/qcam/qt_event_dispatcher.h | 62 ------------- 4 files changed, 218 deletions(-) delete mode 100644 src/qcam/qt_event_dispatcher.cpp delete mode 100644 src/qcam/qt_event_dispatcher.h diff --git a/src/qcam/main.cpp b/src/qcam/main.cpp index a7ff5c52663b..297453914ae9 100644 --- a/src/qcam/main.cpp +++ b/src/qcam/main.cpp @@ -15,7 +15,6 @@ #include "main_window.h" #include "../cam/options.h" -#include "qt_event_dispatcher.h" void signalHandler(int signal) { @@ -62,9 +61,7 @@ int main(int argc, char **argv) sa.sa_handler = &signalHandler; sigaction(SIGINT, &sa, nullptr); - std::unique_ptr dispatcher(new QtEventDispatcher()); CameraManager *cm = new CameraManager(); - cm->setEventDispatcher(std::move(dispatcher)); ret = cm->start(); if (ret) { diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 5150631b55c8..214bfb12aabb 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -3,7 +3,6 @@ qcam_sources = files([ 'main.cpp', 'main_window.cpp', '../cam/options.cpp', - 'qt_event_dispatcher.cpp', 'viewfinder.cpp', ]) diff --git a/src/qcam/qt_event_dispatcher.cpp b/src/qcam/qt_event_dispatcher.cpp deleted file mode 100644 index 2780c9123ac3..000000000000 --- a/src/qcam/qt_event_dispatcher.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * qt_event_dispatcher.cpp - qcam - Qt-based event dispatcher - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "qt_event_dispatcher.h" - -using namespace libcamera; - -QtEventDispatcher::QtEventDispatcher() -{ -} - -QtEventDispatcher::~QtEventDispatcher() -{ - for (auto &it : notifiers_) { - NotifierSet &set = it.second; - delete set.read.qnotifier; - delete set.write.qnotifier; - delete set.exception.qnotifier; - } -} - -void QtEventDispatcher::registerEventNotifier(EventNotifier *notifier) -{ - NotifierSet &set = notifiers_[notifier->fd()]; - QSocketNotifier::Type qtype; - void (QtEventDispatcher::*method)(int); - NotifierPair *pair; - - switch (notifier->type()) { - case EventNotifier::Read: - default: - qtype = QSocketNotifier::Read; - method = &QtEventDispatcher::readNotifierActivated; - pair = &set.read; - break; - - case EventNotifier::Write: - qtype = QSocketNotifier::Write; - method = &QtEventDispatcher::writeNotifierActivated; - pair = &set.write; - break; - - case EventNotifier::Exception: - qtype = QSocketNotifier::Exception; - method = &QtEventDispatcher::exceptionNotifierActivated; - pair = &set.exception; - break; - } - - QSocketNotifier *qnotifier = new QSocketNotifier(notifier->fd(), qtype); - connect(qnotifier, &QSocketNotifier::activated, this, method); - pair->notifier = notifier; - pair->qnotifier = qnotifier; -} - -void QtEventDispatcher::unregisterEventNotifier(EventNotifier *notifier) -{ - NotifierSet &set = notifiers_[notifier->fd()]; - NotifierPair *pair; - - switch (notifier->type()) { - case EventNotifier::Read: - default: - pair = &set.read; - break; - - case EventNotifier::Write: - pair = &set.write; - break; - - case EventNotifier::Exception: - pair = &set.exception; - break; - } - - delete pair->qnotifier; - pair->qnotifier = nullptr; - pair->notifier = nullptr; -} - -void QtEventDispatcher::readNotifierActivated(int socket) -{ - EventNotifier *notifier = notifiers_[socket].read.notifier; - notifier->activated.emit(notifier); -} - -void QtEventDispatcher::writeNotifierActivated(int socket) -{ - EventNotifier *notifier = notifiers_[socket].write.notifier; - notifier->activated.emit(notifier); -} - -void QtEventDispatcher::exceptionNotifierActivated(int socket) -{ - EventNotifier *notifier = notifiers_[socket].exception.notifier; - notifier->activated.emit(notifier); -} - -void QtEventDispatcher::registerTimer(Timer *timer) -{ - std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); - std::chrono::steady_clock::duration duration = timer->deadline() - now; - std::chrono::milliseconds msec = - std::chrono::duration_cast(duration); - int timerId = startTimer(msec.count()); - timers_[timerId] = timer; - timerIds_[timer] = timerId; -} - -void QtEventDispatcher::unregisterTimer(Timer *timer) -{ - auto it = timerIds_.find(timer); - if (it == timerIds_.end()) - return; - - timers_.erase(it->second); - killTimer(it->second); - timerIds_.erase(it); -} - -void QtEventDispatcher::timerEvent(QTimerEvent *event) -{ - Timer *timer = timers_[event->timerId()]; - timer->stop(); - timer->timeout.emit(timer); -} - -void QtEventDispatcher::processEvents() -{ - std::cout << "QtEventDispatcher::processEvents() should not be called" - << std::endl; -} - -void QtEventDispatcher::interrupt() -{ - QCoreApplication::eventDispatcher()->interrupt(); -} diff --git a/src/qcam/qt_event_dispatcher.h b/src/qcam/qt_event_dispatcher.h deleted file mode 100644 index b0f123e52d06..000000000000 --- a/src/qcam/qt_event_dispatcher.h +++ /dev/null @@ -1,62 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2019, Google Inc. - * - * qt_event_dispatcher.h - qcam - Qt-based event dispatcher - */ -#ifndef __QCAM_QT_EVENT_DISPATCHER_H__ -#define __QCAM_QT_EVENT_DISPATCHER_H__ - -#include - -#include - -using namespace libcamera; - -class QSocketNotifier; - -class QtEventDispatcher final : public EventDispatcher, public QObject -{ -public: - QtEventDispatcher(); - ~QtEventDispatcher(); - - void registerEventNotifier(EventNotifier *notifier); - void unregisterEventNotifier(EventNotifier *notifier); - - void registerTimer(Timer *timer); - void unregisterTimer(Timer *timer); - - void processEvents(); - - void interrupt(); - -protected: - void timerEvent(QTimerEvent *event); - -private: - void readNotifierActivated(int socket); - void writeNotifierActivated(int socket); - void exceptionNotifierActivated(int socket); - - struct NotifierPair { - NotifierPair() - : notifier(nullptr), qnotifier(nullptr) - { - } - EventNotifier *notifier; - QSocketNotifier *qnotifier; - }; - - struct NotifierSet { - NotifierPair read; - NotifierPair write; - NotifierPair exception; - }; - - std::map notifiers_; - std::map timers_; - std::map timerIds_; -}; - -#endif /* __QCAM_QT_EVENT_DISPATCHER_H__ */ From patchwork Mon Mar 23 17:35:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3268 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1F75060417 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BA29A308 for ; Mon, 23 Mar 2020 18:36:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984976; bh=s+Iqz9znRqWSmtq7lW1qfOQxYUTrpz6t6L+xF8J61r0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UY6ozwK8m5FUZVEPUOQ2u7wfS7ttutcQGbfulPgQENbAGHjVcmrHv/Gln/LfaePyp F1Ow6cAGlJK7x5hlDypLmPKfWJ1B07WoFSQD9lzucd8sjmV0UWrQdcvRAkXulRjPuz aTYQJOF5iHViHi+prM4gRYmuyBUYXvJlvpbyTq4U= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:40 +0200 Message-Id: <20200323173559.21109-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 02/21] qcam: Ensure headers are self-contained X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:17 -0000 Include the headers corresponding to each compile unit at the very first line to ensure they are self-contained. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/format_converter.cpp | 4 ++-- src/qcam/main_window.cpp | 3 ++- src/qcam/viewfinder.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp index 483f7c1edfce..d8962a28c06c 100644 --- a/src/qcam/format_converter.cpp +++ b/src/qcam/format_converter.cpp @@ -5,12 +5,12 @@ * format_convert.cpp - qcam - Convert buffer to RGB */ +#include "format_converter.h" + #include #include -#include "format_converter.h" - #define RGBSHIFT 8 #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 6f4f1cd770bd..66aaf40c5d45 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -5,6 +5,8 @@ * main_window.cpp - qcam - Main application window */ +#include "main_window.h" + #include #include #include @@ -25,7 +27,6 @@ #include #include -#include "main_window.h" #include "viewfinder.h" using namespace libcamera; diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index e9d5cc1e014b..f4602f07c5d2 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -5,13 +5,14 @@ * viewfinder.cpp - qcam - Viewfinder */ +#include "viewfinder.h" + #include #include #include #include #include "format_converter.h" -#include "viewfinder.h" ViewFinder::ViewFinder(QWidget *parent) : QWidget(parent), format_(0), width_(0), height_(0), image_(nullptr) From patchwork Mon Mar 23 17:35:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3269 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7AD3062C75 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1A204A31 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984977; bh=H6tP2WiYtQXoW1gr64JmAi7wXT4J3vUVkUPHf2q4zBo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jxNR/umzEyeT6CtdBxtYjucpj2Xc9kzlLpv9BSfLi5WuGVj3na6pd/o41hYqkjw75 9kEkBNWniqlh01Q6qQoq6WFEzOGJv3eIweEDEGOU6Y10F0jiZARuHLRdAMcN755ETV pf/3HP4Y7cA0jwydDPlUypWSQmhaUURYlgEtOhvE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:41 +0200 Message-Id: <20200323173559.21109-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 03/21] qcam: Use QSize through the code base X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:17 -0000 Qt has a QSize class to store sizes. Use it to replace width and height where applicable. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/format_converter.cpp | 6 +++--- src/qcam/format_converter.h | 5 +++-- src/qcam/main_window.cpp | 4 ++-- src/qcam/viewfinder.cpp | 13 ++++++------- src/qcam/viewfinder.h | 11 +++++------ 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/qcam/format_converter.cpp b/src/qcam/format_converter.cpp index d8962a28c06c..bf887ad446eb 100644 --- a/src/qcam/format_converter.cpp +++ b/src/qcam/format_converter.cpp @@ -26,7 +26,7 @@ #endif int FormatConverter::configure(const libcamera::PixelFormat &format, - unsigned int width, unsigned int height) + const QSize &size) { switch (format) { case DRM_FORMAT_NV12: @@ -139,8 +139,8 @@ int FormatConverter::configure(const libcamera::PixelFormat &format, }; format_ = format; - width_ = width; - height_ = height; + width_ = size.width(); + height_ = size.height(); return 0; } diff --git a/src/qcam/format_converter.h b/src/qcam/format_converter.h index 96bde2384ddf..5e28adf0ef63 100644 --- a/src/qcam/format_converter.h +++ b/src/qcam/format_converter.h @@ -9,6 +9,8 @@ #include +#include + #include class QImage; @@ -16,8 +18,7 @@ class QImage; class FormatConverter { public: - int configure(const libcamera::PixelFormat &format, unsigned int width, - unsigned int height); + int configure(const libcamera::PixelFormat &format, const QSize &size); void convert(const unsigned char *src, size_t size, QImage *dst); diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 66aaf40c5d45..e0668176e427 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -232,8 +232,8 @@ int MainWindow::startCapture() } Stream *stream = cfg.stream(); - ret = viewfinder_->setFormat(cfg.pixelFormat, cfg.size.width, - cfg.size.height); + ret = viewfinder_->setFormat(cfg.pixelFormat, + QSize(cfg.size.width, cfg.size.height)); if (ret < 0) { std::cout << "Failed to set viewfinder format" << std::endl; return ret; diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index f4602f07c5d2..066ac605e7b4 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -15,7 +15,7 @@ #include "format_converter.h" ViewFinder::ViewFinder(QWidget *parent) - : QWidget(parent), format_(0), width_(0), height_(0), image_(nullptr) + : QWidget(parent), format_(0), image_(nullptr) { } @@ -46,20 +46,19 @@ QImage ViewFinder::getCurrentImage() } int ViewFinder::setFormat(const libcamera::PixelFormat &format, - unsigned int width, unsigned int height) + const QSize &size) { int ret; - ret = converter_.configure(format, width, height); + ret = converter_.configure(format, size); if (ret < 0) return ret; format_ = format; - width_ = width; - height_ = height; + size_ = size; delete image_; - image_ = new QImage(width, height, QImage::Format_RGB32); + image_ = new QImage(size_, QImage::Format_RGB32); updateGeometry(); return 0; @@ -73,5 +72,5 @@ void ViewFinder::paintEvent(QPaintEvent *) QSize ViewFinder::sizeHint() const { - return image_ ? image_->size() : QSize(640, 480); + return size_.isValid() ? size_ : QSize(640, 480); } diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 0549f038edd6..a019c3a470ea 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -8,6 +8,7 @@ #define __QCAM_VIEWFINDER_H__ #include +#include #include #include @@ -22,8 +23,7 @@ public: ViewFinder(QWidget *parent); ~ViewFinder(); - int setFormat(const libcamera::PixelFormat &format, unsigned int width, - unsigned int height); + int setFormat(const libcamera::PixelFormat &format, const QSize &size); void display(const unsigned char *rgb, size_t size); QImage getCurrentImage(); @@ -33,12 +33,11 @@ protected: QSize sizeHint() const override; private: - libcamera::PixelFormat format_; - unsigned int width_; - unsigned int height_; - FormatConverter converter_; + libcamera::PixelFormat format_; + QSize size_; + QImage *image_; QMutex mutex_; /* Prevent concurrent access to image_ */ }; From patchwork Mon Mar 23 17:35:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3270 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C150862C75 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6B4C6308 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984977; bh=sJeSFFq7Y3wN1fGa3MDVBAIi56divZ7+/mskXvU77Kg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=rnqgalPKEtBIYH3EoWijkwDGozrbiqZzFCuK/BC1Ix9cI+vM6H2v+L40MXj8m2Nwo 6A3gEkBCD8Bm7jXiiFH5piQAz0KANwEEXJCz+IyT4zUJKjTbMAxB0p5JCelbuw3FOD 5KLGJ0TaVf1A1cA3t3TRZssOSAHIlbS+Z3a0okA8= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:42 +0200 Message-Id: <20200323173559.21109-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 04/21] qcam: main_window: Move request queuing to a separate function X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:17 -0000 Requests are requeued synchronously from the completion handler. To prepare for delayed requeuing, move the queuing to a separate function. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 29 +++++++++++++++-------------- src/qcam/main_window.h | 1 + 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index e0668176e427..354a53367d0f 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -389,20 +389,7 @@ void MainWindow::requestComplete(Request *request) display(buffer); - request = camera_->createRequest(); - if (!request) { - std::cerr << "Can't create request" << std::endl; - return; - } - - for (auto it = buffers.begin(); it != buffers.end(); ++it) { - Stream *stream = it->first; - FrameBuffer *buffer = it->second; - - request->addBuffer(stream, buffer); - } - - camera_->queueRequest(request); + queueRequest(buffer); } int MainWindow::display(FrameBuffer *buffer) @@ -417,3 +404,17 @@ int MainWindow::display(FrameBuffer *buffer) return 0; } + +void MainWindow::queueRequest(FrameBuffer *buffer) +{ + Request *request = camera_->createRequest(); + if (!request) { + std::cerr << "Can't create request" << std::endl; + return; + } + + Stream *stream = config_->at(0).stream(); + request->addBuffer(stream, buffer); + + camera_->queueRequest(request); +} diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 40aa10aaea8e..720a3393e3dc 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -58,6 +58,7 @@ private: void requestComplete(Request *request); int display(FrameBuffer *buffer); + void queueRequest(FrameBuffer *buffer); QString title_; QTimer titleTimer_; From patchwork Mon Mar 23 17:35:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3271 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 286AF62C75 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BCB5AA31 for ; Mon, 23 Mar 2020 18:36:17 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984977; bh=VZ+Fdi4R/qcjgacHAMFeo4rZahK6A5/1bLp+7gEqKb0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=XTPmQ7CwPZBPO69+M4Jw/9S21an3F6o8lXLmFRfxCfvnqi5xTFJtmNyM4PS1OcjCv 7WFTg5N9aLJLn3WCPB9/gsKWYBCzxIK6vQUWxxPaBgFIxDaPkxhF8GIA4TteinHcrp vwIkWDsgDMur7wjqOeq7FjN2J4Fj5lvIWpSLaH6k= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:43 +0200 Message-Id: <20200323173559.21109-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 05/21] qcam: main_window: Move capture event processing to main thread X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:20 -0000 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 Reviewed-by: Kieran Bingham --- Changes since v1: - Add blank line --- src/qcam/main_window.cpp | 55 +++++++++++++++++++++++++++++++++++++++- src/qcam/main_window.h | 8 ++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 354a53367d0f..805690d5006a 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -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); + } +}; + 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 &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 #include +#include #include +#include #include #include @@ -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 doneQueue_; + QToolBar *toolbar_; ViewFinder *viewfinder_; std::map> mappedBuffers_; From patchwork Mon Mar 23 17:35:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3272 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 9895C60417 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1A15E308 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984978; bh=KviRyMViYIPNum4+T1mlXXg5Bc3HJHWIRECGIb01JqU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=R5OGwbM7mXzjCVj7mRHxjFvdz0pCEsqxh5sov9adAqhVB6YjL8PPgrDQ9M7ZHciPB EWDEDVSX/sp2luoyR0T0annnf9KmegSAG18zCk3RKjzXBROM49U6QRHe6gjk5CVZGq WPjWaZXhLs9Kfh2Vjj35LExODVMEz2QyIqlWXCBY= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:44 +0200 Message-Id: <20200323173559.21109-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 06/21] qcam: main_window: Replace start and stop actions with a toggle action X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:22 -0000 The main window toolbar contains a start button and a stop button. This allows starting an already started camera (which is currently not handled and results in an error) or stopping an already stopped camera. Replace the two actions with a single start/stop toggle action, preventing UI misuse and reducing confusion. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Switch between play and stop icons --- src/qcam/main_window.cpp | 34 ++++++++++++++++++++++++---------- src/qcam/main_window.h | 13 ++++++++++--- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 805690d5006a..74b8748c3347 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -63,11 +62,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) adjustSize(); ret = openCamera(); - if (!ret) - ret = startCapture(); - if (ret < 0) quit(); + + startStopAction_->setChecked(true); } MainWindow::~MainWindow() @@ -113,11 +111,13 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); - action = toolbar_->addAction(QIcon(":play-circle.svg"), "start"); - connect(action, &QAction::triggered, this, &MainWindow::startCapture); + iconPlay_ = QIcon(":play-circle.svg"); + iconStop_ = QIcon(":stop-circle.svg"); - action = toolbar_->addAction(QIcon(":stop-circle.svg"), "stop"); - connect(action, &QAction::triggered, this, &MainWindow::stopCapture); + action = toolbar_->addAction(iconPlay_, "Start Capture"); + action->setCheckable(true); + connect(action, &QAction::toggled, this, &MainWindow::toggleCapture); + startStopAction_ = action; action = toolbar_->addAction(QIcon(":save.svg"), "saveAs"); connect(action, &QAction::triggered, this, &MainWindow::saveImageAs); @@ -159,12 +159,12 @@ void MainWindow::switchCamera(int index) std::cout << "Switching to camera " << cam->name() << std::endl; - stopCapture(); + startStopAction_->setChecked(false); camera_->release(); camera_ = cam; - startCapture(); + startStopAction_->setChecked(true); } std::string MainWindow::chooseCamera() @@ -217,6 +217,19 @@ int MainWindow::openCamera() return 0; } +void MainWindow::toggleCapture(bool start) +{ + if (start) { + startCapture(); + startStopAction_->setIcon(iconStop_); + startStopAction_->setText("Stop Capture"); + } else { + stopCapture(); + startStopAction_->setIcon(iconPlay_); + startStopAction_->setText("Start Capture"); + } +} + int MainWindow::startCapture() { int ret; @@ -322,6 +335,7 @@ int MainWindow::startCapture() } isCapturing_ = true; + return 0; error_disconnect: diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index c623120d5894..34a090cc463e 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ using namespace libcamera; +class QAction; class ViewFinder; enum { @@ -49,9 +51,7 @@ private Q_SLOTS: void updateTitle(); void switchCamera(int index); - - int startCapture(); - void stopCapture(); + void toggleCapture(bool start); void saveImageAs(); @@ -60,11 +60,17 @@ private: std::string chooseCamera(); int openCamera(); + int startCapture(); + void stopCapture(); + void requestComplete(Request *request); void processCapture(); int display(FrameBuffer *buffer); void queueRequest(FrameBuffer *buffer); + QIcon iconPlay_; + QIcon iconStop_; + QString title_; QTimer titleTimer_; @@ -87,6 +93,7 @@ private: QQueue doneQueue_; QToolBar *toolbar_; + QAction *startStopAction_; ViewFinder *viewfinder_; std::map> mappedBuffers_; }; From patchwork Mon Mar 23 17:35:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3273 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CAEFE62CC3 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6B1FFA31 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984978; bh=kx4gjDAMNtkpvOXxR9uIYamZfxIRWIZM0OCOZ9J/E/s=; h=From:To:Subject:Date:In-Reply-To:References:From; b=TBDRN2TaRHtFMMCr7NCJqkYqWkwRvXvzPjM7G6yJmIYSzEZUUAofQh2UC2VhYxahw WrT+c4JHB5jl6ZVBZ2a5qEBSg0365118/kEDgAqLWob4mnXb4QDx5gL/Wj0GZBl/xk wlfwLgKRt0pcxbpsYqiSnIXfKs8LIy7U3hF2ly5A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:45 +0200 Message-Id: <20200323173559.21109-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 07/21] qcam: main_window: Use icons from system icon theme X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:22 -0000 Use the system icon theme by default, falling back to custom icons if no theme is available. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Rebase on play/stop action toggle --- src/qcam/main_window.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 74b8748c3347..9f008a57f9a1 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -96,7 +96,9 @@ int MainWindow::createToolbars() /* Disable right click context menu. */ toolbar_->setContextMenuPolicy(Qt::PreventContextMenu); - action = toolbar_->addAction(QIcon(":x-circle.svg"), "Quit"); + action = toolbar_->addAction(QIcon::fromTheme("application-exit", + QIcon(":x-circle.svg")), + "Quit"); connect(action, &QAction::triggered, this, &MainWindow::quit); /* Camera selection. */ @@ -111,15 +113,19 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); - iconPlay_ = QIcon(":play-circle.svg"); - iconStop_ = QIcon(":stop-circle.svg"); + iconPlay_ = QIcon::fromTheme("media-playback-start", + QIcon(":play-circle.svg")); + iconStop_ = QIcon::fromTheme("media-playback-stop", + QIcon(":stop-circle.svg")); action = toolbar_->addAction(iconPlay_, "Start Capture"); action->setCheckable(true); connect(action, &QAction::toggled, this, &MainWindow::toggleCapture); startStopAction_ = action; - action = toolbar_->addAction(QIcon(":save.svg"), "saveAs"); + action = toolbar_->addAction(QIcon::fromTheme("document-save-as", + QIcon(":save.svg")), + "Save As..."); connect(action, &QAction::triggered, this, &MainWindow::saveImageAs); return 0; From patchwork Mon Mar 23 17:35:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3274 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2859662C9A for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BD199308 for ; Mon, 23 Mar 2020 18:36:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984978; bh=Xracp1fiNf22uYy2CLIxNfwSgQxuNQd7bvIJzTbxX38=; h=From:To:Subject:Date:In-Reply-To:References:From; b=lx51jEm3x2b06XzP44GINNRt47UGAEXJym+RZwnV+AYGO70vQA8pkuz+085b2i3wi F4GM6rXG6VyVh/NX1U3QPNxa4PdOoECkVR5hAoCWlZmyaak0iv3j2T7582G/tNESvi i5D0ms6ZQrAJ4lRRAy33BO5lB5JMdcKtcyzJE1tE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:46 +0200 Message-Id: <20200323173559.21109-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 08/21] qcam: main_window: Add shortcuts for toolbar actions X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:22 -0000 Allow triggering toolbar actions with keyboard shortcuts. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Use QKeySequence::SaveAs --- src/qcam/main_window.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 9f008a57f9a1..6afb7714c457 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -99,6 +99,7 @@ int MainWindow::createToolbars() action = toolbar_->addAction(QIcon::fromTheme("application-exit", QIcon(":x-circle.svg")), "Quit"); + action->setShortcut(Qt::CTRL | Qt::Key_Q); connect(action, &QAction::triggered, this, &MainWindow::quit); /* Camera selection. */ @@ -120,12 +121,14 @@ int MainWindow::createToolbars() action = toolbar_->addAction(iconPlay_, "Start Capture"); action->setCheckable(true); + action->setShortcut(Qt::Key_Space); connect(action, &QAction::toggled, this, &MainWindow::toggleCapture); startStopAction_ = action; action = toolbar_->addAction(QIcon::fromTheme("document-save-as", QIcon(":save.svg")), "Save As..."); + action->setShortcut(QKeySequence::SaveAs); connect(action, &QAction::triggered, this, &MainWindow::saveImageAs); return 0; From patchwork Mon Mar 23 17:35:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3275 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7AF6D62CD0 for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 199F3A31 for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984979; bh=8JiUz19Lt9JOUVAhxgL6yLvl19nOjqPLuLXY7pVwuhY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=fhG42jsv0Pv6InU0TFxgGekfQakApGWKe0FkxpDkiRe7VCRN+//5QXxH6Hn4kV18n UZL/RhiFJeX8lMsvltxexcmT2HkOTAOyHLW6/W5HAcrpX9O47mIBKbPJxOTvBPC+RF MDVhtXPAIg63OXyWqx3wVA4J9wQpWvZZxqLiePxs= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:47 +0200 Message-Id: <20200323173559.21109-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 09/21] qcam: main_window: Don't print message when saving a picture X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:22 -0000 When saving a picture, the application prints a message on cout. This isn't necessary and doesn't really help with debugging or diagnostics, remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 6afb7714c457..7959c17cd610 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -410,9 +410,6 @@ void MainWindow::saveImageAs() QString filename = QFileDialog::getSaveFileName(this, "Save Image", defaultPath, "Image Files (*.png *.jpg *.jpeg)"); - - std::cout << "Save image to " << filename.toStdString() << std::endl; - if (filename.isEmpty()) return; From patchwork Mon Mar 23 17:35:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3277 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CB31562CA6 for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6A95B308 for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984979; bh=BujrZLoKPy/+bE7zekAjMLPsYYYJ00vMwXL5VFlLGSI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=K9nK1mTHyLZC5Hev3cta6vpqxgPNCW2LIptLIFu8v4eF2ijIyc0NPsQfVwDw+SBni grP4LVrrHC3tg1u3p5aSAQXGbOQfeEsV7jXuFFbBv9fG/okI/w4OD4Vzfdoz3R0QPE YPjSgFieE0r4zO63cDGJdnGtqcdopZYfR0UGQZng= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:48 +0200 Message-Id: <20200323173559.21109-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 10/21] qcam: main_window: Document functions and reorganize member data X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:23 -0000 The qcam application is our reference implementation of a libcamera GUI application. Document the code of the MainWindow class to make it easier to follow, and reorganize the member data in logical groups for clarity. No code change. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 69 +++++++++++++++++++++++++++++++++++++++- src/qcam/main_window.h | 24 ++++++++------ 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 7959c17cd610..20e84171e4a5 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -31,6 +31,9 @@ using namespace libcamera; +/** + * \brief Custom QEvent to signal capture completion + */ class CaptureEvent : public QEvent { public: @@ -51,6 +54,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) { int ret; + /* + * Initialize the UI: Create the toolbar, set the window title and + * create the viewfinder widget. + */ createToolbars(); title_ = "QCam " + QString::fromStdString(CameraManager::version()); @@ -61,6 +68,7 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) setCentralWidget(viewfinder_); adjustSize(); + /* Open the camera and start capture. */ ret = openCamera(); if (ret < 0) quit(); @@ -96,13 +104,14 @@ int MainWindow::createToolbars() /* Disable right click context menu. */ toolbar_->setContextMenuPolicy(Qt::PreventContextMenu); + /* Quit action. */ action = toolbar_->addAction(QIcon::fromTheme("application-exit", QIcon(":x-circle.svg")), "Quit"); action->setShortcut(Qt::CTRL | Qt::Key_Q); connect(action, &QAction::triggered, this, &MainWindow::quit); - /* Camera selection. */ + /* Camera selector. */ QComboBox *cameraCombo = new QComboBox(); connect(cameraCombo, QOverload::of(&QComboBox::activated), this, &MainWindow::switchCamera); @@ -114,6 +123,7 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); + /* Start/Stop action. */ iconPlay_ = QIcon::fromTheme("media-playback-start", QIcon(":play-circle.svg")); iconStop_ = QIcon::fromTheme("media-playback-stop", @@ -125,6 +135,7 @@ int MainWindow::createToolbars() connect(action, &QAction::toggled, this, &MainWindow::toggleCapture); startStopAction_ = action; + /* Save As... action. */ action = toolbar_->addAction(QIcon::fromTheme("document-save-as", QIcon(":save.svg")), "Save As..."); @@ -142,6 +153,7 @@ void MainWindow::quit() void MainWindow::updateTitle() { + /* Calculate the average frame rate over the last period. */ unsigned int duration = frameRateInterval_.elapsed(); unsigned int frames = framesCaptured_ - previousFrames_; double fps = frames * 1000.0 / duration; @@ -153,8 +165,13 @@ void MainWindow::updateTitle() setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + " fps"); } +/* ----------------------------------------------------------------------------- + * Camera Selection + */ + void MainWindow::switchCamera(int index) { + /* Get and acquire the new camera. */ const auto &cameras = cm_->cameras(); if (static_cast(index) >= cameras.size()) return; @@ -168,6 +185,10 @@ void MainWindow::switchCamera(int index) std::cout << "Switching to camera " << cam->name() << std::endl; + /* + * Stop the capture session, release the current camera, replace it with + * the new camera and start a new capture session. + */ startStopAction_->setChecked(false); camera_->release(); @@ -181,9 +202,11 @@ std::string MainWindow::chooseCamera() QStringList cameras; bool result; + /* If only one camera is available, use it automatically. */ if (cm_->cameras().size() == 1) return cm_->cameras()[0]->name(); + /* Present a dialog box to pick a camera. */ for (const std::shared_ptr &cam : cm_->cameras()) cameras.append(QString::fromStdString(cam->name())); @@ -200,6 +223,10 @@ int MainWindow::openCamera() { std::string cameraName; + /* + * Use the camera specified on the command line, if any, or display the + * camera selection dialog box otherwise. + */ if (options_.isSet(OptCamera)) cameraName = static_cast(options_[OptCamera]); else @@ -208,6 +235,7 @@ int MainWindow::openCamera() if (cameraName == "") return -EINVAL; + /* Get and acquire the camera. */ camera_ = cm_->get(cameraName); if (!camera_) { std::cout << "Camera " << cameraName << " not found" @@ -226,6 +254,10 @@ int MainWindow::openCamera() return 0; } +/* ----------------------------------------------------------------------------- + * Capture Start & Stop + */ + void MainWindow::toggleCapture(bool start) { if (start) { @@ -239,10 +271,16 @@ void MainWindow::toggleCapture(bool start) } } +/** + * \brief Start capture with the current camera + * + * This function shall not be called directly, use toggleCapture() instead. + */ int MainWindow::startCapture() { int ret; + /* Configure the camera. */ config_ = camera_->generateConfiguration({ StreamRole::Viewfinder }); StreamConfiguration &cfg = config_->at(0); @@ -279,6 +317,7 @@ int MainWindow::startCapture() return ret; } + /* Configure the viewfinder. */ Stream *stream = cfg.stream(); ret = viewfinder_->setFormat(cfg.pixelFormat, QSize(cfg.size.width, cfg.size.height)); @@ -289,6 +328,7 @@ int MainWindow::startCapture() adjustSize(); + /* Allocate buffers and requests. */ allocator_ = new FrameBufferAllocator(camera_); ret = allocator_->allocate(stream); if (ret < 0) { @@ -321,6 +361,7 @@ int MainWindow::startCapture() std::make_pair(memory, plane.length); } + /* Start the title timer and the camera. */ titleTimer_.start(2000); frameRateInterval_.start(); previousFrames_ = 0; @@ -335,6 +376,7 @@ int MainWindow::startCapture() camera_->requestCompleted.connect(this, &MainWindow::requestComplete); + /* Queue all requests. */ for (Request *request : requests) { ret = camera_->queueRequest(request); if (ret < 0) { @@ -368,6 +410,12 @@ error: return ret; } +/** + * \brief Stop ongoing capture + * + * This function may be called directly when tearing down the MainWindow. Use + * toggleCapture() instead in all other cases. + */ void MainWindow::stopCapture() { if (!isCapturing_) @@ -403,6 +451,10 @@ void MainWindow::stopCapture() setWindowTitle(title_); } +/* ----------------------------------------------------------------------------- + * Image Save + */ + void MainWindow::saveImageAs() { QImage image = viewfinder_->getCurrentImage(); @@ -418,11 +470,20 @@ void MainWindow::saveImageAs() writer.write(image); } +/* ----------------------------------------------------------------------------- + * Request Completion Handling + */ + void MainWindow::requestComplete(Request *request) { if (request->status() == Request::RequestCancelled) return; + /* + * We're running in the libcamera thread context, expensive operations + * are not allowed. Add the buffer to the done queue and post a + * CaptureEvent for the application thread to handle. + */ const std::map &buffers = request->buffers(); FrameBuffer *buffer = buffers.begin()->second; @@ -436,6 +497,11 @@ void MainWindow::requestComplete(Request *request) void MainWindow::processCapture() { + /* + * Retrieve the next buffer from the done queue. The queue may be empty + * if stopCapture() has been called while a CaptureEvent was posted but + * not processed yet. Return immediately in that case. + */ FrameBuffer *buffer; { @@ -460,6 +526,7 @@ void MainWindow::processCapture() << " fps: " << std::fixed << std::setprecision(2) << fps << std::endl; + /* Display the buffer and requeue it to the camera. */ display(buffer); queueRequest(buffer); diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 34a090cc463e..c662a2ef3bcf 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -57,6 +57,7 @@ private Q_SLOTS: private: int createToolbars(); + std::string chooseCamera(); int openCamera(); @@ -68,34 +69,37 @@ private: int display(FrameBuffer *buffer); void queueRequest(FrameBuffer *buffer); + /* UI elements */ + QToolBar *toolbar_; + QAction *startStopAction_; + ViewFinder *viewfinder_; + QIcon iconPlay_; QIcon iconStop_; QString title_; QTimer titleTimer_; + /* Options */ const OptionsParser::Options &options_; + /* Camera manager, camera, configuration and buffers */ CameraManager *cm_; std::shared_ptr camera_; FrameBufferAllocator *allocator_; - bool isCapturing_; std::unique_ptr config_; + std::map> mappedBuffers_; - uint64_t lastBufferTime_; + /* Capture state, buffers queue and statistics */ + bool isCapturing_; + QQueue doneQueue_; + QMutex mutex_; /* Protects doneQueue_ */ + uint64_t lastBufferTime_; QElapsedTimer frameRateInterval_; uint32_t previousFrames_; uint32_t framesCaptured_; - - QMutex mutex_; - QQueue doneQueue_; - - QToolBar *toolbar_; - QAction *startStopAction_; - ViewFinder *viewfinder_; - std::map> mappedBuffers_; }; #endif /* __QCAM_MAIN_WINDOW__ */ From patchwork Mon Mar 23 17:35:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3276 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1F8B562C54 for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BBA98A31 for ; Mon, 23 Mar 2020 18:36:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984979; bh=0XGZiIToAwEhSgXz1L2qCDg0+oPVA50ixpHiATOmZtE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=glu+LCGo2QoEi7Ihlhe0a5xQiPmdF9KRflmAXHDvEjP8PhAzzvRAn5Ll2CF2/Oqxb kT3tKPStaNSCYiLCyjQN0fSfukgFxDpJIGK1F9azM0KPRb67mwDVa8JTzVJZxEkUjY MvCByzh1JLb+ZgB0Df/dxP9vmEmOSLmrZhEFCGt4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:49 +0200 Message-Id: <20200323173559.21109-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 11/21] qcam: main_window: Remove unneeded debug message X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:23 -0000 Printing the name of the selected camera to the log doesn't provide any value. Remove it. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 20e84171e4a5..c0d42c64749c 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -249,8 +249,6 @@ int MainWindow::openCamera() return -EBUSY; } - std::cout << "Using camera " << camera_->name() << std::endl; - return 0; } From patchwork Mon Mar 23 17:35:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3278 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7A92962C75 for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1A94D308 for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984980; bh=XyKVwKMcUtSXSHJwN6mAV5phrTcamQLSPcFS0Hb5rvo=; h=From:To:Subject:Date:In-Reply-To:References:From; b=VaRKsJdQTIKVigtz+bHEpFkGF6MnBLB6DZDX8NcZfsqVdTCpwMTad7Mky5trRQ58O psaORePr4Pp9HaoHsLDW+jPSeryXrlf1EZQ2qOhlkJqTRc70RlYAqRtMhHLNbzbRru OUs/fF7BIi3WwV+nr4UpxB4rACxDWAO7xUKSU5Ec= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:50 +0200 Message-Id: <20200323173559.21109-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 12/21] qcam: Use Qt qInfo() and qWarning() logging facilities X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 Replace manual usage of std::cout and std::cerr with the Qt logging facilities. This allows redirection log output if needed, and integrates better with Qt. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Fix compilation on Qt 5.12 --- src/qcam/main.cpp | 8 +++---- src/qcam/main_window.cpp | 45 ++++++++++++++++++++-------------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/qcam/main.cpp b/src/qcam/main.cpp index 297453914ae9..862d714f467c 100644 --- a/src/qcam/main.cpp +++ b/src/qcam/main.cpp @@ -5,11 +5,11 @@ * main.cpp - cam - The libcamera swiss army knife */ -#include #include #include #include +#include #include @@ -18,7 +18,7 @@ void signalHandler(int signal) { - std::cout << "Exiting" << std::endl; + qInfo() << "Exiting"; qApp->quit(); } @@ -65,8 +65,8 @@ int main(int argc, char **argv) ret = cm->start(); if (ret) { - std::cout << "Failed to start camera manager: " - << strerror(-ret) << std::endl; + qInfo() << "Failed to start camera manager:" + << strerror(-ret); return EXIT_FAILURE; } diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index c0d42c64749c..cb8f769e9bb8 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -8,7 +8,6 @@ #include "main_window.h" #include -#include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include #include #include @@ -179,11 +179,11 @@ void MainWindow::switchCamera(int index) const std::shared_ptr &cam = cameras[index]; if (cam->acquire()) { - std::cout << "Failed to acquire camera " << cam->name() << std::endl; + qInfo() << "Failed to acquire camera" << cam->name().c_str(); return; } - std::cout << "Switching to camera " << cam->name() << std::endl; + qInfo() << "Switching to camera" << cam->name().c_str(); /* * Stop the capture session, release the current camera, replace it with @@ -238,13 +238,12 @@ int MainWindow::openCamera() /* Get and acquire the camera. */ camera_ = cm_->get(cameraName); if (!camera_) { - std::cout << "Camera " << cameraName << " not found" - << std::endl; + qInfo() << "Camera" << cameraName.c_str() << "not found"; return -ENODEV; } if (camera_->acquire()) { - std::cout << "Failed to acquire camera" << std::endl; + qInfo() << "Failed to acquire camera"; camera_.reset(); return -EBUSY; } @@ -300,18 +299,18 @@ int MainWindow::startCapture() CameraConfiguration::Status validation = config_->validate(); if (validation == CameraConfiguration::Invalid) { - std::cerr << "Failed to create valid camera configuration"; + qWarning() << "Failed to create valid camera configuration"; return -EINVAL; } if (validation == CameraConfiguration::Adjusted) { - std::cout << "Stream size adjusted to " - << cfg.size.toString() << std::endl; + qInfo() << "Stream size adjusted to" + << cfg.size.toString().c_str(); } ret = camera_->configure(config_.get()); if (ret < 0) { - std::cout << "Failed to configure camera" << std::endl; + qInfo() << "Failed to configure camera"; return ret; } @@ -320,7 +319,7 @@ int MainWindow::startCapture() ret = viewfinder_->setFormat(cfg.pixelFormat, QSize(cfg.size.width, cfg.size.height)); if (ret < 0) { - std::cout << "Failed to set viewfinder format" << std::endl; + qInfo() << "Failed to set viewfinder format"; return ret; } @@ -330,7 +329,7 @@ int MainWindow::startCapture() allocator_ = new FrameBufferAllocator(camera_); ret = allocator_->allocate(stream); if (ret < 0) { - std::cerr << "Failed to allocate capture buffers" << std::endl; + qWarning() << "Failed to allocate capture buffers"; return ret; } @@ -338,14 +337,14 @@ int MainWindow::startCapture() for (const std::unique_ptr &buffer : allocator_->buffers(stream)) { Request *request = camera_->createRequest(); if (!request) { - std::cerr << "Can't create request" << std::endl; + qWarning() << "Can't create request"; ret = -ENOMEM; goto error; } ret = request->addBuffer(stream, buffer.get()); if (ret < 0) { - std::cerr << "Can't set buffer for request" << std::endl; + qWarning() << "Can't set buffer for request"; goto error; } @@ -368,7 +367,7 @@ int MainWindow::startCapture() ret = camera_->start(); if (ret) { - std::cout << "Failed to start capture" << std::endl; + qInfo() << "Failed to start capture"; goto error; } @@ -378,7 +377,7 @@ int MainWindow::startCapture() for (Request *request : requests) { ret = camera_->queueRequest(request); if (ret < 0) { - std::cerr << "Can't queue request" << std::endl; + qWarning() << "Can't queue request"; goto error_disconnect; } } @@ -421,7 +420,7 @@ void MainWindow::stopCapture() int ret = camera_->stop(); if (ret) - std::cout << "Failed to stop capture" << std::endl; + qInfo() << "Failed to stop capture"; camera_->requestCompleted.disconnect(this, &MainWindow::requestComplete); @@ -518,11 +517,11 @@ void MainWindow::processCapture() fps = lastBufferTime_ && fps ? 1000000000.0 / fps : 0.0; lastBufferTime_ = metadata.timestamp; - std::cout << "seq: " << std::setw(6) << std::setfill('0') << metadata.sequence - << " bytesused: " << metadata.planes[0].bytesused - << " timestamp: " << metadata.timestamp - << " fps: " << std::fixed << std::setprecision(2) << fps - << std::endl; + qInfo() << "seq:" << qSetFieldWidth(6) << qSetPadChar('0') + << metadata.sequence << reset + << "bytesused:" << metadata.planes[0].bytesused + << "timestamp:" << metadata.timestamp + << "fps:" << fixed << qSetRealNumberPrecision(2) << fps; /* Display the buffer and requeue it to the camera. */ display(buffer); @@ -547,7 +546,7 @@ void MainWindow::queueRequest(FrameBuffer *buffer) { Request *request = camera_->createRequest(); if (!request) { - std::cerr << "Can't create request" << std::endl; + qWarning() << "Can't create request"; return; } From patchwork Mon Mar 23 17:35:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3279 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C4CC462CEE for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 6CEC411FD for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984980; bh=tLXsNpw2+r/yirHmSwZKwH1iEYzw646uJGvvHq+c6X0=; h=From:To:Subject:Date:In-Reply-To:References:From; b=vRiHg1E2ruDzLRUAse99+3scpBqNv1hwyNy9JEjNzPnpWqGSXxr04sDNuCYx5NiSA Uh/0+bquE/j6CIyhPIoEXab02ctVhLMjx5Xn9dvhAlruJB8vITDACOt0DBZyJp86rq qXmKqVYxmv/uuUML9cwBPtNK0xkrTY6JTYow1y7Y= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:51 +0200 Message-Id: <20200323173559.21109-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 13/21] qcam: viewfinder: Add MappedBuffer to store memory mapping information X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 The new MappedBuffer structure replaces the std::pair<> used in the mapped buffers map, and allows passing data to the ViewFinder::display() function in a more structured way. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 20 ++++++-------------- src/qcam/main_window.h | 4 ++-- src/qcam/viewfinder.cpp | 6 ++++-- src/qcam/viewfinder.h | 10 +++++++++- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index cb8f769e9bb8..d10c542c0b6d 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -27,8 +27,6 @@ #include #include -#include "viewfinder.h" - using namespace libcamera; /** @@ -354,8 +352,7 @@ int MainWindow::startCapture() const FrameBuffer::Plane &plane = buffer->planes().front(); void *memory = mmap(NULL, plane.length, PROT_READ, MAP_SHARED, plane.fd.fd(), 0); - mappedBuffers_[plane.fd.fd()] = - std::make_pair(memory, plane.length); + mappedBuffers_[buffer.get()] = { memory, plane.length }; } /* Start the title timer and the camera. */ @@ -395,9 +392,8 @@ error: delete request; for (auto &iter : mappedBuffers_) { - void *memory = iter.second.first; - unsigned int length = iter.second.second; - munmap(memory, length); + const MappedBuffer &buffer = iter.second; + munmap(buffer.memory, buffer.size); } mappedBuffers_.clear(); @@ -425,9 +421,8 @@ void MainWindow::stopCapture() camera_->requestCompleted.disconnect(this, &MainWindow::requestComplete); for (auto &iter : mappedBuffers_) { - void *memory = iter.second.first; - unsigned int length = iter.second.second; - munmap(memory, length); + const MappedBuffer &buffer = iter.second; + munmap(buffer.memory, buffer.size); } mappedBuffers_.clear(); @@ -534,10 +529,7 @@ int MainWindow::display(FrameBuffer *buffer) if (buffer->planes().size() != 1) return -EINVAL; - const FrameBuffer::Plane &plane = buffer->planes().front(); - void *memory = mappedBuffers_[plane.fd.fd()].first; - unsigned char *raw = static_cast(memory); - viewfinder_->display(raw, buffer->metadata().planes[0].bytesused); + viewfinder_->display(buffer, &mappedBuffers_[buffer]); return 0; } diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index c662a2ef3bcf..71206bc96fc4 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -24,11 +24,11 @@ #include #include "../cam/options.h" +#include "viewfinder.h" using namespace libcamera; class QAction; -class ViewFinder; enum { OptCamera = 'c', @@ -89,7 +89,7 @@ private: FrameBufferAllocator *allocator_; std::unique_ptr config_; - std::map> mappedBuffers_; + std::map mappedBuffers_; /* Capture state, buffers queue and statistics */ bool isCapturing_; diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 066ac605e7b4..d00edc33dfb7 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -24,7 +24,8 @@ ViewFinder::~ViewFinder() delete image_; } -void ViewFinder::display(const unsigned char *raw, size_t size) +void ViewFinder::display(const libcamera::FrameBuffer *buffer, + MappedBuffer *map) { QMutexLocker locker(&mutex_); @@ -34,7 +35,8 @@ void ViewFinder::display(const unsigned char *raw, size_t size) * impacting performances. */ - converter_.convert(raw, size, image_); + converter_.convert(static_cast(map->memory), + buffer->metadata().planes[0].bytesused, image_); update(); } diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index a019c3a470ea..735a6b67e91d 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -7,16 +7,24 @@ #ifndef __QCAM_VIEWFINDER_H__ #define __QCAM_VIEWFINDER_H__ +#include + #include #include #include +#include #include #include "format_converter.h" class QImage; +struct MappedBuffer { + void *memory; + size_t size; +}; + class ViewFinder : public QWidget { public: @@ -24,7 +32,7 @@ public: ~ViewFinder(); int setFormat(const libcamera::PixelFormat &format, const QSize &size); - void display(const unsigned char *rgb, size_t size); + void display(const libcamera::FrameBuffer *buffer, MappedBuffer *map); QImage getCurrentImage(); From patchwork Mon Mar 23 17:35:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3280 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2840D62CDF for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BF06C11FF for ; Mon, 23 Mar 2020 18:36:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984980; bh=9q3NV9u/XVH4JI9fAG4o2MP3lBe6QKic+WSF4YO7HTM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=De6UOUcLIvVuqThT2vdHhImuY0xs4ELzjC26xM3UHPPo5kyb4hMd3qcMAwU/0TP9L 8GeIqTlzd/vZqhgltzcv11SNTYgghC8NufpHno84DuFD8SV7zMR7mBg6Z1qcQNFTZW Oihn3CoJYkytVISamn3033SKsdIL+ObTrL5BBtfk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:52 +0200 Message-Id: <20200323173559.21109-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 14/21] qcam: viewfinder: Move multi-planar check into viewfinder X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 The lack of support for multiplanar buffers comes from the viewfinder. Move the corresponding check from MainWindow. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 7 +------ src/qcam/main_window.h | 2 +- src/qcam/viewfinder.cpp | 6 ++++++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index d10c542c0b6d..3711a02c7fdc 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -524,14 +524,9 @@ void MainWindow::processCapture() queueRequest(buffer); } -int MainWindow::display(FrameBuffer *buffer) +void MainWindow::display(FrameBuffer *buffer) { - if (buffer->planes().size() != 1) - return -EINVAL; - viewfinder_->display(buffer, &mappedBuffers_[buffer]); - - return 0; } void MainWindow::queueRequest(FrameBuffer *buffer) diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 71206bc96fc4..33522115b6be 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -66,7 +66,7 @@ private: void requestComplete(Request *request); void processCapture(); - int display(FrameBuffer *buffer); + void display(FrameBuffer *buffer); void queueRequest(FrameBuffer *buffer); /* UI elements */ diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index d00edc33dfb7..b8feabd5d189 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "format_converter.h" @@ -27,6 +28,11 @@ ViewFinder::~ViewFinder() void ViewFinder::display(const libcamera::FrameBuffer *buffer, MappedBuffer *map) { + if (buffer->planes().size() != 1) { + qWarning() << "Multi-planar buffers are not supported"; + return; + } + QMutexLocker locker(&mutex_); /* From patchwork Mon Mar 23 17:35:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3281 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7B3FD62C88 for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 2150DA31 for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984981; bh=CXKOfeBu+kJFTHGU7KKKu3mJrQaaF4nK76CNfVRNetY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=k/gcgtpKnLr2HeGGG6b1qyIpuIj4z4ErXwJRVhAp3CzNdXIMc0p75Dh3h1lFJKfC5 XwexqbRrt5cGIjk4R6Hm7QNqrQSWlVQT72wHIs3QIWboWMGc4H8mQ+pO1bBzKZWUX9 wY996NOf9K9yKp2zYutb5FlILEWe93Zq6nSWomYo= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:53 +0200 Message-Id: <20200323173559.21109-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 15/21] qcam: viewfinder: Make the viewfinder hold a reference to a buffer X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 The viewfinder is currently expected to render frames to the screen synchronously in the display() function, or at least to copy data so that the buffer can be queued in a new request when the function returns. This prevents optimisations when the capture format is identical to the display format. Make the viewfinder take ownership of the buffer, and notify of its release through a signal. The release is currently still synchronous, this will be addressed in a subsequent patch. Rename the ViewFinder::display() function to render() to better describe its purpose, as it's meant to start the rendering and not display the frame synchronously. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/main_window.cpp | 13 ++++--------- src/qcam/main_window.h | 4 ++-- src/qcam/meson.build | 1 + src/qcam/viewfinder.cpp | 5 +++-- src/qcam/viewfinder.h | 7 ++++++- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 3711a02c7fdc..e872bdd7ba86 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -63,6 +63,8 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) connect(&titleTimer_, SIGNAL(timeout()), this, SLOT(updateTitle())); viewfinder_ = new ViewFinder(this); + connect(viewfinder_, &ViewFinder::renderComplete, + this, &MainWindow::queueRequest); setCentralWidget(viewfinder_); adjustSize(); @@ -518,15 +520,8 @@ void MainWindow::processCapture() << "timestamp:" << metadata.timestamp << "fps:" << fixed << qSetRealNumberPrecision(2) << fps; - /* Display the buffer and requeue it to the camera. */ - display(buffer); - - queueRequest(buffer); -} - -void MainWindow::display(FrameBuffer *buffer) -{ - viewfinder_->display(buffer, &mappedBuffers_[buffer]); + /* Render the frame on the viewfinder. */ + viewfinder_->render(buffer, &mappedBuffers_[buffer]); } void MainWindow::queueRequest(FrameBuffer *buffer) diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 33522115b6be..5d6251c83070 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -55,6 +55,8 @@ private Q_SLOTS: void saveImageAs(); + void queueRequest(FrameBuffer *buffer); + private: int createToolbars(); @@ -66,8 +68,6 @@ private: void requestComplete(Request *request); void processCapture(); - void display(FrameBuffer *buffer); - void queueRequest(FrameBuffer *buffer); /* UI elements */ QToolBar *toolbar_; diff --git a/src/qcam/meson.build b/src/qcam/meson.build index 214bfb12aabb..c256d06f8ccf 100644 --- a/src/qcam/meson.build +++ b/src/qcam/meson.build @@ -8,6 +8,7 @@ qcam_sources = files([ qcam_moc_headers = files([ 'main_window.h', + 'viewfinder.h', ]) qcam_resources = files([ diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index b8feabd5d189..2a35932e0b79 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -25,8 +25,7 @@ ViewFinder::~ViewFinder() delete image_; } -void ViewFinder::display(const libcamera::FrameBuffer *buffer, - MappedBuffer *map) +void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) { if (buffer->planes().size() != 1) { qWarning() << "Multi-planar buffers are not supported"; @@ -44,6 +43,8 @@ void ViewFinder::display(const libcamera::FrameBuffer *buffer, converter_.convert(static_cast(map->memory), buffer->metadata().planes[0].bytesused, image_); update(); + + renderComplete(buffer); } QImage ViewFinder::getCurrentImage() diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 735a6b67e91d..784fcceda5bd 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -27,15 +27,20 @@ struct MappedBuffer { class ViewFinder : public QWidget { + Q_OBJECT + public: ViewFinder(QWidget *parent); ~ViewFinder(); int setFormat(const libcamera::PixelFormat &format, const QSize &size); - void display(const libcamera::FrameBuffer *buffer, MappedBuffer *map); + void render(libcamera::FrameBuffer *buffer, MappedBuffer *map); QImage getCurrentImage(); +Q_SIGNALS: + void renderComplete(libcamera::FrameBuffer *buffer); + protected: void paintEvent(QPaintEvent *) override; QSize sizeHint() const override; From patchwork Mon Mar 23 17:35:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3282 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D8EC462CB2 for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 7463A11FD for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984981; bh=ix2mgukEZFp56ZaLeP4DDPr6mZL023/orOZ3cJuWTt8=; h=From:To:Subject:Date:In-Reply-To:References:From; b=HhlR5xDyaW2Mjw+nhHHckri6XOsh2w9BbKHbcX2NvBJlZ/c6vkVdzZ4RxYw7gmmYN +u+4xxVeI0zlzeGmkAVToGnPoWyHBnHDQXsyOclpptO0RS+dNqdk3y3c/cSDBIOirE sxi3DGWR4zMlvo67lMef23N/OGxq7UYPRnzdTXFw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:54 +0200 Message-Id: <20200323173559.21109-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 16/21] qcam: viewfinder: Embed QImage in ViewFinder X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 The QImage class is a thin wrapper that uses implicit sharing. We can thus embed it in the ViewFinder class instead of allocating it dynamically, and assign it at runtime. This simplifies the code. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/viewfinder.cpp | 12 +++++------- src/qcam/viewfinder.h | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 2a35932e0b79..e7b12015d8f6 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -16,13 +16,12 @@ #include "format_converter.h" ViewFinder::ViewFinder(QWidget *parent) - : QWidget(parent), format_(0), image_(nullptr) + : QWidget(parent), format_(0) { } ViewFinder::~ViewFinder() { - delete image_; } void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) @@ -41,7 +40,7 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) */ converter_.convert(static_cast(map->memory), - buffer->metadata().planes[0].bytesused, image_); + buffer->metadata().planes[0].bytesused, &image_); update(); renderComplete(buffer); @@ -51,7 +50,7 @@ QImage ViewFinder::getCurrentImage() { QMutexLocker locker(&mutex_); - return image_->copy(); + return image_.copy(); } int ViewFinder::setFormat(const libcamera::PixelFormat &format, @@ -66,8 +65,7 @@ int ViewFinder::setFormat(const libcamera::PixelFormat &format, format_ = format; size_ = size; - delete image_; - image_ = new QImage(size_, QImage::Format_RGB32); + image_ = QImage(size_, QImage::Format_RGB32); updateGeometry(); return 0; @@ -76,7 +74,7 @@ int ViewFinder::setFormat(const libcamera::PixelFormat &format, void ViewFinder::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.drawImage(rect(), *image_, image_->rect()); + painter.drawImage(rect(), image_, image_.rect()); } QSize ViewFinder::sizeHint() const diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 784fcceda5bd..54c0fa9dd7a0 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -51,7 +52,7 @@ private: libcamera::PixelFormat format_; QSize size_; - QImage *image_; + QImage image_; QMutex mutex_; /* Prevent concurrent access to image_ */ }; From patchwork Mon Mar 23 17:35:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3283 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3865362CBF for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C6E71308 for ; Mon, 23 Mar 2020 18:36:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984981; bh=KHky5wQDrxlrZylZbKpfKU6yMx+vbRwM5uH5RwoXuEU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=d/uR5jN7GRT888MSILxik8RfJIPXfl+KldV/XphcdTJKQWReG7P1X9x7rH4ufS6Ih 8Y2pxqFjLQmeJVoaLJ7hu3yVKIa8HhmlgXc7cYPgfY73XOp+H4bdU+Y9+irYIE8uaZ Q9+0aNpls1TxcYrrd8Rk4Ow5vYjgjYPMCJ60Kts0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:55 +0200 Message-Id: <20200323173559.21109-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 17/21] qcam: viewfinder: Use PixelFormat default constructor X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 There's no need to initialize the PixelFormat stored in ViewFinder explicitly, as PixelFormat is now a class with a default constructor. Remove the initialization. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/viewfinder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index e7b12015d8f6..c4471ffa4a06 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -16,7 +16,7 @@ #include "format_converter.h" ViewFinder::ViewFinder(QWidget *parent) - : QWidget(parent), format_(0) + : QWidget(parent) { } From patchwork Mon Mar 23 17:35:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3284 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 86D7760417 for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 23EE6A31 for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984982; bh=FOEDiw5ZOGVfA1UftcUjP9SER1zDd2uJT/V19dVdqD4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=NzNj8Z1uVjh+eJ2FF9KOA8YfFA8cNREjltb19YJHRYTcxciRpBqBf2nMJqgrcd/Ib 3kvZuOJd3RRfP6OQZsoZtzzjsjtdBUPsFO4eI3ib+K9FkHivtBGXpEGSNCwLZnHp+A CVlIPo38XDG9wiSQhxOpAFa9nOd6q7GogkiL5cCc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:56 +0200 Message-Id: <20200323173559.21109-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 18/21] qcam: viewfinder: Reorder methods to match header file X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 Reorder the methods in viewfinder.cpp to match the order in viewfinder.h. No code change. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- src/qcam/viewfinder.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index c4471ffa4a06..31b358da47dc 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -24,6 +24,24 @@ ViewFinder::~ViewFinder() { } +int ViewFinder::setFormat(const libcamera::PixelFormat &format, + const QSize &size) +{ + int ret; + + ret = converter_.configure(format, size); + if (ret < 0) + return ret; + + format_ = format; + size_ = size; + + image_ = QImage(size_, QImage::Format_RGB32); + + updateGeometry(); + return 0; +} + void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) { if (buffer->planes().size() != 1) { @@ -53,24 +71,6 @@ QImage ViewFinder::getCurrentImage() return image_.copy(); } -int ViewFinder::setFormat(const libcamera::PixelFormat &format, - const QSize &size) -{ - int ret; - - ret = converter_.configure(format, size); - if (ret < 0) - return ret; - - format_ = format; - size_ = size; - - image_ = QImage(size_, QImage::Format_RGB32); - - updateGeometry(); - return 0; -} - void ViewFinder::paintEvent(QPaintEvent *) { QPainter painter(this); From patchwork Mon Mar 23 17:35:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3285 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D408F62CD4 for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 75C76308 for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984982; bh=XBJTDLeBpsITfQTnntj/V4e5CGymnErEuB9yFtPeiFc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pPE93g7DNlJBOCzVKz0OHRSepm/q1LkF+VPnLcAxEqJ4YRdY5gc9xlZU2AUuDRM6i yjSw//Vg0xRlDdiWAGZS+043IdpUye8rXWw7kpgm8M6kqsbZq8EeNk501taxjm41qY fFkQ28MEQPn0suHtgeacX/IUbmCkYP+w2yoQqNno= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:57 +0200 Message-Id: <20200323173559.21109-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 19/21] qcam: viewfinder: Avoid memory copy when conversion isn't needed X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 If the frame buffer format is identical to the display format, the viewfinder still invokes the converter to perform what is essentially a slow memcpy(). Make it possible to skip that operation by creating a QImage referencing the buffer memory instead. A reference to the frame buffer is kept internally, and released when the next buffer is queued, pushing the current one out. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Add stop() function to release the buffer --- src/qcam/main_window.cpp | 2 ++ src/qcam/viewfinder.cpp | 74 +++++++++++++++++++++++++++++++--------- src/qcam/viewfinder.h | 2 ++ 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index e872bdd7ba86..b13660bccb25 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -416,6 +416,8 @@ void MainWindow::stopCapture() if (!isCapturing_) return; + viewfinder_->stop(); + int ret = camera_->stop(); if (ret) qInfo() << "Failed to stop capture"; diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 31b358da47dc..3f984efbf434 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -7,6 +7,8 @@ #include "viewfinder.h" +#include + #include #include #include @@ -16,7 +18,7 @@ #include "format_converter.h" ViewFinder::ViewFinder(QWidget *parent) - : QWidget(parent) + : QWidget(parent), buffer_(nullptr) { } @@ -27,17 +29,23 @@ ViewFinder::~ViewFinder() int ViewFinder::setFormat(const libcamera::PixelFormat &format, const QSize &size) { - int ret; + image_ = QImage(); - ret = converter_.configure(format, size); - if (ret < 0) - return ret; + /* + * If format conversion is needed, configure the converter and allocate + * the destination image. + */ + if (format != DRM_FORMAT_ARGB8888) { + int ret = converter_.configure(format, size); + if (ret < 0) + return ret; + + image_ = QImage(size, QImage::Format_RGB32); + } format_ = format; size_ = size; - image_ = QImage(size_, QImage::Format_RGB32); - updateGeometry(); return 0; } @@ -49,19 +57,51 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) return; } - QMutexLocker locker(&mutex_); - - /* - * \todo We're not supposed to block the pipeline handler thread - * for long, implement a better way to save images without - * impacting performances. - */ + unsigned char *memory = static_cast(map->memory); + size_t size = buffer->metadata().planes[0].bytesused; + + { + QMutexLocker locker(&mutex_); + + if (format_ == DRM_FORMAT_ARGB8888) { + /* + * If the frame format is identical to the display + * format, create a QImage that references the frame + * and store a reference to the frame buffer. The + * previously stored frame buffer, if any, will be + * released. + * + * \todo Get the stride from the buffer instead of + * computing it naively + */ + image_ = QImage(memory, size_.width(), size_.height(), + size / size_.height(), QImage::Format_RGB32); + std::swap(buffer, buffer_); + } else { + /* + * Otherwise, convert the format and release the frame + * buffer immediately. + */ + converter_.convert(memory, size, &image_); + } + } - converter_.convert(static_cast(map->memory), - buffer->metadata().planes[0].bytesused, &image_); update(); - renderComplete(buffer); + if (buffer) + renderComplete(buffer); +} + +void ViewFinder::stop() +{ + image_ = QImage(); + + if (buffer_) { + renderComplete(buffer_); + buffer_ = nullptr; + } + + update(); } QImage ViewFinder::getCurrentImage() diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 54c0fa9dd7a0..4d0622a8e4ea 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -36,6 +36,7 @@ public: int setFormat(const libcamera::PixelFormat &format, const QSize &size); void render(libcamera::FrameBuffer *buffer, MappedBuffer *map); + void stop(); QImage getCurrentImage(); @@ -52,6 +53,7 @@ private: libcamera::PixelFormat format_; QSize size_; + libcamera::FrameBuffer *buffer_; QImage image_; QMutex mutex_; /* Prevent concurrent access to image_ */ }; From patchwork Mon Mar 23 17:35:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3287 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 27FA562C9A for ; Mon, 23 Mar 2020 18:36:23 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C4E4EA31 for ; Mon, 23 Mar 2020 18:36:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984982; bh=Bk9RqVAYRV6bSXazONtXWPi5XHAba8loE+9oT3Xlh38=; h=From:To:Subject:Date:In-Reply-To:References:From; b=pHgxDY+EK1jPmK1DhaH3y+G9HqD+U+vCWihJRiU/slv60zxED7ID1UwQ24fObC6M3 imvZfnxVAB/WLqEMNoJmTiEdGrUf5TIuX4pKvlNeXDK+czUHTekclNaRE34Lb0LzV6 FW40HpYlkEPn2d9CqO99/aNwwSXexd+0BlO++NbA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:58 +0200 Message-Id: <20200323173559.21109-21-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 20/21] qcam: viewfinder: Display icon when stopping capture X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 When stopping capture, display an icon instead of the last frame. This is required to be able to release the last buffer when the viewfinder operators in zero-copy mode. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Don't use QSize::shrunkBy() which was introduced in Qt 5.14 - Move stop() function to previous commit --- src/qcam/assets/feathericons/feathericons.qrc | 1 + src/qcam/viewfinder.cpp | 32 ++++++++++++++++++- src/qcam/viewfinder.h | 7 ++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc index 6ca3a846803c..c4eb7a0be688 100644 --- a/src/qcam/assets/feathericons/feathericons.qrc +++ b/src/qcam/assets/feathericons/feathericons.qrc @@ -1,5 +1,6 @@ +./camera-off.svg ./play-circle.svg ./save.svg ./stop-circle.svg diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 3f984efbf434..45e226b58135 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -20,6 +20,7 @@ ViewFinder::ViewFinder(QWidget *parent) : QWidget(parent), buffer_(nullptr) { + icon_ = QIcon(":camera-off.svg"); } ViewFinder::~ViewFinder() @@ -114,7 +115,36 @@ QImage ViewFinder::getCurrentImage() void ViewFinder::paintEvent(QPaintEvent *) { QPainter painter(this); - painter.drawImage(rect(), image_, image_.rect()); + + /* If we have an image, draw it. */ + if (!image_.isNull()) { + painter.drawImage(rect(), image_, image_.rect()); + return; + } + + /* + * Otherwise, draw the camera stopped icon. Render it to the pixmap if + * the size has changed. + */ + constexpr int margin = 20; + + if (vfSize_ != size() || pixmap_.isNull()) { + QSize vfSize = size() - QSize{ 2 * margin, 2 * margin }; + QSize pixmapSize{ 1, 1 }; + pixmapSize.scale(vfSize, Qt::KeepAspectRatio); + pixmap_ = icon_.pixmap(pixmapSize); + + vfSize_ = size(); + } + + QPoint point{ margin, margin }; + if (pixmap_.width() < width() - 2 * margin) + point.setX((width() - pixmap_.width()) / 2); + else + point.setY((height() - pixmap_.height()) / 2); + + painter.setBackgroundMode(Qt::OpaqueMode); + painter.drawPixmap(point, pixmap_); } QSize ViewFinder::sizeHint() const diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 4d0622a8e4ea..1a27f99ea202 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -53,6 +54,12 @@ private: libcamera::PixelFormat format_; QSize size_; + /* Camera stopped icon */ + QSize vfSize_; + QIcon icon_; + QPixmap pixmap_; + + /* Buffer and render image */ libcamera::FrameBuffer *buffer_; QImage image_; QMutex mutex_; /* Prevent concurrent access to image_ */ From patchwork Mon Mar 23 17:35:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3286 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 855BD62CD6 for ; Mon, 23 Mar 2020 18:36:23 +0100 (CET) Received: from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi [81.175.216.236]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 22D75308 for ; Mon, 23 Mar 2020 18:36:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584984983; bh=+qikXKyshxo/qTFBH5W/AsDuvSQNdfc4zbNVWdaLOl4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=I+xjZM23PqnTS0ToSde5nCw5ij6+q3pZf/KV4SbQi9+890/Pa78VFUfSCHgC4H+dH 1IrBTqdmozbTGSDIOxl9oI3YNsd43K1PZYXLYjTR3IvqU2FQRqmY6ZIonH4pQyiqBc g/pA8pktKCtKWLRj+VbfHdft1/cl/n+vmycOqkbI= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 19:35:59 +0200 Message-Id: <20200323173559.21109-22-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> References: <20200323173559.21109-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 21/21] qcam: viewfinder: Add support for more native formats X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 23 Mar 2020 17:36:26 -0000 Qt supports more 24-bit and 32-bit RGB formats for native painting. Disable the converter and create a QImage in the appropriate format. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- Changes since v1: - Rename formats to nativeFormats --- src/qcam/viewfinder.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 45e226b58135..5aa0daebfb2d 100644 --- a/src/qcam/viewfinder.cpp +++ b/src/qcam/viewfinder.cpp @@ -7,16 +7,26 @@ #include "viewfinder.h" +#include #include #include #include +#include #include #include #include #include "format_converter.h" +static const QMap nativeFormats{ + { DRM_FORMAT_ARGB8888, QImage::Format_RGB32 }, + { DRM_FORMAT_RGB888, QImage::Format_RGB888 }, +#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) + { DRM_FORMAT_BGR888, QImage::Format_BGR888 }, +#endif +}; + ViewFinder::ViewFinder(QWidget *parent) : QWidget(parent), buffer_(nullptr) { @@ -36,7 +46,7 @@ int ViewFinder::setFormat(const libcamera::PixelFormat &format, * If format conversion is needed, configure the converter and allocate * the destination image. */ - if (format != DRM_FORMAT_ARGB8888) { + if (!nativeFormats.contains(format)) { int ret = converter_.configure(format, size); if (ret < 0) return ret; @@ -64,7 +74,7 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) { QMutexLocker locker(&mutex_); - if (format_ == DRM_FORMAT_ARGB8888) { + if (nativeFormats.contains(format_)) { /* * If the frame format is identical to the display * format, create a QImage that references the frame @@ -76,7 +86,8 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) * computing it naively */ image_ = QImage(memory, size_.width(), size_.height(), - size / size_.height(), QImage::Format_RGB32); + size / size_.height(), + nativeFormats[format_]); std::swap(buffer, buffer_); } else { /*