[libcamera-devel,v7,6/8] qcam: CamSelectDialog: Add capture script button
diff mbox series

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

Commit Message

Utkarsh Tiwari Aug. 9, 2022, 8:50 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:
	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(-)

Comments

Kieran Bingham Aug. 9, 2022, 9:59 p.m. UTC | #1
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@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
>
Utkarsh Tiwari Aug. 10, 2022, 4:30 a.m. UTC | #2
Hi Kieran thanks for the review.

I accept all the grammetical mistakes.

On Wed, Aug 10, 2022 at 3:29 AM Kieran Bingham <
kieran.bingham@ideasonboard.com> wrote:

> 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@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?
>
> Ah shoots this should be done in the MainWindow constructor.

> >
> >         /*
> >          * 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
> >
>

Patch
diff mbox series

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_;
+	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);
 
 	/*
 	 * 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,
 ]