[libcamera-devel] [PATCH v7 6/8] qcam: CamSelectDialog: Add capture script button
Kieran Bingham
kieran.bingham at ideasonboard.com
Tue Aug 9 23:59:54 CEST 2022
Quoting Utkarsh Tiwari via libcamera-devel (2022-08-09 21:50:40)
> Implement an Capture Script in CamSelectDialog button which would allow
> the user to open a Capture Script (*.yaml).
> This button has three states :
> - Open Capture Script
> - Loaded
> - Stop the execution of current capture script
>
> When being clicked in open state, present them with a QFileDialog to
"When clicked in an open state, present the user with" ...
> allow user to select a single file. When the script is loaded the button
"to allow selecting a single file." ...
> displays "Loaded", the script has not been verified yet. Verifying the
> script and executing it happens after user presses Ok.
>
> Introduce a queueCount_ to keep track of the requests queued.
>
> When stopping the execution of the capture script the queueCount_ is not
> reseted and the capture is continues as it is (i.e it is not stopped or
s/reseted/reset/
s/capture is continues/capture continues/
> restarted).
>
> Requests are queued with any controls the script matching the current
> queueCount_.
>
> Signed-off-by: Utkarsh Tiwari <utkarsh02t at gmail.com>
> ---
> Difference:
> 1. override accept and reject to handle capture script paths.
> src/qcam/cam_select_dialog.cpp | 68 ++++++++++++++++++++++++++++++++--
> src/qcam/cam_select_dialog.h | 21 ++++++++++-
> src/qcam/main_window.cpp | 59 ++++++++++++++++++++++++++++-
> src/qcam/main_window.h | 7 ++++
> src/qcam/meson.build | 2 +
> 5 files changed, 152 insertions(+), 5 deletions(-)
>
> diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp
> index f97ad6eb..f3df9970 100644
> --- a/src/qcam/cam_select_dialog.cpp
> +++ b/src/qcam/cam_select_dialog.cpp
> @@ -20,8 +20,8 @@
> #include <QString>
>
> CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManager,
> - QWidget *parent)
> - : QDialog(parent), cm_(cameraManager)
> + bool isScriptRunning, QWidget *parent)
> + : QDialog(parent), cm_(cameraManager), isScriptRunning_(isScriptRunning)
> {
> /* Use a QFormLayout for the dialog. */
> QFormLayout *layout = new QFormLayout(this);
> @@ -39,6 +39,16 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag
> connect(cameraIdComboBox_, &QComboBox::currentTextChanged,
> this, &CameraSelectorDialog::handleCameraChange);
>
> + captureScriptButton_ = new QPushButton;
> + connect(captureScriptButton_, &QPushButton::clicked,
> + this, &CameraSelectorDialog::handleCaptureScriptButton);
> +
> + /* Display the action that would be performed when button is clicked. */
> + if (isScriptRunning_)
> + captureScriptButton_->setText("Stop");
> + else
> + captureScriptButton_->setText("Open");
> +
> /* Setup the QDialogButton Box */
> QDialogButtonBox *buttonBox =
> new QDialogButtonBox(QDialogButtonBox::Ok |
> @@ -50,10 +60,10 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag
> this, &QDialog::reject);
>
> /* Set the layout. */
> -
> layout->addRow("Camera:", cameraIdComboBox_);
> layout->addRow("Location:", cameraLocation_);
> layout->addRow("Model:", cameraModel_);
> + layout->addRow("Capture Script:", captureScriptButton_);
> layout->addWidget(buttonBox);
> }
>
> @@ -62,6 +72,11 @@ std::string CameraSelectorDialog::getCameraId()
> return cameraIdComboBox_->currentText().toStdString();
> }
>
> +std::string CameraSelectorDialog::getCaptureScript()
> +{
> + return scriptPath_;
> +}
> +
> /* Hotplug / Unplug Support. */
> void CameraSelectorDialog::cameraAdded(libcamera::Camera *camera)
> {
> @@ -115,3 +130,50 @@ void CameraSelectorDialog::updateCamInfo(const std::shared_ptr<libcamera::Camera
>
> cameraModel_->setText(QString::fromStdString(model));
> }
> +
> +/* Capture script support. */
> +void CameraSelectorDialog::handleCaptureScriptButton()
> +{
> + if (isScriptRunning_) {
> + Q_EMIT stopCaptureScript();
> + isScriptRunning_ = false;
> + captureScriptButton_->setText("Open");
> + } else {
> + selectedScriptPath_ = QFileDialog::getOpenFileName(this,
> + "Run Capture Script", QDir::currentPath(),
> + "Capture Script (*.yaml)")
> + .toStdString();
> +
> + if (!selectedScriptPath_.empty())
> + captureScriptButton_->setText("Loaded");
> + else
> + captureScriptButton_->setText("Open");
> + }
> +}
> +
> +void CameraSelectorDialog::accept()
> +{
> + scriptPath_ = selectedScriptPath_;
> + QDialog::accept();
> +}
> +
> +void CameraSelectorDialog::reject()
> +{
> + if (isScriptRunning_)
> + selectedScriptPath_ = scriptPath_;
What is this for ?
> + QDialog::reject();
> +}
> +
> +void CameraSelectorDialog::informScriptReset()
> +{
> + isScriptRunning_ = false;
> + scriptPath_.clear();
> + captureScriptButton_->setText("Open");
> +}
> +
> +void CameraSelectorDialog::informScriptRunning(std::string scriptPath)
> +{
> + isScriptRunning_ = true;
> + scriptPath_ = scriptPath;
> + captureScriptButton_->setText("Stop");
> +}
> diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h
> index 359df811..56d90596 100644
> --- a/src/qcam/cam_select_dialog.h
> +++ b/src/qcam/cam_select_dialog.h
> @@ -17,8 +17,10 @@
> #include <QComboBox>
> #include <QDialog>
> #include <QDialogButtonBox>
> +#include <QFileDialog>
> #include <QFormLayout>
> #include <QLabel>
> +#include <QPushButton>
> #include <QString>
>
> class CameraSelectorDialog : public QDialog
> @@ -26,12 +28,14 @@ class CameraSelectorDialog : public QDialog
> Q_OBJECT
> public:
> CameraSelectorDialog(libcamera::CameraManager *cameraManager,
> - QWidget *parent);
> + bool isScriptRunning, QWidget *parent);
>
> ~CameraSelectorDialog() = default;
>
> std::string getCameraId();
>
> + std::string getCaptureScript();
> +
> /* Hotplug / Unplug Support. */
> void cameraAdded(libcamera::Camera *camera);
>
> @@ -41,11 +45,26 @@ public:
> void updateCamInfo(const std::shared_ptr<libcamera::Camera> &camera);
> void handleCameraChange();
>
> + /* Capture script support. */
> + void handleCaptureScriptButton();
> + void informScriptReset();
> + void informScriptRunning(std::string scriptPath);
> + void accept() override;
> + void reject() override;
> +
> +Q_SIGNALS:
> + void stopCaptureScript();
> +
> private:
> libcamera::CameraManager *cm_;
>
> + bool isScriptRunning_;
> + std::string scriptPath_;
> + std::string selectedScriptPath_;
> +
> /* UI elements. */
> QComboBox *cameraIdComboBox_;
> QLabel *cameraLocation_;
> QLabel *cameraModel_;
> + QPushButton *captureScriptButton_;
> };
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index 3feabcff..d73fb42a 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -9,6 +9,7 @@
>
> #include <assert.h>
> #include <iomanip>
> +#include <memory>
> #include <string>
>
> #include <libcamera/camera_manager.h>
> @@ -19,6 +20,7 @@
> #include <QFileDialog>
> #include <QImage>
> #include <QImageWriter>
> +#include <QMessageBox>
> #include <QMutexLocker>
> #include <QStandardPaths>
> #include <QStringList>
> @@ -151,6 +153,9 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
> return;
> }
>
> + /* Start capture script. */
> + loadCaptureScript();
> +
> startStopAction_->setChecked(true);
> }
>
> @@ -289,10 +294,53 @@ void MainWindow::switchCamera()
> startStopAction_->setChecked(true);
> }
>
> +void MainWindow::stopCaptureScript()
> +{
> + if (script_) {
> + script_.reset();
> + cameraSelectorDialog_->informScriptReset();
> + }
> +}
> +
> +void MainWindow::loadCaptureScript()
> +{
> + if (scriptPath_.empty() || camera_ == nullptr)
> + return;
> +
> + script_ = std::make_unique<CaptureScript>(camera_, scriptPath_);
> +
> + /*
> + * If we are already capturing, stop so we don't have stuck image
> + * in viewfinder.
> + */
> + bool wasCapturing = isCapturing_;
> + if (isCapturing_)
> + toggleCapture(false);
> +
> + if (!script_->valid()) {
> + script_.reset();
> + cameraSelectorDialog_->informScriptReset();
> +
> + QMessageBox::critical(this, "Invalid Script",
> + "Couldn't load the capture script");
> +
> + } else
> + cameraSelectorDialog_->informScriptRunning(scriptPath_);
> +
> + /* Start capture again if we were capturing before. */
> + if (wasCapturing)
> + toggleCapture(true);
> +}
> +
> std::string MainWindow::chooseCamera()
> {
> + bool scriptRunning = script_ != nullptr;
> +
> /* Construct the selection dialog, unconditionally. */
> - cameraSelectorDialog_ = new CameraSelectorDialog(cm_, this);
> + cameraSelectorDialog_ = new CameraSelectorDialog(cm_, scriptRunning, this);
> +
> + connect(cameraSelectorDialog_, &CameraSelectorDialog::stopCaptureScript,
> + this, &MainWindow::stopCaptureScript);
I fear that creating a new dialog box every time we choose a camera
means that every call here leaks at least a CameraSelectorDialog
allocation, *and* because we're connecting more signals - we're going to
end up with duplicted signals?
>
> /*
> * Use the camera specified on the command line, if any, or display the
> @@ -305,6 +353,9 @@ std::string MainWindow::chooseCamera()
> std::string cameraId = cameraSelectorDialog_->getCameraId();
> cameraSelectButton_->setText(QString::fromStdString(cameraId));
>
> + scriptPath_ = cameraSelectorDialog_->getCaptureScript();
> + loadCaptureScript();
> +
> return cameraId;
> } else
> return std::string();
> @@ -502,6 +553,7 @@ int MainWindow::startCapture()
> previousFrames_ = 0;
> framesCaptured_ = 0;
> lastBufferTime_ = 0;
> + queueCount_ = 0;
>
> ret = camera_->start();
> if (ret) {
> @@ -779,5 +831,10 @@ void MainWindow::renderComplete(FrameBuffer *buffer)
>
> int MainWindow::queueRequest(Request *request)
> {
> + if (script_)
> + request->controls() = script_->frameControls(queueCount_);
> +
> + queueCount_++;
> +
> return camera_->queueRequest(request);
> }
> diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
> index bd6f0172..887f1db1 100644
> --- a/src/qcam/main_window.h
> +++ b/src/qcam/main_window.h
> @@ -28,6 +28,7 @@
> #include <QQueue>
> #include <QTimer>
>
> +#include "../cam/capture_script.h"
> #include "../cam/stream_options.h"
>
> #include "cam_select_dialog.h"
> @@ -90,6 +91,9 @@ private:
> void processHotplug(HotplugEvent *e);
> void processViewfinder(libcamera::FrameBuffer *buffer);
>
> + void loadCaptureScript();
> + void stopCaptureScript();
> +
> /* UI elements */
> QToolBar *toolbar_;
> QAction *startStopAction_;
> @@ -130,6 +134,9 @@ private:
> QElapsedTimer frameRateInterval_;
> uint32_t previousFrames_;
> uint32_t framesCaptured_;
> + uint32_t queueCount_;
>
> std::vector<std::unique_ptr<libcamera::Request>> requests_;
> + std::unique_ptr<CaptureScript> script_;
> + std::string scriptPath_;
> };
> diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> index 61861ea6..70a18d7e 100644
> --- a/src/qcam/meson.build
> +++ b/src/qcam/meson.build
> @@ -15,6 +15,7 @@ endif
> qcam_enabled = true
>
> qcam_sources = files([
> + '../cam/capture_script.cpp',
> '../cam/image.cpp',
> '../cam/options.cpp',
> '../cam/stream_options.cpp',
> @@ -39,6 +40,7 @@ qcam_resources = files([
> qcam_deps = [
> libatomic,
> libcamera_public,
> + libyaml,
> qt5_dep,
> ]
>
> --
> 2.25.1
>
More information about the libcamera-devel
mailing list