From patchwork Mon Mar 23 14:21: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: 3244 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 B6E6C6041A for ; Mon, 23 Mar 2020 15:22: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 5724EA31 for ; Mon, 23 Mar 2020 15:22:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973338; bh=izU4WjE5TNQPEidrpNUe1+lyYISq/HVG9nGGsESm39U=; h=From:To:Subject:Date:In-Reply-To:References:From; b=NY8jDXIh36mjdCeRUOSVQbJB5/OxioLewFKUSm93wwN48SGtcDtH1d69A39H0NCNi XHrlDKiO7AeNGqSiKbdFUrPMxCpb/0d9C56LEvsujLmc81Aw8q2jbUlDZt5zXfTUll sPu5t7dHzpkjjJw0cTeToT2XPoucLNnmbHD5ElFk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:45 +0200 Message-Id: <20200323142205.28342-2-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:18 -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 14:21: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: 3245 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0ABE16041A for ; Mon, 23 Mar 2020 15:22: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 A82AC308 for ; Mon, 23 Mar 2020 15:22:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973338; bh=4XLUshCMNIt87XB720GbiwJWGezmI9nsCi4TKE0C6kU=; h=From:To:Subject:Date:In-Reply-To:References:From; b=CErJPVeoZzWA1TMEux6MpAnpnVD53E9OtbSYZmTSrcIUfYzog74xOVQiMsexUFQ1w K9AOm0Id/bSqKNWAsvCkN3xETyiOxL3pMY9p8SwGenPqrHHXCP3O0x1NFvfLpF75Sz j8Gzxq9jpSQToxj8olJXoVt8gFswR92xcd50MNyA= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:46 +0200 Message-Id: <20200323142205.28342-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:19 -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 14:21: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: 3246 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 67EB162BFC for ; Mon, 23 Mar 2020 15:22: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 050FFA31 for ; Mon, 23 Mar 2020 15:22:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973339; bh=U0Djti0LcolrGa3tTF/X08u2bDUuEifn5hJE0um57yM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=JQZALvUsCkxIiA1O6IhHDaUeMZ3ladEg9UweZZNZ9iQQoMybywBhIUBp1rKJ1Qda6 mlxArtc0e697hK2M+EIAaW3nAlox8aa6ixxXfY0I8ZNaWyGz9YfCU15HDjv3a47/XH rT7J3jvKVrXef3J0BVpsU4HGKYTzWpbqtw1CwfDk= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:47 +0200 Message-Id: <20200323142205.28342-4-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:19 -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 14:21: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: 3247 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AF04562BFC for ; Mon, 23 Mar 2020 15:22: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 57B72308 for ; Mon, 23 Mar 2020 15:22:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973339; bh=MqK7QUbiwoSiHIC626STnQgrKoRO1R9/LuHmJEjqzCw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Mkh9097dYn6fir5OUgoHxERp90pQBRb3DzIqLjZfbj1pePtF92Di1NMt4KyD49tNf WH4sOO3G8gtecSpwmvPYdyym0FpYWHwaq558kJrvHqh9F2CkYpvntqOV/yQQtD99Ry xieQabvpRzc/kpCJ8FJQMA9t2Q/H2qJoxdqn+gTQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:48 +0200 Message-Id: <20200323142205.28342-5-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:20 -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 14:21: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: 3248 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 19E0162BFC for ; Mon, 23 Mar 2020 15:22: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 AAD4DA31 for ; Mon, 23 Mar 2020 15:22:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973339; bh=ARN4LQviLZOyZ816TB8d6dQao3vjfBvauuJZHouvbvg=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Z7MNs+7tOoqRGOZCqJaTN2uCT0nxI+OersNVWgYzt22vcKp0ApO0BMaxE9vvYAnpB CFOcDnuy0RdqvVWLEVevYgnUVnkoqWN4g4IdvNyflc1w9rEfH8J2CUlxDj5jhAqEeT YCM5Q1hdDBMKKJtiPUJhnfjxPVFC+yYj+j/reQ68= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:49 +0200 Message-Id: <20200323142205.28342-6-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:22 -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 --- src/qcam/main_window.cpp | 54 +++++++++++++++++++++++++++++++++++++++- src/qcam/main_window.h | 8 ++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 354a53367d0f..afd8b9c413f5 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -19,6 +19,7 @@ #include #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,29 @@ 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 14:21: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: 3249 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 8684862C48 for ; Mon, 23 Mar 2020 15:22: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 08505308 for ; Mon, 23 Mar 2020 15:22:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973340; bh=eW09ti/wOhxVQFXKOBaWJE47HHMZe5xlSLIBrHdwJ54=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bk2E/Pt2chfQhtaqlLvos5gXMF9U77P2wW+ijU3Fjghs5yGVqmSvAX7FbgD3IV3VP fozMLV0wAYlbsULOj9JC60Z3XLLj/Sv0qvg3mYIx1Jnv5uyzNU5aFSLEBbFAFLFCjv Y4IQBCRBzxTcx6K9HHDD7pJso1Aess+PFi+PnJ2k= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:50 +0200 Message-Id: <20200323142205.28342-7-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:24 -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 --- src/qcam/main_window.cpp | 30 ++++++++++++++++++++---------- src/qcam/main_window.h | 9 ++++++--- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index afd8b9c413f5..86f92360a1a9 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -63,11 +63,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 +112,10 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); - action = toolbar_->addAction(QIcon(":play-circle.svg"), "start"); - connect(action, &QAction::triggered, this, &MainWindow::startCapture); - - action = toolbar_->addAction(QIcon(":stop-circle.svg"), "stop"); - connect(action, &QAction::triggered, this, &MainWindow::stopCapture); + action = toolbar_->addAction(QIcon(":play-circle.svg"), "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 +157,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 +215,17 @@ int MainWindow::openCamera() return 0; } +void MainWindow::toggleCapture(bool start) +{ + if (start) { + startCapture(); + startStopAction_->setText("Stop Capture"); + } else { + stopCapture(); + startStopAction_->setText("Start Capture"); + } +} + int MainWindow::startCapture() { int ret; @@ -322,6 +331,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..3d8d02b44696 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -26,6 +26,7 @@ using namespace libcamera; +class QAction; class ViewFinder; enum { @@ -49,9 +50,7 @@ private Q_SLOTS: void updateTitle(); void switchCamera(int index); - - int startCapture(); - void stopCapture(); + void toggleCapture(bool start); void saveImageAs(); @@ -60,6 +59,9 @@ private: std::string chooseCamera(); int openCamera(); + int startCapture(); + void stopCapture(); + void requestComplete(Request *request); void processCapture(); int display(FrameBuffer *buffer); @@ -87,6 +89,7 @@ private: QQueue doneQueue_; QToolBar *toolbar_; + QAction *startStopAction_; ViewFinder *viewfinder_; std::map> mappedBuffers_; }; From patchwork Mon Mar 23 14:21: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: 3250 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CCFC962C50 for ; Mon, 23 Mar 2020 15:22: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 59723A31 for ; Mon, 23 Mar 2020 15:22:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973340; bh=cVb52Stk9ppYJwFRDHb9aaavjPXSp25SbMpq6eRtJAE=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bX44HsgTSirrGPLg/BKJ4aag4pFdw6H9rlp+lqDzR5lbGrcaZXDpg28RG73bqJusL yaoXU9EIGzJdHk2xUoy9r2dQ2PDzhnnPrhzw7zJTj0i0DW66dj/SCkJQCczY7WLEAg Ietjfbzcioyx2cvnkt7mbfr2EMBi31/CuEf4U3lE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:51 +0200 Message-Id: <20200323142205.28342-8-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:24 -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 --- src/qcam/main_window.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 86f92360a1a9..14baf7ec4c2e 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -97,7 +97,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. */ @@ -112,12 +114,16 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); - action = toolbar_->addAction(QIcon(":play-circle.svg"), "Start Capture"); + action = toolbar_->addAction(QIcon::fromTheme("media-playback-start", + QIcon(":play-circle.svg")), + "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 14:21: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: 3251 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 2629262C5A for ; Mon, 23 Mar 2020 15:22: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 AA55E308 for ; Mon, 23 Mar 2020 15:22:20 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973340; bh=fUPxOR4GjouFYTsBGilSKWyclN8t7TYqptysdhj8FHk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=u31SKwUMQa28B1EHDaMIcW8/GQunDChnkdVijY+7SSAynvkXLGAP6TWLv8cOnNrL2 3ZY2QVem1dWBkHBcb30owlhB/1AnUhk+3lXqe8WNCU9MknucK4dXifRUteudGG4T5f y+CbR9S58Ms45ye3j36BQ6KlZrfqPO0MvsTHrhD0= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:52 +0200 Message-Id: <20200323142205.28342-9-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:24 -0000 Allow triggering toolbar actions with keyboard shortcuts. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham --- 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 14baf7ec4c2e..18aae07ffce7 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -100,6 +100,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. */ @@ -118,12 +119,14 @@ int MainWindow::createToolbars() QIcon(":play-circle.svg")), "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(Qt::CTRL | Qt::Key_S); connect(action, &QAction::triggered, this, &MainWindow::saveImageAs); return 0; From patchwork Mon Mar 23 14:21: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: 3252 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 74F4B62C68 for ; Mon, 23 Mar 2020 15:22: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 0F99DA31 for ; Mon, 23 Mar 2020 15:22:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973341; bh=9klAwUZMv+hh1pYubVMeghSnO3MNPDsYBfzap4LhRVc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=ljqJOrHoLO44nV7lRkWs8pI7VTjtfr+EZR7zqpw7A0uRjsVR2jrafub7Mm9Kk/WsR ZitI8neap6fmuMYj3yAx3d1GT6LSaXUPUelqqBqwrZAOIP/IVrJEq2wGPQ0ATzapvm 8MQUvkaLS9qtexFFPA7RvsoEb68bK1dPtu4J3Bjc= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:53 +0200 Message-Id: <20200323142205.28342-10-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:24 -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 18aae07ffce7..7aaa73e9a709 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -406,9 +406,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 14:21: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: 3253 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C18B062C22 for ; Mon, 23 Mar 2020 15:22: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 63651308 for ; Mon, 23 Mar 2020 15:22:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973341; bh=mdukGe9jiXqn/6rO4HZjMRjti0q8kRW7aHP1MeueCPQ=; h=From:To:Subject:Date:In-Reply-To:References:From; b=T9XABiXCUdB44Ru4mNg8JBfF057TO2VIphwsj9aRfs8YLBMic4JNuutappZHa7f9a zezc9KmU+2uMRzChrbJw24ALUI40amaLGwsZD0CUlezhz2qYDWERC+fsHLtP51datz OiXeup6KNxDVqdkLgouc3aMurxHUBhazcKnLi68A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:54 +0200 Message-Id: <20200323142205.28342-11-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:25 -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 7aaa73e9a709..21a8fcfe711d 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -32,6 +32,9 @@ using namespace libcamera; +/** + * \brief Custom QEvent to signal capture completion + */ class CaptureEvent : public QEvent { public: @@ -52,6 +55,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()); @@ -62,6 +69,7 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) setCentralWidget(viewfinder_); adjustSize(); + /* Open the camera and start capture. */ ret = openCamera(); if (ret < 0) quit(); @@ -97,13 +105,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); @@ -115,6 +124,7 @@ int MainWindow::createToolbars() toolbar_->addSeparator(); + /* Start/Stop action. */ action = toolbar_->addAction(QIcon::fromTheme("media-playback-start", QIcon(":play-circle.svg")), "Start Capture"); @@ -123,6 +133,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..."); @@ -140,6 +151,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; @@ -151,8 +163,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; @@ -166,6 +183,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(); @@ -179,9 +200,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())); @@ -198,6 +221,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 @@ -206,6 +233,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" @@ -224,6 +252,10 @@ int MainWindow::openCamera() return 0; } +/* ----------------------------------------------------------------------------- + * Capture Start & Stop + */ + void MainWindow::toggleCapture(bool start) { if (start) { @@ -235,10 +267,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); @@ -275,6 +313,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)); @@ -285,6 +324,7 @@ int MainWindow::startCapture() adjustSize(); + /* Allocate buffers and requests. */ allocator_ = new FrameBufferAllocator(camera_); ret = allocator_->allocate(stream); if (ret < 0) { @@ -317,6 +357,7 @@ int MainWindow::startCapture() std::make_pair(memory, plane.length); } + /* Start the title timer and the camera. */ titleTimer_.start(2000); frameRateInterval_.start(); previousFrames_ = 0; @@ -331,6 +372,7 @@ int MainWindow::startCapture() camera_->requestCompleted.connect(this, &MainWindow::requestComplete); + /* Queue all requests. */ for (Request *request : requests) { ret = camera_->queueRequest(request); if (ret < 0) { @@ -364,6 +406,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_) @@ -399,6 +447,10 @@ void MainWindow::stopCapture() setWindowTitle(title_); } +/* ----------------------------------------------------------------------------- + * Image Save + */ + void MainWindow::saveImageAs() { QImage image = viewfinder_->getCurrentImage(); @@ -414,11 +466,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; @@ -432,6 +493,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; { QMutexLocker locker(&mutex_); @@ -455,6 +521,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 3d8d02b44696..fcde88c14f77 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -56,6 +56,7 @@ private Q_SLOTS: private: int createToolbars(); + std::string chooseCamera(); int openCamera(); @@ -67,31 +68,34 @@ private: int display(FrameBuffer *buffer); void queueRequest(FrameBuffer *buffer); + /* UI elements */ + QToolBar *toolbar_; + QAction *startStopAction_; + ViewFinder *viewfinder_; + 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 14:21: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: 3254 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2229462C71 for ; Mon, 23 Mar 2020 15:22: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 B3549A31 for ; Mon, 23 Mar 2020 15:22:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973341; bh=qMp1dtH5+XIq/Ph1b6k5dHbDwOxCO31oqqAeiJO36xY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aL6e2riLZxaw9uzn9qw433zfI4ScvocdRyRgTxDnk3eSyBQhxFwdFbTYPcMol1V// AfgveyA1AWqpS7isIIinCpNJJsH8/1005VKiasslECYPQWF619f5to/qqVu3YA8Zuy PoVjaRxanFRY5tcaEj/gRFMtMGVWiHt0gdzzdC8A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:55 +0200 Message-Id: <20200323142205.28342-12-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:25 -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 21a8fcfe711d..ed8301502fb2 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -247,8 +247,6 @@ int MainWindow::openCamera() return -EBUSY; } - std::cout << "Using camera " << camera_->name() << std::endl; - return 0; } From patchwork Mon Mar 23 14:21: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: 3255 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7AE0462C6C for ; Mon, 23 Mar 2020 15:22: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 22800308 for ; Mon, 23 Mar 2020 15:22:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973342; bh=5qNNXD1UHaPqpKagR1Sa0dkIstLLCcE7R/J9hkKWElk=; h=From:To:Subject:Date:In-Reply-To:References:From; b=jB5q43YrbVKAqF/+XyT+6cg07Zw0z49TorTrh0B6NtS6Ot/XkXSY+LyTgphuQcLlS wINZQvFXQbAHDYwKjDzdYFWkXL81fiaQ8f/PS+8F6MomtNBuj2UjbGXGyyxQZiEWUb l2dmzzYYrPe/6qqvrE7MdFqgqfKi98ScMRvLgDBE= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:56 +0200 Message-Id: <20200323142205.28342-13-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:27 -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 --- 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 ed8301502fb2..184345b0e2a6 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 @@ -24,6 +23,7 @@ #include #include #include +#include #include #include @@ -177,11 +177,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 @@ -236,13 +236,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; } @@ -296,18 +295,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; } @@ -316,7 +315,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; } @@ -326,7 +325,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; } @@ -334,14 +333,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; } @@ -364,7 +363,7 @@ int MainWindow::startCapture() ret = camera_->start(); if (ret) { - std::cout << "Failed to start capture" << std::endl; + qInfo() << "Failed to start capture"; goto error; } @@ -374,7 +373,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; } } @@ -417,7 +416,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); @@ -513,11 +512,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 << Qt::reset + << "bytesused:" << metadata.planes[0].bytesused + << "timestamp:" << metadata.timestamp + << "fps:" << Qt::fixed << qSetRealNumberPrecision(2) << fps; /* Display the buffer and requeue it to the camera. */ display(buffer); @@ -542,7 +541,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 14:21: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: 3256 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id CD05E62C81 for ; Mon, 23 Mar 2020 15:22: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 7475C11FD for ; Mon, 23 Mar 2020 15:22:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973342; bh=B/vsZYfjryhoy/2Qt+BqsX/HD3nUquKpVeSN8UcJilY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=kPhScnLH+2GRBInMlTEncdK7i0Ok7uWQZD6ZCmHwQLPqa/DwdCarWmgVwFXaBDEmI Z7+zpbkkOwUhAr0TKVII47vqfph+Rt8UWSyYuBV7qW/T0D+75gqLioV80yk3cwxeJ/ IlhRbxATAHxtotGxJOmb/iwOBxuo8ydmyIRqhJ14= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:57 +0200 Message-Id: <20200323142205.28342-14-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 184345b0e2a6..c0feb91a6fb1 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -28,8 +28,6 @@ #include #include -#include "viewfinder.h" - using namespace libcamera; /** @@ -350,8 +348,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. */ @@ -391,9 +388,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(); @@ -421,9 +417,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(); @@ -529,10 +524,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 fcde88c14f77..0918ae5307d8 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -23,11 +23,11 @@ #include #include "../cam/options.h" +#include "viewfinder.h" using namespace libcamera; class QAction; -class ViewFinder; enum { OptCamera = 'c', @@ -85,7 +85,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 14:21: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: 3258 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 2E72862C43 for ; Mon, 23 Mar 2020 15:22: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 C690711FF for ; Mon, 23 Mar 2020 15:22:22 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973342; bh=73DZW4P+YJYZlOKUVjd+jGYbROnoK66kdikqo+TUOnc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=mW2mhxWfKFQCF2yz7EzQw9M70W2848oOfeIMz53lpCcvbU+vaLlGhr0dQgf6JQAXj ghUzyaDHxlKCaWvvvDBP5B5asVaVDrSvkkpD1P5QnC0ddUqEgAawwuT1oULNuTVQHT MVYJuhVzXpCBDlQ4kKOnNygLgwQh6CmUIzRPWCkw= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:58 +0200 Message-Id: <20200323142205.28342-15-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 c0feb91a6fb1..ad0d6bf4f3e5 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -519,14 +519,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 0918ae5307d8..03db761b58e4 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -65,7 +65,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 14:21: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: 3257 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7FD5362C3B for ; Mon, 23 Mar 2020 15:22: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 26DFCA31 for ; Mon, 23 Mar 2020 15:22:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973343; bh=H2RV0aIkeUXrQs9hzTcXOfgSZh5VT92rFw1DjR7uQ4g=; h=From:To:Subject:Date:In-Reply-To:References:From; b=QIBT6Uqq31XvnLaIOc7l4BW6HeALuyGUCbi//Id2YQWMLQQRP34MpqnE6/1eZ74Ig PIZ5zcE4JFioyImfC716QhnY2PGlw0H4EqMwhzaDvideVHcMPHHEIKSnSM4bmgfUYo OJpVlAwwAe1Uk8J0DgnFkqN5EA4vf1LecXMWOR2s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:21:59 +0200 Message-Id: <20200323142205.28342-16-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 ad0d6bf4f3e5..b68e171c5e01 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -64,6 +64,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(); @@ -513,15 +515,8 @@ void MainWindow::processCapture() << "timestamp:" << metadata.timestamp << "fps:" << Qt::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 03db761b58e4..1a2ccbd632b0 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -54,6 +54,8 @@ private Q_SLOTS: void saveImageAs(); + void queueRequest(FrameBuffer *buffer); + private: int createToolbars(); @@ -65,8 +67,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 14:22:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3259 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 E298A62C0E for ; Mon, 23 Mar 2020 15:22: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 79AC5308 for ; Mon, 23 Mar 2020 15:22:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973343; bh=SQpup1GvmigzZjuo3rNPDe1Qr86L5ep1mOvu+Nb2uWI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=v1dQ3Bo35QlkI8Iqqks0ZwxcN+tei7vhErzYOlWmx+bb8OG8rBOtkVbXrVOLF2JuX dIouXiej2LgpLoal3iLsk+r/kGSyj+JOsh0W1M7zsQN1zZB7zlp4Lhe2+25xja7aOV FBG94Sa44Duzb5NCB5u2lhTLLfiffDT/iexLduH4= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:00 +0200 Message-Id: <20200323142205.28342-17-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 14:22:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3260 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E44662C2B for ; Mon, 23 Mar 2020 15:22:24 +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 CB676A31 for ; Mon, 23 Mar 2020 15:22:23 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973344; bh=Q4UdvPFVtoI31fxhYLw/8tgK0UG7RFoZBa6ByFz7KL4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=wU3Hg419AdyGmX7X6APrCg1ywgXZeJNfB8GeXaUKrfL23J8gqjuhmG1SOiv4opeYK yaVMwycDB26bDQPoSoBg4SLDR5Ib0sGt2PA6TxVM+7lbZEflhNYXqOXoE6+HuwJ7IN NRdVIcIkSN0fXBVgIgOAEx62Cz1flJMGkn/VuvaQ= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:01 +0200 Message-Id: <20200323142205.28342-18-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 14:22:02 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3261 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 D51FA62C50 for ; Mon, 23 Mar 2020 15:22:24 +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 71EDB308 for ; Mon, 23 Mar 2020 15:22:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973344; bh=GzYLsl6eyJQx444+3aSSH2NunyC0uV2+2hTdSCK3uso=; h=From:To:Subject:Date:In-Reply-To:References:From; b=FByki+Ffp5tbYOpppDe1IpUbTeR5AC3ivNj11hHg+NkEEgRNrem/X78naqO0HYzp8 yh5PDeM5WtI/MbrDPPaH33VjibN1Q0ShTtRmOcD3A11Flr1trHqVgZYdgjxUTchblF 1FUt1IGXhxtYGPz/hmm3e5gALJicVrHB4mRChC0s= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:02 +0200 Message-Id: <20200323142205.28342-19-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 14:22:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3262 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3237162BE3 for ; Mon, 23 Mar 2020 15:22:25 +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 C69EEA31 for ; Mon, 23 Mar 2020 15:22:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973344; bh=USHdb1T8Gag3w1vXyqq1i+XOI3qduUfmdx1fQpIY3nA=; h=From:To:Subject:Date:In-Reply-To:References:From; b=qMRWzQAkJW8NtydIOAL9nE123VcCqrVCrCPZBqfCf4Pnxblu2SUTctZlGeW4bOmL+ OWmmhpgL9RDy5Dib/obJCKgPiWxeJDnfVWoG1u6TmI7gq1h/kuoAecp8tVBoyH0M86 BJlcn5nqZVaPfsFxkXHauP07HasJpPCKhc7iDAiU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:03 +0200 Message-Id: <20200323142205.28342-20-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:28 -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 is 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 --- src/qcam/viewfinder.cpp | 59 +++++++++++++++++++++++++++++------------ src/qcam/viewfinder.h | 1 + 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index 31b358da47dc..4c35659e24aa 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(); + + /* + * 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; - 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,36 @@ 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. + */ + 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); } QImage ViewFinder::getCurrentImage() diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h index 54c0fa9dd7a0..b5153160f70e 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -52,6 +52,7 @@ private: libcamera::PixelFormat format_; QSize size_; + libcamera::FrameBuffer *buffer_; QImage image_; QMutex mutex_; /* Prevent concurrent access to image_ */ }; From patchwork Mon Mar 23 14:22:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3263 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7BC5562C90 for ; Mon, 23 Mar 2020 15:22:25 +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 24E82308 for ; Mon, 23 Mar 2020 15:22:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973345; bh=wyjNonEx8jFAhcUPkQCz7VR6tyWoj/JFy6i6LmH5R/4=; h=From:To:Subject:Date:In-Reply-To:References:From; b=aijlcRlBowSDsgzIzjvngr6ShRm4KNGrsXsMWtPH7CBs1IpUPMbAAdGHRzhtUvJZe voEtgJvydhpXW1rbdN5wGTAtC0ys36AyK8nW3HEEeXIG188hPWKLkYsVL0849+Ca6U UugITBoFEHDYfawChO4XjG82BNlFjPcZnGcPER3A= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:04 +0200 Message-Id: <20200323142205.28342-21-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:29 -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 --- src/qcam/assets/feathericons/feathericons.qrc | 1 + src/qcam/main_window.cpp | 2 + src/qcam/viewfinder.cpp | 44 ++++++++++++++++++- src/qcam/viewfinder.h | 8 ++++ 4 files changed, 54 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/main_window.cpp b/src/qcam/main_window.cpp index b68e171c5e01..a77d10bb7076 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -412,6 +412,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 4c35659e24aa..a40b2b400daa 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() @@ -89,6 +90,18 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) renderComplete(buffer); } +void ViewFinder::stop() +{ + image_ = QImage(); + + if (buffer_) { + renderComplete(buffer_); + buffer_ = nullptr; + } + + update(); +} + QImage ViewFinder::getCurrentImage() { QMutexLocker locker(&mutex_); @@ -99,7 +112,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()) { + vfSize_ = size(); + + QSize pixmapSize{ 1, 1 }; + pixmapSize.scale(vfSize_.shrunkBy({ margin, margin, margin, margin }), + Qt::KeepAspectRatio); + pixmap_ = icon_.pixmap(pixmapSize); + } + + 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 b5153160f70e..1a27f99ea202 100644 --- a/src/qcam/viewfinder.h +++ b/src/qcam/viewfinder.h @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -36,6 +37,7 @@ public: int setFormat(const libcamera::PixelFormat &format, const QSize &size); void render(libcamera::FrameBuffer *buffer, MappedBuffer *map); + void stop(); QImage getCurrentImage(); @@ -52,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 14:22:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3264 Return-Path: Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D8F5962C71 for ; Mon, 23 Mar 2020 15:22:25 +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 75D48A31 for ; Mon, 23 Mar 2020 15:22:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1584973345; bh=rOfyiGMGR0blr8uRS6jkzcG5eo47D2SsKERhXaNODds=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Fs4oRh73j3RUuyoKFwvTeS3oQ1zNZKkEX8kJf1Or7cqTjMd7Wf1kbyCDdmxT8YCB8 NgBQc5uPqQ/0QVgOa777jHwd3roDJo0MKsVJpqNkTSiuDB5ayRpZM1xWqr3WU2szZh ioiroaSoTGvgwSak817xcOQVtXT4dOU5MCPAO6AU= From: Laurent Pinchart To: libcamera-devel@lists.libcamera.org Date: Mon, 23 Mar 2020 16:22:05 +0200 Message-Id: <20200323142205.28342-22-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> References: <20200323142205.28342-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 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 14:22:29 -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 --- src/qcam/viewfinder.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp index a40b2b400daa..e5cfa45fc662 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 formats{ + { 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 (!formats.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 (formats.contains(format_)) { /* * If the frame format is identical to the display * format, create a QImage that references the frame @@ -73,7 +83,7 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map) * released. */ image_ = QImage(memory, size_.width(), size_.height(), - size / size_.height(), QImage::Format_RGB32); + size / size_.height(), formats[format_]); std::swap(buffer, buffer_); } else { /*