[libcamera-devel] [PATCH 10/21] qcam: main_window: Document functions and reorganize member data
Kieran Bingham
kieran.bingham at ideasonboard.com
Mon Mar 23 16:49:10 CET 2020
Hi Laurent,
On 23/03/2020 14:21, Laurent Pinchart wrote:
> 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 <laurent.pinchart at ideasonboard.com>
Sure, ship it.
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> ---
> 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. */
Poh Tay Toe, Poe Tah Toe.
> QComboBox *cameraCombo = new QComboBox();
> connect(cameraCombo, QOverload<int>::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<unsigned int>(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<Camera> &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<std::string>(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<Stream *, FrameBuffer *> &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> camera_;
> FrameBufferAllocator *allocator_;
>
> - bool isCapturing_;
> std::unique_ptr<CameraConfiguration> config_;
> + std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
>
> - uint64_t lastBufferTime_;
> + /* Capture state, buffers queue and statistics */
> + bool isCapturing_;
> + QQueue<FrameBuffer *> doneQueue_;
> + QMutex mutex_; /* Protects doneQueue_ */
>
> + uint64_t lastBufferTime_;
> QElapsedTimer frameRateInterval_;
> uint32_t previousFrames_;
> uint32_t framesCaptured_;
> -
> - QMutex mutex_;
> - QQueue<FrameBuffer *> doneQueue_;
> -
> - QToolBar *toolbar_;
> - QAction *startStopAction_;
> - ViewFinder *viewfinder_;
> - std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
> };
>
> #endif /* __QCAM_MAIN_WINDOW__ */
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list