[libcamera-devel] [PATCH v2 2/3] qcam: Add a GUI way to use capture script

Kieran Bingham kieran.bingham at ideasonboard.com
Wed Jun 22 18:27:10 CEST 2022


Quoting Kieran Bingham (2022-06-22 16:51:03)
> Hi Utkarsh,
> 
> Quoting Utkarsh Tiwari via libcamera-devel (2022-06-22 14:16:37)
> > 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, this would allow better testing
> > as we can stop in between script and observe.
> 
> I think it sounds like the right thing to do, but I'm not sure it makes
> a difference to testing. 
> 
> > 
> > Initialize a Script Parser instance when the user selects
> > a valid capture script.
> > 
> > At queueRequest() time if script parser has been initialized,
> > then populate the Request::controls() with it at
> > queueRequest time providing the queueCount_.
> > 
> > The queueCount_ is incremented after the getting controls from
> > the parser, so the first request is for frame 0.
> 
> I think the 'useful' information here is that the request is queued with
> any controls that are defined in the script matching the current
> queueCount_.
> 
> > 
> > Signed-off-by: Utkarsh Tiwari <utkarsh02t at gmail.com>
> > ---
> >  src/qcam/assets/feathericons/feathericons.qrc |  2 +
> >  src/qcam/main_window.cpp                      | 61 +++++++++++++++++++
> >  src/qcam/main_window.h                        |  7 +++
> >  src/qcam/meson.build                          |  2 +
> >  4 files changed, 72 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..29da3947 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,53 @@ 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 (isScriptExecuting_) {
> 
> How about just checking if (script_) rather than adding a new
> isScriptExecuting flag?
> 
> I think it conveys the same state?
> 
> > +               /*
> > +                * 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");
> > +               isScriptExecuting_ = false;
> > +               return;
> > +       }
> > +
> > +       QString scriptFile = QFileDialog::getOpenFileName(this, "Open Capture Script", QDir::currentPath(),
> > +                                                         "Capture Script (*.yaml)");
> > +       if (scriptFile.isEmpty())
> > +               return;
> 
> New line here I think. It hides the 'return' otherwise.
> 
> 
> 
> 
> > +       script_ = std::make_unique<CaptureScript>(camera_, scriptFile.toStdString());
> > +       if (!script_->valid()) {
> > +               script_.reset();
> > +               QMessageBox::critical(this, "Invalid Script",
> > +                                             "Couldn't load the capture script");
> > +               return;
> > +       }
> > +
> > +       /*
> > +        * Valid script verified
> > +        * Set the button to indicate stopping availibility
> > +        */
> > +       scriptExecAction_->setIcon(QIcon(":x-square.svg"));
> > +       scriptExecAction_->setText("Stop Script execution");
> > +       isScriptExecuting_ = true;
> > +
> > +       /* Restart the capture so we can reset every counter */
> > +       if (isCapturing_) {
> > +               toggleCapture(false);
> > +               toggleCapture(true);
> > +       }

However if you do use script_ for your state, you still need to make
sure you're not racing with the queue requests here.

Better to stop the capture if isCapturing_ is set, then assign script_
and then restart.

I would still keep the loading of the script where it is though and
assign it to a local variable to validate, before assigning to script_
as the last thing before toggleCapture().



> > +}
> > +
> >  /* -----------------------------------------------------------------------------
> >   * Camera Selection
> >   */
> > @@ -510,6 +565,7 @@ int MainWindow::startCapture()
> >         previousFrames_ = 0;
> >         framesCaptured_ = 0;
> >         lastBufferTime_ = 0;
> > +       queueCount_ = 0;
> >  
> >         ret = camera_->start();
> >         if (ret) {
> > @@ -789,5 +845,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..58df4e15 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_;
> > @@ -112,6 +116,7 @@ private:
> >  
> >         /* Capture state, buffers queue and statistics */
> >         bool isCapturing_;
> > +       bool isScriptExecuting_;
> >         bool captureRaw_;
> >         libcamera::Stream *vfStream_;
> >         libcamera::Stream *rawStream_;
> > @@ -124,6 +129,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
> >


More information about the libcamera-devel mailing list