[libcamera-devel,v4,2/3] qcam: Add a GUI way to use capture script
diff mbox series

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

Commit Message

Utkarsh Tiwari July 3, 2022, 4:37 a.m. UTC
Implement an Open Capture Script button which would allow the user
to open a Capture Script (*.yaml).
This button has two states Open and Stop.

Open state allows user to load a capture script.
When clicked in open state present them with a QFileDialog
to allow user to select a single file.

Stop state stops the execution of the current capture script.

Introduce a queueCount_ to keep track of the requests queued.

When stopping the execution no count is reset and the
capture continues as it is.

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

Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---
 src/qcam/assets/feathericons/feathericons.qrc |  2 +
 src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
 src/qcam/main_window.h                        |  6 ++
 src/qcam/meson.build                          |  2 +
 4 files changed, 78 insertions(+)

Comments

Utkarsh Tiwari July 4, 2022, 3:46 p.m. UTC | #1
On Sun, Jul 3, 2022 at 12:37 PM Utkarsh Tiwari <utkarsh02t@gmail.com> wrote:

> Implement an Open Capture Script button which would allow the user
> to open a Capture Script (*.yaml).
> This button has two states Open and Stop.
>
> Open state allows user to load a capture script.
> When clicked in open state present them with a QFileDialog
> to allow user to select a single file.
>
> Stop state stops the execution of the current capture script.
>
> Introduce a queueCount_ to keep track of the requests queued.
>
> When stopping the execution no count is reset and the
> capture continues as it is.
>
> Requests are queued with any controls the script matching
> the current queueCount_
>
> Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
>  src/qcam/assets/feathericons/feathericons.qrc |  2 +
>  src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
>  src/qcam/main_window.h                        |  6 ++
>  src/qcam/meson.build                          |  2 +
>  4 files changed, 78 insertions(+)
>
> diff --git a/src/qcam/assets/feathericons/feathericons.qrc
> b/src/qcam/assets/feathericons/feathericons.qrc
> index c5302040..6b08395a 100644
> --- a/src/qcam/assets/feathericons/feathericons.qrc
> +++ b/src/qcam/assets/feathericons/feathericons.qrc
> @@ -3,9 +3,11 @@
>  <qresource>
>         <file>aperture.svg</file>
>         <file>camera-off.svg</file>
> +       <file>file.svg</file>
>         <file>play-circle.svg</file>
>         <file>save.svg</file>
>         <file>stop-circle.svg</file>
>         <file>x-circle.svg</file>
> +       <file>x-square.svg</file>
>  </qresource>
>  </RCC>
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index adeb3181..4fbaeccc 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -20,6 +20,7 @@
>  #include <QImage>
>  #include <QImageWriter>
>  #include <QInputDialog>
> +#include <QMessageBox>
>  #include <QMutexLocker>
>  #include <QStandardPaths>
>  #include <QStringList>
> @@ -232,6 +233,13 @@ int MainWindow::createToolbars()
>         saveRaw_ = action;
>  #endif
>
> +       /* Open Script... action. */
> +       action = toolbar_->addAction(QIcon::fromTheme("document-open",
> +                                                     QIcon(":file.svg")),
> +                                    "Open Capture Script");
> +       connect(action, &QAction::triggered, this,
> &MainWindow::chooseScript);
> +       scriptExecAction_ = action;
> +
>         return 0;
>  }
>
> @@ -255,6 +263,60 @@ void MainWindow::updateTitle()
>         setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + "
> fps");
>  }
>
> +/**
> + * \brief Load a capture script for handling the capture session.
> + *
> + * If already capturing, it would restart the capture.
> + */
> +void MainWindow::chooseScript()
> +{
> +       if (script_) {
> +               /*
> +                * This is the second valid press of load script button,
> +                * It indicates stopping, Stop and set button for new
> script.
> +                */
> +               script_.reset();
> +
>  scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
> +
>  QIcon(":file.svg")));
> +               scriptExecAction_->setText("Open Capture Script");
> +               return;
> +       }
> +
> +       QString scriptFile = QFileDialog::getOpenFileName(this, "Open
> Capture Script", QDir::currentPath(),
> +                                                         "Capture Script
> (*.yaml)");
> +       if (scriptFile.isEmpty())
> +               return;
> +
> +       /*
> +        * If we are already capturing,
> +        * stop so we don't have stuck image in viewfinder.
> +        */
> +       bool wasCapturing = isCapturing_;
> +       if (isCapturing_)
> +               toggleCapture(false);
> +
> +       script_ = std::make_unique<CaptureScript>(camera_,
> scriptFile.toStdString());
> +       if (!script_->valid()) {
> +               script_.reset();
> +               QMessageBox::critical(this, "Invalid Script",
> +                                             "Couldn't load the capture
> script");
>

This is wrongly indented  and should be

		QMessageBox::critical(this, "Invalid Script",
				      "Couldn't load the capture script");

+               if (wasCapturing)
> +                       toggleCapture(true);
> +               return;
> +       }
> +
> +       /*
> +        * Valid script verified
> +        * Set the button to indicate stopping availibility.
> +        */
> +       scriptExecAction_->setIcon(QIcon(":x-square.svg"));
> +       scriptExecAction_->setText("Stop Script execution");
> +
> +       /* Start capture again if we were capturing before. */
> +       if (wasCapturing)
> +               toggleCapture(true);
> +}
> +
>  /*
> -----------------------------------------------------------------------------
>   * Camera Selection
>   */
> @@ -510,6 +572,7 @@ int MainWindow::startCapture()
>         previousFrames_ = 0;
>         framesCaptured_ = 0;
>         lastBufferTime_ = 0;
> +       queueCount_ = 0;
>
>         ret = camera_->start();
>         if (ret) {
> @@ -789,5 +852,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 c3e4b665..2cdf7169 100644
> --- a/src/qcam/main_window.h
> +++ b/src/qcam/main_window.h
> @@ -26,6 +26,7 @@
>  #include <libcamera/request.h>
>  #include <libcamera/stream.h>
>
> +#include "../cam/capture_script.h"
>  #include "../cam/stream_options.h"
>  #include "viewfinder.h"
>
> @@ -86,11 +87,14 @@ private:
>         void processHotplug(HotplugEvent *e);
>         void processViewfinder(libcamera::FrameBuffer *buffer);
>
> +       void chooseScript();
> +
>         /* UI elements */
>         QToolBar *toolbar_;
>         QAction *startStopAction_;
>         QComboBox *cameraCombo_;
>         QAction *saveRaw_;
> +       QAction *scriptExecAction_;
>         ViewFinder *viewfinder_;
>
>         QIcon iconPlay_;
> @@ -124,6 +128,8 @@ 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_;
>  };
> diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> index c46f4631..67074252 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',
> @@ -37,6 +38,7 @@ qcam_resources = files([
>  qcam_deps = [
>      libatomic,
>      libcamera_public,
> +    libyaml,
>      qt5_dep,
>  ]
>
> --
> 2.25.1
>
>
Umang Jain July 25, 2022, 6:44 p.m. UTC | #2
Hi Utkarsh,

On 7/3/22 10:07, Utkarsh Tiwari via libcamera-devel wrote:
> Implement an Open Capture Script button which would allow the user
> to open a Capture Script (*.yaml).
> This button has two states Open and Stop.
>
> Open state allows user to load a capture script.
> When clicked in open state present them with a QFileDialog
> to allow user to select a single file.
>
> Stop state stops the execution of the current capture script.
>
> Introduce a queueCount_ to keep track of the requests queued.
>
> When stopping the execution no count is reset and the
> capture continues as it is.


So there are two states of stop(s) ? One would stop the capture script 
and other one would stop the camera? Is my understanding correct?

>
> Requests are queued with any controls the script matching
> the current queueCount_
>
> Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> ---
>   src/qcam/assets/feathericons/feathericons.qrc |  2 +
>   src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
>   src/qcam/main_window.h                        |  6 ++
>   src/qcam/meson.build                          |  2 +
>   4 files changed, 78 insertions(+)
>
> diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
> index c5302040..6b08395a 100644
> --- a/src/qcam/assets/feathericons/feathericons.qrc
> +++ b/src/qcam/assets/feathericons/feathericons.qrc
> @@ -3,9 +3,11 @@
>   <qresource>
>   	<file>aperture.svg</file>
>   	<file>camera-off.svg</file>
> +	<file>file.svg</file>
>   	<file>play-circle.svg</file>
>   	<file>save.svg</file>
>   	<file>stop-circle.svg</file>
>   	<file>x-circle.svg</file>
> +	<file>x-square.svg</file>
>   </qresource>
>   </RCC>
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index adeb3181..4fbaeccc 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -20,6 +20,7 @@
>   #include <QImage>
>   #include <QImageWriter>
>   #include <QInputDialog>
> +#include <QMessageBox>
>   #include <QMutexLocker>
>   #include <QStandardPaths>
>   #include <QStringList>
> @@ -232,6 +233,13 @@ int MainWindow::createToolbars()
>   	saveRaw_ = action;
>   #endif
>   
> +	/* Open Script... action. */
> +	action = toolbar_->addAction(QIcon::fromTheme("document-open",
> +						      QIcon(":file.svg")),
> +				     "Open Capture Script");
> +	connect(action, &QAction::triggered, this, &MainWindow::chooseScript);
> +	scriptExecAction_ = action;
> +
>   	return 0;
>   }
>   
> @@ -255,6 +263,60 @@ void MainWindow::updateTitle()
>   	setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + " fps");
>   }
>   
> +/**
> + * \brief Load a capture script for handling the capture session.
> + *
> + * If already capturing, it would restart the capture.
> + */
> +void MainWindow::chooseScript()
> +{
> +	if (script_) {
> +		/*
> +		 * This is the second valid press of load script button,
> +		 * It indicates stopping, Stop and set button for new script.
> +		 */
> +		script_.reset();
> +		scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
> +							    QIcon(":file.svg")));
> +		scriptExecAction_->setText("Open Capture Script");
> +		return;
> +	}
> +
> +	QString scriptFile = QFileDialog::getOpenFileName(this, "Open Capture Script", QDir::currentPath(),
> +							  "Capture Script (*.yaml)");
> +	if (scriptFile.isEmpty())
> +		return;
> +
> +	/*
> +	 * If we are already capturing,
> +	 * stop so we don't have stuck image in viewfinder.
> +	 */
> +	bool wasCapturing = isCapturing_;
> +	if (isCapturing_)
> +		toggleCapture(false);
> +
> +	script_ = std::make_unique<CaptureScript>(camera_, scriptFile.toStdString());
> +	if (!script_->valid()) {
> +		script_.reset();
> +		QMessageBox::critical(this, "Invalid Script",
> +					      "Couldn't load the capture script");
> +		if (wasCapturing)
> +			toggleCapture(true);
> +		return;
> +	}
> +
> +	/*
> +	 * Valid script verified
> +	 * Set the button to indicate stopping availibility.
> +	 */
> +	scriptExecAction_->setIcon(QIcon(":x-square.svg"));
> +	scriptExecAction_->setText("Stop Script execution");
> +
> +	/* Start capture again if we were capturing before. */
> +	if (wasCapturing)
> +		toggleCapture(true);
> +}
> +
>   /* -----------------------------------------------------------------------------
>    * Camera Selection
>    */
> @@ -510,6 +572,7 @@ int MainWindow::startCapture()
>   	previousFrames_ = 0;
>   	framesCaptured_ = 0;
>   	lastBufferTime_ = 0;
> +	queueCount_ = 0;
>   
>   	ret = camera_->start();
>   	if (ret) {
> @@ -789,5 +852,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 c3e4b665..2cdf7169 100644
> --- a/src/qcam/main_window.h
> +++ b/src/qcam/main_window.h
> @@ -26,6 +26,7 @@
>   #include <libcamera/request.h>
>   #include <libcamera/stream.h>
>   
> +#include "../cam/capture_script.h"
>   #include "../cam/stream_options.h"
>   #include "viewfinder.h"
>   
> @@ -86,11 +87,14 @@ private:
>   	void processHotplug(HotplugEvent *e);
>   	void processViewfinder(libcamera::FrameBuffer *buffer);
>   
> +	void chooseScript();
> +
>   	/* UI elements */
>   	QToolBar *toolbar_;
>   	QAction *startStopAction_;
>   	QComboBox *cameraCombo_;
>   	QAction *saveRaw_;
> +	QAction *scriptExecAction_;
>   	ViewFinder *viewfinder_;
>   
>   	QIcon iconPlay_;
> @@ -124,6 +128,8 @@ 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_;
>   };
> diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> index c46f4631..67074252 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',
> @@ -37,6 +38,7 @@ qcam_resources = files([
>   qcam_deps = [
>       libatomic,
>       libcamera_public,
> +    libyaml,
>       qt5_dep,
>   ]
>
Utkarsh Tiwari July 26, 2022, 2:20 a.m. UTC | #3
On Tue, 26 Jul, 2022, 00:14 Umang Jain, <umang.jain@ideasonboard.com> wrote:

> Hi Utkarsh,
>
> On 7/3/22 10:07, Utkarsh Tiwari via libcamera-devel wrote:
> > Implement an Open Capture Script button which would allow the user
> > to open a Capture Script (*.yaml).
> > This button has two states Open and Stop.
> >
> > Open state allows user to load a capture script.
> > When clicked in open state present them with a QFileDialog
> > to allow user to select a single file.
> >
> > Stop state stops the execution of the current capture script.
> >
> > Introduce a queueCount_ to keep track of the requests queued.
> >
> > When stopping the execution no count is reset and the
> > capture continues as it is.
>
>
> So there are two states of stop(s) ? One would stop the capture script
> and other one would stop the camera? Is my understanding correct?
>

No, the two states of the button are
- Open Capture Script
- Stop the current capture script

The  open state allows the user to select a capture script to execute.

The stop state is visible when the user has loaded a capture script either
through cmdline  or through the button. This state allows to stop the
current script.

Should reword the commit message ?

>
>
> >
> > Requests are queued with any controls the script matching
> > the current queueCount_
> >
> > Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
> > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > ---
> >   src/qcam/assets/feathericons/feathericons.qrc |  2 +
> >   src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
> >   src/qcam/main_window.h                        |  6 ++
> >   src/qcam/meson.build                          |  2 +
> >   4 files changed, 78 insertions(+)
> >
> > diff --git a/src/qcam/assets/feathericons/feathericons.qrc
> b/src/qcam/assets/feathericons/feathericons.qrc
> > index c5302040..6b08395a 100644
> > --- a/src/qcam/assets/feathericons/feathericons.qrc
> > +++ b/src/qcam/assets/feathericons/feathericons.qrc
> > @@ -3,9 +3,11 @@
> >   <qresource>
> >       <file>aperture.svg</file>
> >       <file>camera-off.svg</file>
> > +     <file>file.svg</file>
> >       <file>play-circle.svg</file>
> >       <file>save.svg</file>
> >       <file>stop-circle.svg</file>
> >       <file>x-circle.svg</file>
> > +     <file>x-square.svg</file>
> >   </qresource>
> >   </RCC>
> > diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> > index adeb3181..4fbaeccc 100644
> > --- a/src/qcam/main_window.cpp
> > +++ b/src/qcam/main_window.cpp
> > @@ -20,6 +20,7 @@
> >   #include <QImage>
> >   #include <QImageWriter>
> >   #include <QInputDialog>
> > +#include <QMessageBox>
> >   #include <QMutexLocker>
> >   #include <QStandardPaths>
> >   #include <QStringList>
> > @@ -232,6 +233,13 @@ int MainWindow::createToolbars()
> >       saveRaw_ = action;
> >   #endif
> >
> > +     /* Open Script... action. */
> > +     action = toolbar_->addAction(QIcon::fromTheme("document-open",
> > +                                                   QIcon(":file.svg")),
> > +                                  "Open Capture Script");
> > +     connect(action, &QAction::triggered, this,
> &MainWindow::chooseScript);
> > +     scriptExecAction_ = action;
> > +
> >       return 0;
> >   }
> >
> > @@ -255,6 +263,60 @@ void MainWindow::updateTitle()
> >       setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + "
> fps");
> >   }
> >
> > +/**
> > + * \brief Load a capture script for handling the capture session.
> > + *
> > + * If already capturing, it would restart the capture.
> > + */
> > +void MainWindow::chooseScript()
> > +{
> > +     if (script_) {
> > +             /*
> > +              * This is the second valid press of load script button,
> > +              * It indicates stopping, Stop and set button for new
> script.
> > +              */
> > +             script_.reset();
> > +
>  scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
> > +
>  QIcon(":file.svg")));
> > +             scriptExecAction_->setText("Open Capture Script");
> > +             return;
> > +     }
> > +
> > +     QString scriptFile = QFileDialog::getOpenFileName(this, "Open
> Capture Script", QDir::currentPath(),
> > +                                                       "Capture Script
> (*.yaml)");
> > +     if (scriptFile.isEmpty())
> > +             return;
> > +
> > +     /*
> > +      * If we are already capturing,
> > +      * stop so we don't have stuck image in viewfinder.
> > +      */
> > +     bool wasCapturing = isCapturing_;
> > +     if (isCapturing_)
> > +             toggleCapture(false);
> > +
> > +     script_ = std::make_unique<CaptureScript>(camera_,
> scriptFile.toStdString());
> > +     if (!script_->valid()) {
> > +             script_.reset();
> > +             QMessageBox::critical(this, "Invalid Script",
> > +                                           "Couldn't load the capture
> script");
> > +             if (wasCapturing)
> > +                     toggleCapture(true);
> > +             return;
> > +     }
> > +
> > +     /*
> > +      * Valid script verified
> > +      * Set the button to indicate stopping availibility.
> > +      */
> > +     scriptExecAction_->setIcon(QIcon(":x-square.svg"));
> > +     scriptExecAction_->setText("Stop Script execution");
> > +
> > +     /* Start capture again if we were capturing before. */
> > +     if (wasCapturing)
> > +             toggleCapture(true);
> > +}
> > +
> >   /*
> -----------------------------------------------------------------------------
> >    * Camera Selection
> >    */
> > @@ -510,6 +572,7 @@ int MainWindow::startCapture()
> >       previousFrames_ = 0;
> >       framesCaptured_ = 0;
> >       lastBufferTime_ = 0;
> > +     queueCount_ = 0;
> >
> >       ret = camera_->start();
> >       if (ret) {
> > @@ -789,5 +852,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 c3e4b665..2cdf7169 100644
> > --- a/src/qcam/main_window.h
> > +++ b/src/qcam/main_window.h
> > @@ -26,6 +26,7 @@
> >   #include <libcamera/request.h>
> >   #include <libcamera/stream.h>
> >
> > +#include "../cam/capture_script.h"
> >   #include "../cam/stream_options.h"
> >   #include "viewfinder.h"
> >
> > @@ -86,11 +87,14 @@ private:
> >       void processHotplug(HotplugEvent *e);
> >       void processViewfinder(libcamera::FrameBuffer *buffer);
> >
> > +     void chooseScript();
> > +
> >       /* UI elements */
> >       QToolBar *toolbar_;
> >       QAction *startStopAction_;
> >       QComboBox *cameraCombo_;
> >       QAction *saveRaw_;
> > +     QAction *scriptExecAction_;
> >       ViewFinder *viewfinder_;
> >
> >       QIcon iconPlay_;
> > @@ -124,6 +128,8 @@ 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_;
> >   };
> > diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> > index c46f4631..67074252 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',
> > @@ -37,6 +38,7 @@ qcam_resources = files([
> >   qcam_deps = [
> >       libatomic,
> >       libcamera_public,
> > +    libyaml,
> >       qt5_dep,
> >   ]
> >
>
Umang Jain July 26, 2022, 5:07 a.m. UTC | #4
Hi Utkarsh,

On 7/26/22 07:50, Utkarsh Tiwari wrote:
> On Tue, 26 Jul, 2022, 00:14 Umang Jain, <umang.jain@ideasonboard.com> wrote:
>
>> Hi Utkarsh,
>>
>> On 7/3/22 10:07, Utkarsh Tiwari via libcamera-devel wrote:
>>> Implement an Open Capture Script button which would allow the user
>>> to open a Capture Script (*.yaml).
>>> This button has two states Open and Stop.
>>>
>>> Open state allows user to load a capture script.
>>> When clicked in open state present them with a QFileDialog
>>> to allow user to select a single file.
>>>
>>> Stop state stops the execution of the current capture script.
>>>
>>> Introduce a queueCount_ to keep track of the requests queued.
>>>
>>> When stopping the execution no count is reset and the
>>> capture continues as it is.
>>
>> So there are two states of stop(s) ? One would stop the capture script
>> and other one would stop the camera? Is my understanding correct?
>>
> No, the two states of the button are
> - Open Capture Script
> - Stop the current capture script
>
> The  open state allows the user to select a capture script to execute.
>
> The stop state is visible when the user has loaded a capture script either
> through cmdline  or through the button. This state allows to stop the
> current script.
>
> Should reword the commit message ?

Yes, it would be helpful.

Especially this bit:

     When stopping the execution no count is reset and the
     capture continues as it is.

I also want to ask that we had a recent change where request sequence number
are reset to zero on every start()/stop() cycles. So is this a concern 
this patchset or capture script in general?

https://git.libcamera.org/libcamera/libcamera.git/commit/?id=458d917

>>
>>> Requests are queued with any controls the script matching
>>> the current queueCount_
>>>
>>> Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
>>> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
>>> ---
>>>    src/qcam/assets/feathericons/feathericons.qrc |  2 +
>>>    src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
>>>    src/qcam/main_window.h                        |  6 ++
>>>    src/qcam/meson.build                          |  2 +
>>>    4 files changed, 78 insertions(+)
>>>
>>> diff --git a/src/qcam/assets/feathericons/feathericons.qrc
>> b/src/qcam/assets/feathericons/feathericons.qrc
>>> index c5302040..6b08395a 100644
>>> --- a/src/qcam/assets/feathericons/feathericons.qrc
>>> +++ b/src/qcam/assets/feathericons/feathericons.qrc
>>> @@ -3,9 +3,11 @@
>>>    <qresource>
>>>        <file>aperture.svg</file>
>>>        <file>camera-off.svg</file>
>>> +     <file>file.svg</file>
>>>        <file>play-circle.svg</file>
>>>        <file>save.svg</file>
>>>        <file>stop-circle.svg</file>
>>>        <file>x-circle.svg</file>
>>> +     <file>x-square.svg</file>
>>>    </qresource>
>>>    </RCC>
>>> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
>>> index adeb3181..4fbaeccc 100644
>>> --- a/src/qcam/main_window.cpp
>>> +++ b/src/qcam/main_window.cpp
>>> @@ -20,6 +20,7 @@
>>>    #include <QImage>
>>>    #include <QImageWriter>
>>>    #include <QInputDialog>
>>> +#include <QMessageBox>
>>>    #include <QMutexLocker>
>>>    #include <QStandardPaths>
>>>    #include <QStringList>
>>> @@ -232,6 +233,13 @@ int MainWindow::createToolbars()
>>>        saveRaw_ = action;
>>>    #endif
>>>
>>> +     /* Open Script... action. */
>>> +     action = toolbar_->addAction(QIcon::fromTheme("document-open",
>>> +                                                   QIcon(":file.svg")),
>>> +                                  "Open Capture Script");
>>> +     connect(action, &QAction::triggered, this,
>> &MainWindow::chooseScript);
>>> +     scriptExecAction_ = action;
>>> +
>>>        return 0;
>>>    }
>>>
>>> @@ -255,6 +263,60 @@ void MainWindow::updateTitle()
>>>        setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + "
>> fps");
>>>    }
>>>
>>> +/**
>>> + * \brief Load a capture script for handling the capture session.
>>> + *
>>> + * If already capturing, it would restart the capture.
>>> + */
>>> +void MainWindow::chooseScript()
>>> +{
>>> +     if (script_) {
>>> +             /*
>>> +              * This is the second valid press of load script button,
>>> +              * It indicates stopping, Stop and set button for new
>> script.
>>> +              */
>>> +             script_.reset();
>>> +
>>   scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
>>> +
>>   QIcon(":file.svg")));
>>> +             scriptExecAction_->setText("Open Capture Script");
>>> +             return;
>>> +     }
>>> +
>>> +     QString scriptFile = QFileDialog::getOpenFileName(this, "Open
>> Capture Script", QDir::currentPath(),
>>> +                                                       "Capture Script
>> (*.yaml)");
>>> +     if (scriptFile.isEmpty())
>>> +             return;
>>> +
>>> +     /*
>>> +      * If we are already capturing,
>>> +      * stop so we don't have stuck image in viewfinder.
>>> +      */
>>> +     bool wasCapturing = isCapturing_;
>>> +     if (isCapturing_)
>>> +             toggleCapture(false);
>>> +
>>> +     script_ = std::make_unique<CaptureScript>(camera_,
>> scriptFile.toStdString());
>>> +     if (!script_->valid()) {
>>> +             script_.reset();
>>> +             QMessageBox::critical(this, "Invalid Script",
>>> +                                           "Couldn't load the capture
>> script");
>>> +             if (wasCapturing)
>>> +                     toggleCapture(true);
>>> +             return;
>>> +     }
>>> +
>>> +     /*
>>> +      * Valid script verified
>>> +      * Set the button to indicate stopping availibility.
>>> +      */
>>> +     scriptExecAction_->setIcon(QIcon(":x-square.svg"));
>>> +     scriptExecAction_->setText("Stop Script execution");
>>> +
>>> +     /* Start capture again if we were capturing before. */
>>> +     if (wasCapturing)
>>> +             toggleCapture(true);
>>> +}
>>> +
>>>    /*
>> -----------------------------------------------------------------------------
>>>     * Camera Selection
>>>     */
>>> @@ -510,6 +572,7 @@ int MainWindow::startCapture()
>>>        previousFrames_ = 0;
>>>        framesCaptured_ = 0;
>>>        lastBufferTime_ = 0;
>>> +     queueCount_ = 0;
>>>
>>>        ret = camera_->start();
>>>        if (ret) {
>>> @@ -789,5 +852,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 c3e4b665..2cdf7169 100644
>>> --- a/src/qcam/main_window.h
>>> +++ b/src/qcam/main_window.h
>>> @@ -26,6 +26,7 @@
>>>    #include <libcamera/request.h>
>>>    #include <libcamera/stream.h>
>>>
>>> +#include "../cam/capture_script.h"
>>>    #include "../cam/stream_options.h"
>>>    #include "viewfinder.h"
>>>
>>> @@ -86,11 +87,14 @@ private:
>>>        void processHotplug(HotplugEvent *e);
>>>        void processViewfinder(libcamera::FrameBuffer *buffer);
>>>
>>> +     void chooseScript();
>>> +
>>>        /* UI elements */
>>>        QToolBar *toolbar_;
>>>        QAction *startStopAction_;
>>>        QComboBox *cameraCombo_;
>>>        QAction *saveRaw_;
>>> +     QAction *scriptExecAction_;
>>>        ViewFinder *viewfinder_;
>>>
>>>        QIcon iconPlay_;
>>> @@ -124,6 +128,8 @@ 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_;
>>>    };
>>> diff --git a/src/qcam/meson.build b/src/qcam/meson.build
>>> index c46f4631..67074252 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',
>>> @@ -37,6 +38,7 @@ qcam_resources = files([
>>>    qcam_deps = [
>>>        libatomic,
>>>        libcamera_public,
>>> +    libyaml,
>>>        qt5_dep,
>>>    ]
>>>
Utkarsh Tiwari July 26, 2022, 5:37 p.m. UTC | #5
On Tue, Jul 26, 2022 at 10:37:36AM +0530, Umang Jain wrote:
> Hi Utkarsh,
> 
> On 7/26/22 07:50, Utkarsh Tiwari wrote:
> > On Tue, 26 Jul, 2022, 00:14 Umang Jain, <umang.jain@ideasonboard.com> wrote:
> > 
> > > Hi Utkarsh,
> > > 
> > > On 7/3/22 10:07, Utkarsh Tiwari via libcamera-devel wrote:
> > > > Implement an Open Capture Script button which would allow the user
> > > > to open a Capture Script (*.yaml).
> > > > This button has two states Open and Stop.
> > > > 
> > > > Open state allows user to load a capture script.
> > > > When clicked in open state present them with a QFileDialog
> > > > to allow user to select a single file.
> > > > 
> > > > Stop state stops the execution of the current capture script.
> > > > 
> > > > Introduce a queueCount_ to keep track of the requests queued.
> > > > 
> > > > When stopping the execution no count is reset and the
> > > > capture continues as it is.
> > > 
> > > So there are two states of stop(s) ? One would stop the capture script
> > > and other one would stop the camera? Is my understanding correct?
> > > 
> > No, the two states of the button are
> > - Open Capture Script
> > - Stop the current capture script
> > 
> > The  open state allows the user to select a capture script to execute.
> > 
> > The stop state is visible when the user has loaded a capture script either
> > through cmdline  or through the button. This state allows to stop the
> > current script.
> > 
> > Should reword the commit message ?
> 
> Yes, it would be helpful.
> 
> Especially this bit:
> 
>     When stopping the execution no count is reset and the
>     capture continues as it is.
> 
> I also want to ask that we had a recent change where request sequence number
> are reset to zero on every start()/stop() cycles. So is this a concern this
> patchset or capture script in general?
> 
> https://git.libcamera.org/libcamera/libcamera.git/commit/?id=458d917
  
I don't think this affects this patchset or the capture script.
We need to only the queueCount_ (i.e the frame number) for the capture script.

The line is meant to say that when the script is stopped we don't restart the
capture and nor reset the queueCount_. Qcam resets each counter start() of
the capture.
> 
> > > 
> > > > Requests are queued with any controls the script matching
> > > > the current queueCount_
> > > > 
> > > > Signed-off-by: Utkarsh Tiwari <utkarsh02t@gmail.com>
> > > > Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> > > > ---
> > > >    src/qcam/assets/feathericons/feathericons.qrc |  2 +
> > > >    src/qcam/main_window.cpp                      | 68 +++++++++++++++++++
> > > >    src/qcam/main_window.h                        |  6 ++
> > > >    src/qcam/meson.build                          |  2 +
> > > >    4 files changed, 78 insertions(+)
> > > > 
> > > > diff --git a/src/qcam/assets/feathericons/feathericons.qrc
> > > b/src/qcam/assets/feathericons/feathericons.qrc
> > > > index c5302040..6b08395a 100644
> > > > --- a/src/qcam/assets/feathericons/feathericons.qrc
> > > > +++ b/src/qcam/assets/feathericons/feathericons.qrc
> > > > @@ -3,9 +3,11 @@
> > > >    <qresource>
> > > >        <file>aperture.svg</file>
> > > >        <file>camera-off.svg</file>
> > > > +     <file>file.svg</file>
> > > >        <file>play-circle.svg</file>
> > > >        <file>save.svg</file>
> > > >        <file>stop-circle.svg</file>
> > > >        <file>x-circle.svg</file>
> > > > +     <file>x-square.svg</file>
> > > >    </qresource>
> > > >    </RCC>
> > > > diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> > > > index adeb3181..4fbaeccc 100644
> > > > --- a/src/qcam/main_window.cpp
> > > > +++ b/src/qcam/main_window.cpp
> > > > @@ -20,6 +20,7 @@
> > > >    #include <QImage>
> > > >    #include <QImageWriter>
> > > >    #include <QInputDialog>
> > > > +#include <QMessageBox>
> > > >    #include <QMutexLocker>
> > > >    #include <QStandardPaths>
> > > >    #include <QStringList>
> > > > @@ -232,6 +233,13 @@ int MainWindow::createToolbars()
> > > >        saveRaw_ = action;
> > > >    #endif
> > > > 
> > > > +     /* Open Script... action. */
> > > > +     action = toolbar_->addAction(QIcon::fromTheme("document-open",
> > > > +                                                   QIcon(":file.svg")),
> > > > +                                  "Open Capture Script");
> > > > +     connect(action, &QAction::triggered, this,
> > > &MainWindow::chooseScript);
> > > > +     scriptExecAction_ = action;
> > > > +
> > > >        return 0;
> > > >    }
> > > > 
> > > > @@ -255,6 +263,60 @@ void MainWindow::updateTitle()
> > > >        setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + "
> > > fps");
> > > >    }
> > > > 
> > > > +/**
> > > > + * \brief Load a capture script for handling the capture session.
> > > > + *
> > > > + * If already capturing, it would restart the capture.
> > > > + */
> > > > +void MainWindow::chooseScript()
> > > > +{
> > > > +     if (script_) {
> > > > +             /*
> > > > +              * This is the second valid press of load script button,
> > > > +              * It indicates stopping, Stop and set button for new
> > > script.
> > > > +              */
> > > > +             script_.reset();
> > > > +
> > >   scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
> > > > +
> > >   QIcon(":file.svg")));
> > > > +             scriptExecAction_->setText("Open Capture Script");
> > > > +             return;
> > > > +     }
> > > > +
> > > > +     QString scriptFile = QFileDialog::getOpenFileName(this, "Open
> > > Capture Script", QDir::currentPath(),
> > > > +                                                       "Capture Script
> > > (*.yaml)");
> > > > +     if (scriptFile.isEmpty())
> > > > +             return;
> > > > +
> > > > +     /*
> > > > +      * If we are already capturing,
> > > > +      * stop so we don't have stuck image in viewfinder.
> > > > +      */
> > > > +     bool wasCapturing = isCapturing_;
> > > > +     if (isCapturing_)
> > > > +             toggleCapture(false);
> > > > +
> > > > +     script_ = std::make_unique<CaptureScript>(camera_,
> > > scriptFile.toStdString());
> > > > +     if (!script_->valid()) {
> > > > +             script_.reset();
> > > > +             QMessageBox::critical(this, "Invalid Script",
> > > > +                                           "Couldn't load the capture
> > > script");
> > > > +             if (wasCapturing)
> > > > +                     toggleCapture(true);
> > > > +             return;
> > > > +     }
> > > > +
> > > > +     /*
> > > > +      * Valid script verified
> > > > +      * Set the button to indicate stopping availibility.
> > > > +      */
> > > > +     scriptExecAction_->setIcon(QIcon(":x-square.svg"));
> > > > +     scriptExecAction_->setText("Stop Script execution");
> > > > +
> > > > +     /* Start capture again if we were capturing before. */
> > > > +     if (wasCapturing)
> > > > +             toggleCapture(true);
> > > > +}
> > > > +
> > > >    /*
> > > -----------------------------------------------------------------------------
> > > >     * Camera Selection
> > > >     */
> > > > @@ -510,6 +572,7 @@ int MainWindow::startCapture()
> > > >        previousFrames_ = 0;
> > > >        framesCaptured_ = 0;
> > > >        lastBufferTime_ = 0;
> > > > +     queueCount_ = 0;
> > > > 
> > > >        ret = camera_->start();
> > > >        if (ret) {
> > > > @@ -789,5 +852,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 c3e4b665..2cdf7169 100644
> > > > --- a/src/qcam/main_window.h
> > > > +++ b/src/qcam/main_window.h
> > > > @@ -26,6 +26,7 @@
> > > >    #include <libcamera/request.h>
> > > >    #include <libcamera/stream.h>
> > > > 
> > > > +#include "../cam/capture_script.h"
> > > >    #include "../cam/stream_options.h"
> > > >    #include "viewfinder.h"
> > > > 
> > > > @@ -86,11 +87,14 @@ private:
> > > >        void processHotplug(HotplugEvent *e);
> > > >        void processViewfinder(libcamera::FrameBuffer *buffer);
> > > > 
> > > > +     void chooseScript();
> > > > +
> > > >        /* UI elements */
> > > >        QToolBar *toolbar_;
> > > >        QAction *startStopAction_;
> > > >        QComboBox *cameraCombo_;
> > > >        QAction *saveRaw_;
> > > > +     QAction *scriptExecAction_;
> > > >        ViewFinder *viewfinder_;
> > > > 
> > > >        QIcon iconPlay_;
> > > > @@ -124,6 +128,8 @@ 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_;
> > > >    };
> > > > diff --git a/src/qcam/meson.build b/src/qcam/meson.build
> > > > index c46f4631..67074252 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',
> > > > @@ -37,6 +38,7 @@ qcam_resources = files([
> > > >    qcam_deps = [
> > > >        libatomic,
> > > >        libcamera_public,
> > > > +    libyaml,
> > > >        qt5_dep,
> > > >    ]
> > > >

Patch
diff mbox series

diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
index c5302040..6b08395a 100644
--- a/src/qcam/assets/feathericons/feathericons.qrc
+++ b/src/qcam/assets/feathericons/feathericons.qrc
@@ -3,9 +3,11 @@ 
 <qresource>
 	<file>aperture.svg</file>
 	<file>camera-off.svg</file>
+	<file>file.svg</file>
 	<file>play-circle.svg</file>
 	<file>save.svg</file>
 	<file>stop-circle.svg</file>
 	<file>x-circle.svg</file>
+	<file>x-square.svg</file>
 </qresource>
 </RCC>
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index adeb3181..4fbaeccc 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -20,6 +20,7 @@ 
 #include <QImage>
 #include <QImageWriter>
 #include <QInputDialog>
+#include <QMessageBox>
 #include <QMutexLocker>
 #include <QStandardPaths>
 #include <QStringList>
@@ -232,6 +233,13 @@  int MainWindow::createToolbars()
 	saveRaw_ = action;
 #endif
 
+	/* Open Script... action. */
+	action = toolbar_->addAction(QIcon::fromTheme("document-open",
+						      QIcon(":file.svg")),
+				     "Open Capture Script");
+	connect(action, &QAction::triggered, this, &MainWindow::chooseScript);
+	scriptExecAction_ = action;
+
 	return 0;
 }
 
@@ -255,6 +263,60 @@  void MainWindow::updateTitle()
 	setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + " fps");
 }
 
