[libcamera-devel] [PATCH 10/21] qcam: main_window: Document functions and reorganize member data

Kieran Bingham kieran.bingham at ideasonboard.com
Mon Mar 23 16:49:10 CET 2020


Hi Laurent,

On 23/03/2020 14:21, Laurent Pinchart wrote:
> The qcam application is our reference implementation of a libcamera GUI
> application. Document the code of the MainWindow class to make it easier
> to follow, and reorganize the member data in logical groups for clarity.
> No code change.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>

Sure, ship it.

Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>

> ---
>  src/qcam/main_window.cpp | 69 +++++++++++++++++++++++++++++++++++++++-
>  src/qcam/main_window.h   | 24 ++++++++------
>  2 files changed, 82 insertions(+), 11 deletions(-)
> 
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index 7aaa73e9a709..21a8fcfe711d 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -32,6 +32,9 @@
>  
>  using namespace libcamera;
>  
> +/**
> + * \brief Custom QEvent to signal capture completion
> + */
>  class CaptureEvent : public QEvent
>  {
>  public:
> @@ -52,6 +55,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>  {
>  	int ret;
>  
> +	/*
> +	 * Initialize the UI: Create the toolbar, set the window title and
> +	 * create the viewfinder widget.
> +	 */
>  	createToolbars();
>  
>  	title_ = "QCam " + QString::fromStdString(CameraManager::version());
> @@ -62,6 +69,7 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>  	setCentralWidget(viewfinder_);
>  	adjustSize();
>  
> +	/* Open the camera and start capture. */
>  	ret = openCamera();
>  	if (ret < 0)
>  		quit();
> @@ -97,13 +105,14 @@ int MainWindow::createToolbars()
>  	/* Disable right click context menu. */
>  	toolbar_->setContextMenuPolicy(Qt::PreventContextMenu);
>  
> +	/* Quit action. */
>  	action = toolbar_->addAction(QIcon::fromTheme("application-exit",
>  						      QIcon(":x-circle.svg")),
>  				     "Quit");
>  	action->setShortcut(Qt::CTRL | Qt::Key_Q);
>  	connect(action, &QAction::triggered, this, &MainWindow::quit);
>  
> -	/* Camera selection. */
> +	/* Camera selector. */

Poh Tay Toe, Poe Tah Toe.


>  	QComboBox *cameraCombo = new QComboBox();
>  	connect(cameraCombo, QOverload<int>::of(&QComboBox::activated),
>  		this, &MainWindow::switchCamera);
> @@ -115,6 +124,7 @@ int MainWindow::createToolbars()
>  
>  	toolbar_->addSeparator();
>  
> +	/* Start/Stop action. */
>  	action = toolbar_->addAction(QIcon::fromTheme("media-playback-start",
>  						      QIcon(":play-circle.svg")),
>  				     "Start Capture");
> @@ -123,6 +133,7 @@ int MainWindow::createToolbars()
>  	connect(action, &QAction::toggled, this, &MainWindow::toggleCapture);
>  	startStopAction_ = action;
>  
> +	/* Save As... action. */
>  	action = toolbar_->addAction(QIcon::fromTheme("document-save-as",
>  						      QIcon(":save.svg")),
>  				     "Save As...");
> @@ -140,6 +151,7 @@ void MainWindow::quit()
>  
>  void MainWindow::updateTitle()
>  {
> +	/* Calculate the average frame rate over the last period. */
>  	unsigned int duration = frameRateInterval_.elapsed();
>  	unsigned int frames = framesCaptured_ - previousFrames_;
>  	double fps = frames * 1000.0 / duration;
> @@ -151,8 +163,13 @@ void MainWindow::updateTitle()
>  	setWindowTitle(title_ + " : " + QString::number(fps, 'f', 2) + " fps");
>  }
>  
> +/* -----------------------------------------------------------------------------
> + * Camera Selection
> + */
> +
>  void MainWindow::switchCamera(int index)
>  {
> +	/* Get and acquire the new camera. */
>  	const auto &cameras = cm_->cameras();
>  	if (static_cast<unsigned int>(index) >= cameras.size())
>  		return;
> @@ -166,6 +183,10 @@ void MainWindow::switchCamera(int index)
>  
>  	std::cout << "Switching to camera " << cam->name() << std::endl;
>  
> +	/*
> +	 * Stop the capture session, release the current camera, replace it with
> +	 * the new camera and start a new capture session.
> +	 */
>  	startStopAction_->setChecked(false);
>  
>  	camera_->release();
> @@ -179,9 +200,11 @@ std::string MainWindow::chooseCamera()
>  	QStringList cameras;
>  	bool result;
>  
> +	/* If only one camera is available, use it automatically. */
>  	if (cm_->cameras().size() == 1)
>  		return cm_->cameras()[0]->name();
>  
> +	/* Present a dialog box to pick a camera. */
>  	for (const std::shared_ptr<Camera> &cam : cm_->cameras())
>  		cameras.append(QString::fromStdString(cam->name()));
>  
> @@ -198,6 +221,10 @@ int MainWindow::openCamera()
>  {
>  	std::string cameraName;
>  
> +	/*
> +	 * Use the camera specified on the command line, if any, or display the
> +	 * camera selection dialog box otherwise.
> +	 */
>  	if (options_.isSet(OptCamera))
>  		cameraName = static_cast<std::string>(options_[OptCamera]);
>  	else
> @@ -206,6 +233,7 @@ int MainWindow::openCamera()
>  	if (cameraName == "")
>  		return -EINVAL;
>  
> +	/* Get and acquire the camera. */
>  	camera_ = cm_->get(cameraName);
>  	if (!camera_) {
>  		std::cout << "Camera " << cameraName << " not found"
> @@ -224,6 +252,10 @@ int MainWindow::openCamera()
>  	return 0;
>  }
>  
> +/* -----------------------------------------------------------------------------
> + * Capture Start & Stop
> + */
> +
>  void MainWindow::toggleCapture(bool start)
>  {
>  	if (start) {
> @@ -235,10 +267,16 @@ void MainWindow::toggleCapture(bool start)
>  	}
>  }
>  
> +/**
> + * \brief Start capture with the current camera
> + *
> + * This function shall not be called directly, use toggleCapture() instead.
> + */
>  int MainWindow::startCapture()
>  {
>  	int ret;
>  
> +	/* Configure the camera. */
>  	config_ = camera_->generateConfiguration({ StreamRole::Viewfinder });
>  
>  	StreamConfiguration &cfg = config_->at(0);
> @@ -275,6 +313,7 @@ int MainWindow::startCapture()
>  		return ret;
>  	}
>  
> +	/* Configure the viewfinder. */
>  	Stream *stream = cfg.stream();
>  	ret = viewfinder_->setFormat(cfg.pixelFormat,
>  				     QSize(cfg.size.width, cfg.size.height));
> @@ -285,6 +324,7 @@ int MainWindow::startCapture()
>  
>  	adjustSize();
>  
> +	/* Allocate buffers and requests. */
>  	allocator_ = new FrameBufferAllocator(camera_);
>  	ret = allocator_->allocate(stream);
>  	if (ret < 0) {
> @@ -317,6 +357,7 @@ int MainWindow::startCapture()
>  			std::make_pair(memory, plane.length);
>  	}
>  
> +	/* Start the title timer and the camera. */
>  	titleTimer_.start(2000);
>  	frameRateInterval_.start();
>  	previousFrames_ = 0;
> @@ -331,6 +372,7 @@ int MainWindow::startCapture()
>  
>  	camera_->requestCompleted.connect(this, &MainWindow::requestComplete);
>  
> +	/* Queue all requests. */
>  	for (Request *request : requests) {
>  		ret = camera_->queueRequest(request);
>  		if (ret < 0) {
> @@ -364,6 +406,12 @@ error:
>  	return ret;
>  }
>  
> +/**
> + * \brief Stop ongoing capture
> + *
> + * This function may be called directly when tearing down the MainWindow. Use
> + * toggleCapture() instead in all other cases.
> + */
>  void MainWindow::stopCapture()
>  {
>  	if (!isCapturing_)
> @@ -399,6 +447,10 @@ void MainWindow::stopCapture()
>  	setWindowTitle(title_);
>  }
>  
> +/* -----------------------------------------------------------------------------
> + * Image Save
> + */
> +
>  void MainWindow::saveImageAs()
>  {
>  	QImage image = viewfinder_->getCurrentImage();
> @@ -414,11 +466,20 @@ void MainWindow::saveImageAs()
>  	writer.write(image);
>  }
>  
> +/* -----------------------------------------------------------------------------
> + * Request Completion Handling
> + */
> +
>  void MainWindow::requestComplete(Request *request)
>  {
>  	if (request->status() == Request::RequestCancelled)
>  		return;
>  
> +	/*
> +	 * We're running in the libcamera thread context, expensive operations
> +	 * are not allowed. Add the buffer to the done queue and post a
> +	 * CaptureEvent for the application thread to handle.
> +	 */
>  	const std::map<Stream *, FrameBuffer *> &buffers = request->buffers();
>  	FrameBuffer *buffer = buffers.begin()->second;
>  
> @@ -432,6 +493,11 @@ void MainWindow::requestComplete(Request *request)
>  
>  void MainWindow::processCapture()
>  {
> +	/*
> +	 * Retrieve the next buffer from the done queue. The queue may be empty
> +	 * if stopCapture() has been called while a CaptureEvent was posted but
> +	 * not processed yet. Return immediately in that case.
> +	 */
>  	FrameBuffer *buffer;
>  	{
>  		QMutexLocker locker(&mutex_);
> @@ -455,6 +521,7 @@ void MainWindow::processCapture()
>  		  << " fps: " << std::fixed << std::setprecision(2) << fps
>  		  << std::endl;
>  
> +	/* Display the buffer and requeue it to the camera. */
>  	display(buffer);
>  
>  	queueRequest(buffer);
> diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
> index 3d8d02b44696..fcde88c14f77 100644
> --- a/src/qcam/main_window.h
> +++ b/src/qcam/main_window.h
> @@ -56,6 +56,7 @@ private Q_SLOTS:
>  
>  private:
>  	int createToolbars();
> +
>  	std::string chooseCamera();
>  	int openCamera();
>  
> @@ -67,31 +68,34 @@ private:
>  	int display(FrameBuffer *buffer);
>  	void queueRequest(FrameBuffer *buffer);
>  
> +	/* UI elements */
> +	QToolBar *toolbar_;
> +	QAction *startStopAction_;
> +	ViewFinder *viewfinder_;
> +
>  	QString title_;
>  	QTimer titleTimer_;
>  
> +	/* Options */
>  	const OptionsParser::Options &options_;
>  
> +	/* Camera manager, camera, configuration and buffers */
>  	CameraManager *cm_;
>  	std::shared_ptr<Camera> camera_;
>  	FrameBufferAllocator *allocator_;
>  
> -	bool isCapturing_;
>  	std::unique_ptr<CameraConfiguration> config_;
> +	std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
>  
> -	uint64_t lastBufferTime_;
> +	/* Capture state, buffers queue and statistics */
> +	bool isCapturing_;
> +	QQueue<FrameBuffer *> doneQueue_;
> +	QMutex mutex_;	/* Protects doneQueue_ */
>  
> +	uint64_t lastBufferTime_;
>  	QElapsedTimer frameRateInterval_;
>  	uint32_t previousFrames_;
>  	uint32_t framesCaptured_;
> -
> -	QMutex mutex_;
> -	QQueue<FrameBuffer *> doneQueue_;
> -
> -	QToolBar *toolbar_;
> -	QAction *startStopAction_;
> -	ViewFinder *viewfinder_;
> -	std::map<int, std::pair<void *, unsigned int>> mappedBuffers_;
>  };
>  
>  #endif /* __QCAM_MAIN_WINDOW__ */
> 

-- 
Regards
--
Kieran


More information about the libcamera-devel mailing list