[libcamera-devel,20/21] qcam: viewfinder: Display icon when stopping capture

Message ID 20200323142205.28342-21-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • qcam: Bypass format conversion when not required
Related show

Commit Message

Laurent Pinchart March 23, 2020, 2:22 p.m. UTC
When stopping capture, display an icon instead of the last frame. This
is required to be able to release the last buffer when the viewfinder
operators in zero-copy mode.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/qcam/assets/feathericons/feathericons.qrc |  1 +
 src/qcam/main_window.cpp                      |  2 +
 src/qcam/viewfinder.cpp                       | 44 ++++++++++++++++++-
 src/qcam/viewfinder.h                         |  8 ++++
 4 files changed, 54 insertions(+), 1 deletion(-)

Comments

Kieran Bingham March 23, 2020, 5:28 p.m. UTC | #1
Hi Laurent,

On 23/03/2020 14:22, Laurent Pinchart wrote:
> When stopping capture, display an icon instead of the last frame. This
> is required to be able to release the last buffer when the viewfinder
> operators in zero-copy mode.

This is actually really nice because it displays an icon when streams
fail to start (I have a secondary IR camera on my laptop which is not
supported, and this icon shows up if I try to stream that camera).

However, it does remove a 'feature' that I had before, where we could
'pause' a running stream and have the last image still visible which
could be useful when trying to catch a picture to save perhaps.

But in general, I think this is a really good feature, and displaying an
icon for a stream which can't run is more valuable than a pause feature
which could be added later...


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


> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---
>  src/qcam/assets/feathericons/feathericons.qrc |  1 +
>  src/qcam/main_window.cpp                      |  2 +
>  src/qcam/viewfinder.cpp                       | 44 ++++++++++++++++++-
>  src/qcam/viewfinder.h                         |  8 ++++
>  4 files changed, 54 insertions(+), 1 deletion(-)
> 
> diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
> index 6ca3a846803c..c4eb7a0be688 100644
> --- a/src/qcam/assets/feathericons/feathericons.qrc
> +++ b/src/qcam/assets/feathericons/feathericons.qrc
> @@ -1,5 +1,6 @@
>  <!DOCTYPE RCC><RCC version="1.0">
>  <qresource>
> +<file>./camera-off.svg</file>
>  <file>./play-circle.svg</file>
>  <file>./save.svg</file>
>  <file>./stop-circle.svg</file>
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index b68e171c5e01..a77d10bb7076 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -412,6 +412,8 @@ void MainWindow::stopCapture()
>  	if (!isCapturing_)
>  		return;
>  
> +	viewfinder_->stop();
> +
>  	int ret = camera_->stop();
>  	if (ret)
>  		qInfo() << "Failed to stop capture";
> diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
> index 4c35659e24aa..a40b2b400daa 100644
> --- a/src/qcam/viewfinder.cpp
> +++ b/src/qcam/viewfinder.cpp
> @@ -20,6 +20,7 @@
>  ViewFinder::ViewFinder(QWidget *parent)
>  	: QWidget(parent), buffer_(nullptr)
>  {
> +	icon_ = QIcon(":camera-off.svg");
>  }
>  
>  ViewFinder::~ViewFinder()
> @@ -89,6 +90,18 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
>  		renderComplete(buffer);
>  }
>  
> +void ViewFinder::stop()
> +{
> +	image_ = QImage();
> +
> +	if (buffer_) {
> +		renderComplete(buffer_);
> +		buffer_ = nullptr;
> +	}
> +
> +	update();
> +}
> +
>  QImage ViewFinder::getCurrentImage()
>  {
>  	QMutexLocker locker(&mutex_);
> @@ -99,7 +112,36 @@ QImage ViewFinder::getCurrentImage()
>  void ViewFinder::paintEvent(QPaintEvent *)
>  {
>  	QPainter painter(this);
> -	painter.drawImage(rect(), image_, image_.rect());
> +
> +	/* If we have an image, draw it. */
> +	if (!image_.isNull()) {
> +		painter.drawImage(rect(), image_, image_.rect());
> +		return;
> +	}
> +
> +	/*
> +	 * Otherwise, draw the camera stopped icon. Render it to the pixmap if
> +	 * the size has changed.
> +	 */
> +	constexpr int margin = 20;
> +
> +	if (vfSize_ != size() || pixmap_.isNull()) {
> +		vfSize_ = size();
> +
> +		QSize pixmapSize{ 1, 1 };
> +		pixmapSize.scale(vfSize_.shrunkBy({ margin, margin, margin, margin }),

shrunkBy fails to compile on QT 5.12.2 ... but you already know (and
have fixed) that...


> +				 Qt::KeepAspectRatio);
> +		pixmap_ = icon_.pixmap(pixmapSize);
> +	}
> +
> +	QPoint point{ margin, margin };
> +	if (pixmap_.width() < width() - 2 * margin)
> +		point.setX((width() - pixmap_.width()) / 2);
> +	else
> +		point.setY((height() - pixmap_.height()) / 2);
> +
> +	painter.setBackgroundMode(Qt::OpaqueMode);
> +	painter.drawPixmap(point, pixmap_);
>  }
>  
>  QSize ViewFinder::sizeHint() const
> diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
> index b5153160f70e..1a27f99ea202 100644
> --- a/src/qcam/viewfinder.h
> +++ b/src/qcam/viewfinder.h
> @@ -9,6 +9,7 @@
>  
>  #include <stddef.h>
>  
> +#include <QIcon>
>  #include <QImage>
>  #include <QMutex>
>  #include <QSize>
> @@ -36,6 +37,7 @@ public:
>  
>  	int setFormat(const libcamera::PixelFormat &format, const QSize &size);
>  	void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
> +	void stop();
>  
>  	QImage getCurrentImage();
>  
> @@ -52,6 +54,12 @@ private:
>  	libcamera::PixelFormat format_;
>  	QSize size_;
>  
> +	/* Camera stopped icon */
> +	QSize vfSize_;
> +	QIcon icon_;
> +	QPixmap pixmap_;
> +
> +	/* Buffer and render image */
>  	libcamera::FrameBuffer *buffer_;
>  	QImage image_;
>  	QMutex mutex_; /* Prevent concurrent access to image_ */
>
Laurent Pinchart March 23, 2020, 5:29 p.m. UTC | #2
Hi Kieran,

On Mon, Mar 23, 2020 at 05:28:05PM +0000, Kieran Bingham wrote:
> On 23/03/2020 14:22, Laurent Pinchart wrote:
> > When stopping capture, display an icon instead of the last frame. This
> > is required to be able to release the last buffer when the viewfinder
> > operators in zero-copy mode.
> 
> This is actually really nice because it displays an icon when streams
> fail to start (I have a secondary IR camera on my laptop which is not
> supported, and this icon shows up if I try to stream that camera).
> 
> However, it does remove a 'feature' that I had before, where we could
> 'pause' a running stream and have the last image still visible which
> could be useful when trying to catch a picture to save perhaps.
> 
> But in general, I think this is a really good feature, and displaying an
> icon for a stream which can't run is more valuable than a pause feature
> which could be added later...

I agree with you, let's take a bit of time to design the pause feature
correctly on top of this.

> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > ---
> >  src/qcam/assets/feathericons/feathericons.qrc |  1 +
> >  src/qcam/main_window.cpp                      |  2 +
> >  src/qcam/viewfinder.cpp                       | 44 ++++++++++++++++++-
> >  src/qcam/viewfinder.h                         |  8 ++++
> >  4 files changed, 54 insertions(+), 1 deletion(-)
> > 
> > diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
> > index 6ca3a846803c..c4eb7a0be688 100644
> > --- a/src/qcam/assets/feathericons/feathericons.qrc
> > +++ b/src/qcam/assets/feathericons/feathericons.qrc
> > @@ -1,5 +1,6 @@
> >  <!DOCTYPE RCC><RCC version="1.0">
> >  <qresource>
> > +<file>./camera-off.svg</file>
> >  <file>./play-circle.svg</file>
> >  <file>./save.svg</file>
> >  <file>./stop-circle.svg</file>
> > diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> > index b68e171c5e01..a77d10bb7076 100644
> > --- a/src/qcam/main_window.cpp
> > +++ b/src/qcam/main_window.cpp
> > @@ -412,6 +412,8 @@ void MainWindow::stopCapture()
> >  	if (!isCapturing_)
> >  		return;
> >  
> > +	viewfinder_->stop();
> > +
> >  	int ret = camera_->stop();
> >  	if (ret)
> >  		qInfo() << "Failed to stop capture";
> > diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
> > index 4c35659e24aa..a40b2b400daa 100644
> > --- a/src/qcam/viewfinder.cpp
> > +++ b/src/qcam/viewfinder.cpp
> > @@ -20,6 +20,7 @@
> >  ViewFinder::ViewFinder(QWidget *parent)
> >  	: QWidget(parent), buffer_(nullptr)
> >  {
> > +	icon_ = QIcon(":camera-off.svg");
> >  }
> >  
> >  ViewFinder::~ViewFinder()
> > @@ -89,6 +90,18 @@ void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
> >  		renderComplete(buffer);
> >  }
> >  
> > +void ViewFinder::stop()
> > +{
> > +	image_ = QImage();
> > +
> > +	if (buffer_) {
> > +		renderComplete(buffer_);
> > +		buffer_ = nullptr;
> > +	}
> > +
> > +	update();
> > +}
> > +
> >  QImage ViewFinder::getCurrentImage()
> >  {
> >  	QMutexLocker locker(&mutex_);
> > @@ -99,7 +112,36 @@ QImage ViewFinder::getCurrentImage()
> >  void ViewFinder::paintEvent(QPaintEvent *)
> >  {
> >  	QPainter painter(this);
> > -	painter.drawImage(rect(), image_, image_.rect());
> > +
> > +	/* If we have an image, draw it. */
> > +	if (!image_.isNull()) {
> > +		painter.drawImage(rect(), image_, image_.rect());
> > +		return;
> > +	}
> > +
> > +	/*
> > +	 * Otherwise, draw the camera stopped icon. Render it to the pixmap if
> > +	 * the size has changed.
> > +	 */
> > +	constexpr int margin = 20;
> > +
> > +	if (vfSize_ != size() || pixmap_.isNull()) {
> > +		vfSize_ = size();
> > +
> > +		QSize pixmapSize{ 1, 1 };
> > +		pixmapSize.scale(vfSize_.shrunkBy({ margin, margin, margin, margin }),
> 
> shrunkBy fails to compile on QT 5.12.2 ... but you already know (and
> have fixed) that...
> 
> > +				 Qt::KeepAspectRatio);
> > +		pixmap_ = icon_.pixmap(pixmapSize);
> > +	}
> > +
> > +	QPoint point{ margin, margin };
> > +	if (pixmap_.width() < width() - 2 * margin)
> > +		point.setX((width() - pixmap_.width()) / 2);
> > +	else
> > +		point.setY((height() - pixmap_.height()) / 2);
> > +
> > +	painter.setBackgroundMode(Qt::OpaqueMode);
> > +	painter.drawPixmap(point, pixmap_);
> >  }
> >  
> >  QSize ViewFinder::sizeHint() const
> > diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
> > index b5153160f70e..1a27f99ea202 100644
> > --- a/src/qcam/viewfinder.h
> > +++ b/src/qcam/viewfinder.h
> > @@ -9,6 +9,7 @@
> >  
> >  #include <stddef.h>
> >  
> > +#include <QIcon>
> >  #include <QImage>
> >  #include <QMutex>
> >  #include <QSize>
> > @@ -36,6 +37,7 @@ public:
> >  
> >  	int setFormat(const libcamera::PixelFormat &format, const QSize &size);
> >  	void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
> > +	void stop();
> >  
> >  	QImage getCurrentImage();
> >  
> > @@ -52,6 +54,12 @@ private:
> >  	libcamera::PixelFormat format_;
> >  	QSize size_;
> >  
> > +	/* Camera stopped icon */
> > +	QSize vfSize_;
> > +	QIcon icon_;
> > +	QPixmap pixmap_;
> > +
> > +	/* Buffer and render image */
> >  	libcamera::FrameBuffer *buffer_;
> >  	QImage image_;
> >  	QMutex mutex_; /* Prevent concurrent access to image_ */

Patch

diff --git a/src/qcam/assets/feathericons/feathericons.qrc b/src/qcam/assets/feathericons/feathericons.qrc
index 6ca3a846803c..c4eb7a0be688 100644
--- a/src/qcam/assets/feathericons/feathericons.qrc
+++ b/src/qcam/assets/feathericons/feathericons.qrc
@@ -1,5 +1,6 @@ 
 <!DOCTYPE RCC><RCC version="1.0">
 <qresource>
+<file>./camera-off.svg</file>
 <file>./play-circle.svg</file>
 <file>./save.svg</file>
 <file>./stop-circle.svg</file>
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index b68e171c5e01..a77d10bb7076 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -412,6 +412,8 @@  void MainWindow::stopCapture()
 	if (!isCapturing_)
 		return;
 
+	viewfinder_->stop();
+
 	int ret = camera_->stop();
 	if (ret)
 		qInfo() << "Failed to stop capture";
diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
index 4c35659e24aa..a40b2b400daa 100644
--- a/src/qcam/viewfinder.cpp
+++ b/src/qcam/viewfinder.cpp
@@ -20,6 +20,7 @@ 
 ViewFinder::ViewFinder(QWidget *parent)
 	: QWidget(parent), buffer_(nullptr)
 {
+	icon_ = QIcon(":camera-off.svg");
 }
 
 ViewFinder::~ViewFinder()
@@ -89,6 +90,18 @@  void ViewFinder::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
 		renderComplete(buffer);
 }
 