+/**
+ * \brief Load a capture script for handling the capture session.
+ *
+ * If already capturing, it would restart the capture.
+ */
+void MainWindow::chooseScript()
+{
+	if (script_) {
+		/*
+		 * This is the second valid press of load script button,
+		 * It indicates stopping, Stop and set button for new script.
+		 */
+		script_.reset();
+		scriptExecAction_->setIcon(QIcon::fromTheme("document-open",
+							    QIcon(":file.svg")));
+		scriptExecAction_->setText("Open Capture Script");
+		return;
+	}
+
+	QString scriptFile = QFileDialog::getOpenFileName(this, "Open Capture Script", QDir::currentPath(),
+							  "Capture Script (*.yaml)");
+	if (scriptFile.isEmpty())
+		return;
+
+	/*
+	 * If we are already capturing,
+	 * stop so we don't have stuck image in viewfinder.
+	 */
+	bool wasCapturing = isCapturing_;
+	if (isCapturing_)
+		toggleCapture(false);
+
+	script_ = std::make_unique<CaptureScript>(camera_, scriptFile.toStdString());
+	if (!script_->valid()) {
+		script_.reset();
+		QMessageBox::critical(this, "Invalid Script",
+					      "Couldn't load the capture script");
+		if (wasCapturing)
+			toggleCapture(true);
+		return;
+	}
+
+	/*
+	 * Valid script verified
+	 * Set the button to indicate stopping availibility.
+	 */
+	scriptExecAction_->setIcon(QIcon(":x-square.svg"));
+	scriptExecAction_->setText("Stop Script execution");
+
+	/* Start capture again if we were capturing before. */
+	if (wasCapturing)
+		toggleCapture(true);
+}
+
 /* -----------------------------------------------------------------------------
  * Camera Selection
  */
