[libcamera-devel] [PATCH v9 6/7] qcam: CamSelectDialog: Add capture script button
Utkarsh Tiwari
utkarsh02t at gmail.com
Wed Aug 31 07:49:37 CEST 2022
Display a QLabel which is readonly, and displays the currently
selected capture script. The tooltip of the QLabel displays the file
path of the script.
Implement a capture script button which is a QToolButton which when
clicked opens a QFileDialog this allows to select a capture script
(*.yaml) file.
Next to the capture scipt button, show a QToolButton which stops the
capture script.
If an invalid script has been selected show a QMesssageBox::critical and
continue with the capture's previous state.
Introduce a queueCount_ to keep track of the requests queued.
When stopping the execution of the capture script the queueCount_ is not
reset and the capture continues as it is (i.e it is not stopped or
restarted).
Requests are queued with any controls the script matching the current
queueCount_.
---
Differnce from v8:
1. Now display a QLabel with the fileName and filePath with button
on the side.
2. infromScriptReset() informScriptRunning() are removed
3. Local script makes handling of invalid scripts easy.
src/qcam/assets/feathericons/feathericons.qrc | 2 +
src/qcam/cam_select_dialog.cpp | 88 ++++++++++++++++++-
src/qcam/cam_select_dialog.h | 20 ++++-
src/qcam/main_window.cpp | 67 +++++++++++++-
src/qcam/main_window.h | 7 ++
src/qcam/meson.build | 2 +
6 files changed, 181 insertions(+), 5 deletions(-)
diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
index c5302040..0ea0c2d5 100644
--- a/src/qcam/assets/feathericons/feathericons.qrc
+++ b/src/qcam/assets/feathericons/feathericons.qrc
@@ -3,7 +3,9 @@
<qresource>
<file>aperture.svg</file>
<file>camera-off.svg</file>
+ <file>delete.svg</file>
<file>play-circle.svg</file>
+ <file>upload.svg</file>
<file>save.svg</file>
<file>stop-circle.svg</file>
<file>x-circle.svg</file>
diff --git a/src/qcam/cam_select_dialog.cpp b/src/qcam/cam_select_dialog.cpp
index 6543228a..99405cc1 100644
--- a/src/qcam/cam_select_dialog.cpp
+++ b/src/qcam/cam_select_dialog.cpp
@@ -14,13 +14,18 @@
#include <QComboBox>
#include <QDialogButtonBox>
+#include <QFileDialog>
#include <QFormLayout>
+#include <QHBoxLayout>
+#include <QIcon>
#include <QLabel>
#include <QString>
+#include <QToolButton>
+#include <QWidget>
CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManager,
- QWidget *parent)
- : QDialog(parent), cm_(cameraManager)
+ std::string scriptPath, QWidget *parent)
+ : QDialog(parent), cm_(cameraManager), scriptPath_(scriptPath)
{
/* Use a QFormLayout for the dialog. */
QFormLayout *layout = new QFormLayout(this);
@@ -38,6 +43,41 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag
connect(cameraIdComboBox_, &QComboBox::currentTextChanged,
this, &CameraSelectorDialog::updateCamInfo);
+ /* Set capture script selection / removal button. */
+ QWidget *captureWidget = new QWidget(this);
+ QHBoxLayout *captureLayout = new QHBoxLayout(captureWidget);
+
+ scriptFileLine_ = new QLabel;
+ scriptFileLine_->setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
+
+ chooseCaptureScriptButton_ = new QToolButton;
+ chooseCaptureScriptButton_->setIcon(QIcon::fromTheme("document-open",
+ QIcon(":upload.svg")));
+ chooseCaptureScriptButton_->setStyleSheet("border:none");
+ connect(chooseCaptureScriptButton_, &QToolButton::clicked,
+ this, &CameraSelectorDialog::selectCaptureScript);
+
+ QToolButton *stopCaptureScriptButton = new QToolButton;
+ stopCaptureScriptButton->setIcon(QIcon::fromTheme("edit-clear",
+ QIcon(":delete.svg")));
+ stopCaptureScriptButton->setStyleSheet("border:node;");
+ connect(stopCaptureScriptButton, &QToolButton::clicked,
+ this, &CameraSelectorDialog::resetCaptureScript);
+
+ captureLayout->addWidget(scriptFileLine_);
+ captureLayout->addWidget(chooseCaptureScriptButton_);
+ captureLayout->addWidget(stopCaptureScriptButton);
+ captureLayout->setMargin(0);
+
+ /* Set the file name of the capture script. */
+ if (scriptPath_.empty()) {
+ scriptFileLine_->setText("No File Selected");
+ } else {
+ scriptFileInfo_.setFile(QString::fromStdString(scriptPath_));
+ scriptFileLine_->setText(scriptFileInfo_.fileName());
+ scriptFileLine_->setToolTip(scriptFileInfo_.filePath());
+ }
+
/* Setup the QDialogButton Box */
QDialogButtonBox *buttonBox =
new QDialogButtonBox(QDialogButtonBox::Ok |
@@ -52,6 +92,7 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag
layout->addRow("Camera:", cameraIdComboBox_);
layout->addRow("Location:", cameraLocation_);
layout->addRow("Model:", cameraModel_);
+ layout->addRow("Capture Script:", captureWidget);
layout->addWidget(buttonBox);
}
@@ -110,3 +151,46 @@ void CameraSelectorDialog::updateCamInfo(QString cameraId)
cameraModel_->setText(QString::fromStdString(model));
}
+
+/* Capture script support. */
+void CameraSelectorDialog::selectCaptureScript()
+{
+ selectedScriptPath_ = QFileDialog::getOpenFileName(this,
+ "Run Capture Script", QDir::currentPath(),
+ "Capture Script (*.yaml)")
+ .toStdString();
+
+ if (!selectedScriptPath_.empty()) {
+ scriptFileInfo_.setFile(QString::fromStdString(selectedScriptPath_));
+ scriptFileLine_->setText(scriptFileInfo_.fileName());
+ scriptFileLine_->setToolTip(scriptFileInfo_.filePath());
+ } else {
+ selectedScriptPath_ = scriptPath_;
+ }
+}
+
+void CameraSelectorDialog::resetCaptureScript()
+{
+ Q_EMIT stopCaptureScript();
+ scriptPath_.clear();
+ selectedScriptPath_.clear();
+ scriptFileLine_->setText("No File Selected");
+}
+
+void CameraSelectorDialog::accept()
+{
+ scriptPath_ = selectedScriptPath_;
+ QDialog::accept();
+}
+
+void CameraSelectorDialog::reject()
+{
+ if (scriptPath_.empty()) {
+ scriptFileLine_->setText("No File Selected");
+ } else {
+ scriptFileInfo_.setFile(QString::fromStdString(scriptPath_));
+ scriptFileLine_->setText(scriptFileInfo_.fileName());
+ scriptFileLine_->setToolTip(scriptFileInfo_.filePath());
+ }
+ QDialog::reject();
+}
diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h
index c91b7ebe..377faebc 100644
--- a/src/qcam/cam_select_dialog.h
+++ b/src/qcam/cam_select_dialog.h
@@ -15,21 +15,24 @@
#include <libcamera/property_ids.h>
#include <QDialog>
+#include <QFileInfo>
#include <QString>
class QComboBox;
class QLabel;
+class QToolButton;
class CameraSelectorDialog : public QDialog
{
Q_OBJECT
public:
CameraSelectorDialog(libcamera::CameraManager *cameraManager,
- QWidget *parent);
+ std::string scriptPath, QWidget *parent);
~CameraSelectorDialog();
std::string getCameraId();
+ std::string getCaptureScript() { return scriptPath_; };
/* Hotplug / Unplug Support. */
void addCamera(QString cameraId);
@@ -38,11 +41,26 @@ public:
/* Camera Information */
void updateCamInfo(QString cameraId);
+ /* Capture script support. */
+ void selectCaptureScript();
+ void resetCaptureScript();
+
+ void accept() override;
+ void reject() override;
+
+Q_SIGNALS:
+ void stopCaptureScript();
+
private:
libcamera::CameraManager *cm_;
+ std::string scriptPath_;
+ std::string selectedScriptPath_;
+ QFileInfo scriptFileInfo_;
/* UI elements. */
QComboBox *cameraIdComboBox_;
QLabel *cameraLocation_;
QLabel *cameraModel_;
+ QLabel *scriptFileLine_;
+ QToolButton *chooseCaptureScriptButton_;
};
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 2a9ca830..af992b94 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>
@@ -18,6 +19,7 @@
#include <QFileDialog>
#include <QImage>
#include <QImageWriter>
+#include <QMessageBox>
#include <QMutexLocker>
#include <QStandardPaths>
#include <QStringList>
@@ -143,7 +145,9 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
cm_->cameraAdded.connect(this, &MainWindow::addCamera);
cm_->cameraRemoved.connect(this, &MainWindow::removeCamera);
- cameraSelectorDialog_ = new CameraSelectorDialog(cm_, this);
+ cameraSelectorDialog_ = new CameraSelectorDialog(cm_, scriptPath_, this);
+ connect(cameraSelectorDialog_, &CameraSelectorDialog::stopCaptureScript,
+ this, &MainWindow::stopCaptureScript);
/* Open the camera and start capture. */
ret = openCamera();
@@ -152,6 +156,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
return;
}
+ /* Start capture script. */
+ if (!scriptPath_.empty())
+ ret = loadCaptureScript();
+
startStopAction_->setChecked(true);
}
@@ -266,8 +274,11 @@ void MainWindow::switchCamera()
if (newCameraId.empty())
return;
- if (camera_ && newCameraId == camera_->id())
+ if (camera_ && newCameraId == camera_->id()) {
+ // When user opens camera selection dialog for CaptureScript selection
+ loadCaptureScript();
return;
+ }
const std::shared_ptr<Camera> &cam = cm_->get(newCameraId);
@@ -287,17 +298,63 @@ void MainWindow::switchCamera()
camera_->release();
camera_ = cam;
+ loadCaptureScript();
+
startStopAction_->setChecked(true);
/* Display the current cameraId in the toolbar .*/
cameraSelectButton_->setText(QString::fromStdString(newCameraId));
}
+void MainWindow::stopCaptureScript()
+{
+ if (script_)
+ script_.reset();
+}
+/**
+ * \brief Loads and validates the current capture script
+ *
+ * returns -EINVAL on failure and 0 on success
+ */
+int MainWindow::loadCaptureScript()
+{
+ if (scriptPath_.empty() || camera_ == nullptr)
+ return -EINVAL;
+
+ auto script = std::make_unique<CaptureScript>(camera_, scriptPath_);
+
+ if (!script->valid()) {
+ script.reset();
+
+ QMessageBox::critical(this, "Invalid Script",
+ "Couldn't load the capture script");
+
+ return -EINVAL;
+ }
+
+ /*
+ * If we are already capturing, stop so we don't have stuck image
+ * in viewfinder.
+ */
+ bool wasCapturing = isCapturing_;
+ if (isCapturing_)
+ toggleCapture(false);
+
+ script_ = std::move(script);
+
+ /* Start capture again if we were capturing before. */
+ if (wasCapturing)
+ toggleCapture(true);
+ return 0;
+}
+
std::string MainWindow::chooseCamera()
{
if (cameraSelectorDialog_->exec() != QDialog::Accepted)
return std::string();
+ scriptPath_ = cameraSelectorDialog_->getCaptureScript();
+
return cameraSelectorDialog_->getCameraId();
}
@@ -499,6 +556,7 @@ int MainWindow::startCapture()
previousFrames_ = 0;
framesCaptured_ = 0;
lastBufferTime_ = 0;
+ queueCount_ = 0;
ret = camera_->start();
if (ret) {
@@ -777,5 +835,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 22c85247..7c877ae1 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -27,6 +27,7 @@
#include <QQueue>
#include <QTimer>
+#include "../cam/capture_script.h"
#include "../cam/stream_options.h"
#include "viewfinder.h"
@@ -89,6 +90,9 @@ private:
void processHotplug(HotplugEvent *e);
void processViewfinder(libcamera::FrameBuffer *buffer);
+ int loadCaptureScript();
+ void stopCaptureScript();
+
/* UI elements */
QToolBar *toolbar_;
QAction *startStopAction_;
@@ -129,6 +133,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.34.1
More information about the libcamera-devel
mailing list