+void ViewFinder::stop()
+{
+	image_ = QImage();
+
+	if (buffer_) {
+		renderComplete(buffer_);
+		buffer_ = nullptr;
+	}
+
+	update();
+}
+
 QImage ViewFinder::getCurrentImage()
 {
 	QMutexLocker locker(&mutex_);
@@ -99,7 +112,36 @@  QImage ViewFinder::getCurrentImage()
 void ViewFinder::paintEvent(QPaintEvent *)
 {
 	QPainter painter(this);
-	painter.drawImage(rect(), image_, image_.rect());
+
+	/* If we have an image, draw it. */
+	if (!image_.isNull()) {
+		painter.drawImage(rect(), image_, image_.rect());
+		return;
+	}
+
+	/*
+	 * Otherwise, draw the camera stopped icon. Render it to the pixmap if
+	 * the size has changed.
+	 */
+	constexpr int margin = 20;
+
+	if (vfSize_ != size() || pixmap_.isNull()) {
+		vfSize_ = size();
+
+		QSize pixmapSize{ 1, 1 };
+		pixmapSize.scale(vfSize_.shrunkBy({ margin, margin, margin, margin }),
+				 Qt::KeepAspectRatio);
+		pixmap_ = icon_.pixmap(pixmapSize);
+	}
+
+	QPoint point{ margin, margin };
+	if (pixmap_.width() < width() - 2 * margin)
+		point.setX((width() - pixmap_.width()) / 2);
+	else
+		point.setY((height() - pixmap_.height()) / 2);
+
+	painter.setBackgroundMode(Qt::OpaqueMode);
+	painter.drawPixmap(point, pixmap_);
 }
 
 QSize ViewFinder::sizeHint() const
diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
index b5153160f70e..1a27f99ea202 100644
--- a/src/qcam/viewfinder.h
+++ b/src/qcam/viewfinder.h
@@ -9,6 +9,7 @@ 
 
 #include <stddef.h>
 
+#include <QIcon>
 #include <QImage>
 #include <QMutex>
 #include <QSize>
@@ -36,6 +37,7 @@  public:
 
 	int setFormat(const libcamera::PixelFormat &format, const QSize &size);
 	void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
+	void stop();
 
 	QImage getCurrentImage();
 
@@ -52,6 +54,12 @@  private:
 	libcamera::PixelFormat format_;
 	QSize size_;
 
+	/* Camera stopped icon */
+	QSize vfSize_;
+	QIcon icon_;
+	QPixmap pixmap_;
+
+	/* Buffer and render image */
 	libcamera::FrameBuffer *buffer_;
 	QImage image_;
 	QMutex mutex_; /* Prevent concurrent access to image_ */