@@ -510,6 +572,7 @@  int MainWindow::startCapture()
 	previousFrames_ = 0;
 	framesCaptured_ = 0;
 	lastBufferTime_ = 0;
+	queueCount_ = 0;
 
 	ret = camera_->start();
 	if (ret) {
@@ -789,5 +852,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 c3e4b665..2cdf7169 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -26,6 +26,7 @@ 
 #include <libcamera/request.h>
 #include <libcamera/stream.h>
 
+#include "../cam/capture_script.h"
 #include "../cam/stream_options.h"
 #include "viewfinder.h"
 
@@ -86,11 +87,14 @@  private:
 	void processHotplug(HotplugEvent *e);
 	void processViewfinder(libcamera::FrameBuffer *buffer);
 
+	void chooseScript();
+
 	/* UI elements */
 	QToolBar *toolbar_;
 	QAction *startStopAction_;
 	QComboBox *cameraCombo_;
 	QAction *saveRaw_;
+	QAction *scriptExecAction_;
 	ViewFinder *viewfinder_;
 
 	QIcon iconPlay_;
@@ -124,6 +128,8 @@  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_;
 };
diff --git a/src/qcam/meson.build b/src/qcam/meson.build
index c46f4631..67074252 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',
@@ -37,6 +38,7 @@  qcam_resources = files([
 qcam_deps = [
     libatomic,
     libcamera_public,
+    libyaml,
     qt5_dep,
 ]