[libcamera-devel,v6,2/4] qcam: CamSelectDialog: Add capture script button
diff mbox series

Message ID 20220807203204.152358-3-utkarsh02t@gmail.com
State Superseded
Headers show
Series
  • Introduce capture scripts to qcam
Related show

Commit Message

Utkarsh Tiwari Aug. 7, 2022, 8:32 p.m. UTC
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
allow user to select a single file. When the script is loaded the button
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
restarted).

Requests are queued with any controls the script matching the current
queueCount_.

Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
---
Difference from V1:
	No button on toolbar now it resides in CamSelectDialog
 src/qcam/cam_select_dialog.h | 47 +++++++++++++++++++++++++++++--
 src/qcam/main_window.cpp     | 54 +++++++++++++++++++++++++++++++++++-
 src/qcam/main_window.h       |  7 +++++
 src/qcam/meson.build         |  2 ++
 4 files changed, 107 insertions(+), 3 deletions(-)

Patch
diff mbox series

diff --git a/src/qcam/cam_select_dialog.h b/src/qcam/cam_select_dialog.h
index 6ba61cff..fc29b46a 100644
--- a/src/qcam/cam_select_dialog.h
+++ b/src/qcam/cam_select_dialog.h
@@ -18,16 +18,19 @@ 
 #include <QComboBox>
 #include <QDialog>
 #include <QDialogButtonBox>
+#include <QFileDialog>
 #include <QFormLayout>
 #include <QLabel>
+#include <QPushButton>
 #include <QString>
 
 class CamSelectDialog : public QDialog
 {
 	Q_OBJECT
 public:
-	CamSelectDialog(libcamera::CameraManager *cameraManager, QWidget *parent)
-		: QDialog(parent), cm_(cameraManager)
+	CamSelectDialog(libcamera::CameraManager *cameraManager,
+			bool isScriptRunning, QWidget *parent)
+		: QDialog(parent), cm_(cameraManager), isScriptRunning_(isScriptRunning)
 	{
 		/* Use a QFormLayout for the dialog. */
 		QFormLayout *camSelectDialogLayout = new QFormLayout(this);
@@ -48,6 +51,16 @@  public:
 					cameraIdComboBox_->currentText().toStdString()));
 			});
 
+		captureScriptButton_ = new QPushButton;
+		connect(captureScriptButton_, &QPushButton::clicked,
+			this, &CamSelectDialog::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 *dialogButtonBox =
 			new QDialogButtonBox(QDialogButtonBox::Ok |
@@ -62,6 +75,7 @@  public:
 		camSelectDialogLayout->addRow("Camera: ", cameraIdComboBox_);
 		camSelectDialogLayout->addRow("Location: ", cameraLocation_);
 		camSelectDialogLayout->addRow("Model: ", cameraModel_);
+		camSelectDialogLayout->addRow("Capture Script: ", captureScriptButton_);
 		camSelectDialogLayout->addWidget(dialogButtonBox);
 	}
 
@@ -72,6 +86,11 @@  public:
 		return cameraIdComboBox_->currentText().toStdString();
 	}
 
+	std::string getCaptureScript()
+	{
+		return scriptPath_;
+	}
+
 	/* Hotplug / Unplug Support. */
 	void cameraAdded(libcamera::Camera *camera)
 	{
@@ -122,11 +141,35 @@  public:
 			cameraModel_->setText(QString());
 	}
 
+	/* Capture script support. */
+	void handleCaptureScriptButton()
+	{
+		if (isScriptRunning_) {
+			Q_EMIT stopCaptureScript();
+			isScriptRunning_ = false;
+			captureScriptButton_->setText("Open");
+		} else {
+			scriptPath_ = QFileDialog::getOpenFileName(this, "Run Capture Script",
+								   QDir::currentPath(), "Capture Script (*.yaml)")
+					      .toStdString();
+
+			if (!scriptPath_.empty())
+				captureScriptButton_->setText("Loaded");
+		}
+	}
+
+Q_SIGNALS:
+	void stopCaptureScript();
+
 private:
 	libcamera::CameraManager *cm_;
 
+	bool isScriptRunning_;
+	std::string scriptPath_;
+
 	/* 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 549af024..e0219e5e 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);
 }
 
@@ -290,14 +295,55 @@  void MainWindow::switchCamera()
 	startStopAction_->setChecked(true);
 }
 
+void MainWindow::stopCaptureScript()
+{
+	if (script_) {
+		script_.reset();
+	}
+}
+
+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();
+
+		QMessageBox::critical(this, "Invalid Script",
+				      "Couldn't load the capture script");
+	}
+
+	/* Start capture again if we were capturing before. */
+	if (wasCapturing)
+		toggleCapture(true);
+}
+
 std::string MainWindow::chooseCamera()
 {
-	camSelectDialog_ = new CamSelectDialog(cm_, this);
+	bool scriptRunning = script_ != nullptr;
+	camSelectDialog_ = new CamSelectDialog(cm_, scriptRunning, this);
+
+	connect(camSelectDialog_, &CamSelectDialog::stopCaptureScript,
+		this, &MainWindow::stopCaptureScript);
 
 	if (camSelectDialog_->exec() == QDialog::Accepted) {
 		std::string cameraId = camSelectDialog_->getCameraId();
 		cameraSwitchButton_->setText(QString::fromStdString(cameraId));
 
+		scriptPath_ = camSelectDialog_->getCaptureScript();
+		loadCaptureScript();
+
 		return cameraId;
 	} else
 		return std::string();
@@ -504,6 +550,7 @@  int MainWindow::startCapture()
 	previousFrames_ = 0;
 	framesCaptured_ = 0;
 	lastBufferTime_ = 0;
+	queueCount_ = 0;
 
 	ret = camera_->start();
 	if (ret) {
@@ -783,5 +830,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 7982939e..01466e28 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 70615e92..80c97cc5 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',
@@ -38,6 +39,7 @@  qcam_resources = files([
 qcam_deps = [
     libatomic,
     libcamera_public,
+    libyaml,
     qt5_dep,
 ]