[libcamera-devel,v4,5/6] qcam: main_window: Introduce initial hotplug support

Message ID 20200611171528.9381-6-email@uajain.com
State Superseded
Headers show
Series
  • Introduce UVC hotplugging support
Related show

Commit Message

Umang Jain June 11, 2020, 5:16 p.m. UTC
Hook up various QCam UI bits with hotplug support introduced
in previous commits. This looks good-enough as first steps
to see how the hotplugging functionality is turning out to be
from application point-of-view.

One can still think of few edge case nuances not yet covered
under this implementation hence, those are intentionally
kept out of scope for now. It might require some thinking
and/or additional time on hand.

Signed-off-by: Umang Jain <email@uajain.com>
---
 src/qcam/main_window.cpp | 76 ++++++++++++++++++++++++++++++++++++++++
 src/qcam/main_window.h   |  6 ++++
 2 files changed, 82 insertions(+)

Comments

Laurent Pinchart June 12, 2020, 11:04 a.m. UTC | #1
Hi Umang,

Thank you for the patch.

On Thu, Jun 11, 2020 at 05:16:07PM +0000, Umang Jain wrote:
> Hook up various QCam UI bits with hotplug support introduced
> in previous commits. This looks good-enough as first steps
> to see how the hotplugging functionality is turning out to be
> from application point-of-view.
> 
> One can still think of few edge case nuances not yet covered
> under this implementation hence, those are intentionally
> kept out of scope for now. It might require some thinking
> and/or additional time on hand.
> 
> Signed-off-by: Umang Jain <email@uajain.com>

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

> ---
>  src/qcam/main_window.cpp | 76 ++++++++++++++++++++++++++++++++++++++++
>  src/qcam/main_window.h   |  6 ++++
>  2 files changed, 82 insertions(+)
> 
> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
> index 2960259..7bc1360 100644
> --- a/src/qcam/main_window.cpp
> +++ b/src/qcam/main_window.cpp
> @@ -59,6 +59,36 @@ public:
>  	}
>  };
>  
> +/**
> + * \brief Custom QEvent to signal hotplug or unplug
> + */
> +class HotplugEvent : public QEvent
> +{
> +public:
> +	enum PlugEvent {
> +		HotPlug,
> +		HotUnplug
> +	};
> +
> +	HotplugEvent(std::shared_ptr<Camera> camera, PlugEvent event)
> +		: QEvent(type()), camera_(std::move(camera)), plugEvent_(event)
> +	{
> +	}
> +
> +	static Type type()
> +	{
> +		static int type = QEvent::registerEventType();
> +		return static_cast<Type>(type);
> +	}
> +
> +	PlugEvent hotplugEvent() const { return plugEvent_; }
> +	Camera *camera() const { return camera_.get(); }
> +
> +private:
> +	std::shared_ptr<Camera> camera_;
> +	PlugEvent plugEvent_;
> +};
> +
>  MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>  	: saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr),
>  	  isCapturing_(false), captureRaw_(false)
> @@ -81,6 +111,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>  	setCentralWidget(viewfinder_);
>  	adjustSize();
>  
> +	/* Hotplug/unplug support */
> +	cm_->cameraAdded.connect(this, &MainWindow::addCamera);
> +	cm_->cameraRemoved.connect(this, &MainWindow::removeCamera);
> +
>  	/* Open the camera and start capture. */
>  	ret = openCamera();
>  	if (ret < 0) {
> @@ -105,6 +139,9 @@ bool MainWindow::event(QEvent *e)
>  	if (e->type() == CaptureEvent::type()) {
>  		processCapture();
>  		return true;
> +	} else if (e->type() == HotplugEvent::type()) {
> +		processHotplug(static_cast<HotplugEvent *>(e));
> +		return true;
>  	}
>  
>  	return QMainWindow::event(e);
> @@ -535,6 +572,45 @@ void MainWindow::stopCapture()
>  	setWindowTitle(title_);
>  }
>  
> +/* -----------------------------------------------------------------------------
> + * Camera hotplugging support
> + */
> +
> +void MainWindow::processHotplug(HotplugEvent *e)
> +{
> +	Camera *camera = e->camera();
> +	HotplugEvent::PlugEvent event = e->hotplugEvent();
> +
> +	if (event == HotplugEvent::HotPlug) {
> +		cameraCombo_->addItem(QString::fromStdString(camera->name()));
> +	} else if (event == HotplugEvent::HotUnplug) {
> +		/* Check if the currently-streaming camera is removed. */
> +		if (camera == camera_.get()) {
> +			toggleCapture(false);
> +			cameraCombo_->setCurrentIndex(0);
> +		}
> +
> +		int camIndex = cameraCombo_->findText(QString::fromStdString(camera->name()));
> +		cameraCombo_->removeItem(camIndex);
> +	}
> +}
> +
> +void MainWindow::addCamera(std::shared_ptr<Camera> camera)
> +{
> +	qInfo() << "Adding new camera:" << camera->name().c_str();
> +	QCoreApplication::postEvent(this,
> +				    new HotplugEvent(std::move(camera),
> +						     HotplugEvent::HotPlug));
> +}
> +
> +void MainWindow::removeCamera(std::shared_ptr<Camera> camera)
> +{
> +	qInfo() << "Removing camera:" << camera->name().c_str();
> +	QCoreApplication::postEvent(this,
> +				    new HotplugEvent(std::move(camera),
> +						     HotplugEvent::HotUnplug));
> +}
> +
>  /* -----------------------------------------------------------------------------
>   * Image Save
>   */
> diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
> index 59fa2d9..4606fe4 100644
> --- a/src/qcam/main_window.h
> +++ b/src/qcam/main_window.h
> @@ -32,6 +32,8 @@ using namespace libcamera;
>  class QAction;
>  class QComboBox;
>  
> +class HotplugEvent;
> +
>  enum {
>  	OptCamera = 'c',
>  	OptHelp = 'h',
> @@ -87,8 +89,12 @@ private:
>  	int startCapture();
>  	void stopCapture();
>  
> +	void addCamera(std::shared_ptr<Camera> camera);
> +	void removeCamera(std::shared_ptr<Camera> camera);
> +
>  	void requestComplete(Request *request);
>  	void processCapture();
> +	void processHotplug(HotplugEvent *e);
>  	void processViewfinder(FrameBuffer *buffer);
>  
>  	/* UI elements */
Kieran Bingham June 12, 2020, 3:25 p.m. UTC | #2
Hi Umang,

On 12/06/2020 12:04, Laurent Pinchart wrote:
> Hi Umang,
> 
> Thank you for the patch.
> 
> On Thu, Jun 11, 2020 at 05:16:07PM +0000, Umang Jain wrote:
>> Hook up various QCam UI bits with hotplug support introduced
>> in previous commits. This looks good-enough as first steps
>> to see how the hotplugging functionality is turning out to be
>> from application point-of-view.
>>
>> One can still think of few edge case nuances not yet covered
>> under this implementation hence, those are intentionally
>> kept out of scope for now. It might require some thinking
>> and/or additional time on hand.
>>
>> Signed-off-by: Umang Jain <email@uajain.com>
> 
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
>> ---
>>  src/qcam/main_window.cpp | 76 ++++++++++++++++++++++++++++++++++++++++
>>  src/qcam/main_window.h   |  6 ++++
>>  2 files changed, 82 insertions(+)
>>
>> diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
>> index 2960259..7bc1360 100644
>> --- a/src/qcam/main_window.cpp
>> +++ b/src/qcam/main_window.cpp
>> @@ -59,6 +59,36 @@ public:
>>  	}
>>  };
>>  
>> +/**
>> + * \brief Custom QEvent to signal hotplug or unplug
>> + */
>> +class HotplugEvent : public QEvent
>> +{
>> +public:
>> +	enum PlugEvent {
>> +		HotPlug,
>> +		HotUnplug
>> +	};


Re: Laurent's quizzing of if I would dislike the choices here ...
I think this is the best choice of naming, but I can see how it can be a
bit painful.

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


>> +
>> +	HotplugEvent(std::shared_ptr<Camera> camera, PlugEvent event)
>> +		: QEvent(type()), camera_(std::move(camera)), plugEvent_(event)
>> +	{
>> +	}
>> +
>> +	static Type type()
>> +	{
>> +		static int type = QEvent::registerEventType();
>> +		return static_cast<Type>(type);
>> +	}
>> +
>> +	PlugEvent hotplugEvent() const { return plugEvent_; }
>> +	Camera *camera() const { return camera_.get(); }
>> +
>> +private:
>> +	std::shared_ptr<Camera> camera_;
>> +	PlugEvent plugEvent_;
>> +};
>> +
>>  MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>>  	: saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr),
>>  	  isCapturing_(false), captureRaw_(false)
>> @@ -81,6 +111,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
>>  	setCentralWidget(viewfinder_);
>>  	adjustSize();
>>  
>> +	/* Hotplug/unplug support */
>> +	cm_->cameraAdded.connect(this, &MainWindow::addCamera);
>> +	cm_->cameraRemoved.connect(this, &MainWindow::removeCamera);
>> +
>>  	/* Open the camera and start capture. */
>>  	ret = openCamera();
>>  	if (ret < 0) {
>> @@ -105,6 +139,9 @@ bool MainWindow::event(QEvent *e)
>>  	if (e->type() == CaptureEvent::type()) {
>>  		processCapture();
>>  		return true;
>> +	} else if (e->type() == HotplugEvent::type()) {
>> +		processHotplug(static_cast<HotplugEvent *>(e));
>> +		return true;
>>  	}
>>  
>>  	return QMainWindow::event(e);
>> @@ -535,6 +572,45 @@ void MainWindow::stopCapture()
>>  	setWindowTitle(title_);
>>  }
>>  
>> +/* -----------------------------------------------------------------------------
>> + * Camera hotplugging support
>> + */
>> +
>> +void MainWindow::processHotplug(HotplugEvent *e)
>> +{
>> +	Camera *camera = e->camera();
>> +	HotplugEvent::PlugEvent event = e->hotplugEvent();
>> +
>> +	if (event == HotplugEvent::HotPlug) {
>> +		cameraCombo_->addItem(QString::fromStdString(camera->name()));
>> +	} else if (event == HotplugEvent::HotUnplug) {
>> +		/* Check if the currently-streaming camera is removed. */
>> +		if (camera == camera_.get()) {
>> +			toggleCapture(false);
>> +			cameraCombo_->setCurrentIndex(0);
>> +		}
>> +
>> +		int camIndex = cameraCombo_->findText(QString::fromStdString(camera->name()));
>> +		cameraCombo_->removeItem(camIndex);
>> +	}
>> +}
>> +
>> +void MainWindow::addCamera(std::shared_ptr<Camera> camera)
>> +{
>> +	qInfo() << "Adding new camera:" << camera->name().c_str();
>> +	QCoreApplication::postEvent(this,
>> +				    new HotplugEvent(std::move(camera),
>> +						     HotplugEvent::HotPlug));
>> +}
>> +
>> +void MainWindow::removeCamera(std::shared_ptr<Camera> camera)
>> +{
>> +	qInfo() << "Removing camera:" << camera->name().c_str();
>> +	QCoreApplication::postEvent(this,
>> +				    new HotplugEvent(std::move(camera),
>> +						     HotplugEvent::HotUnplug));
>> +}
>> +
>>  /* -----------------------------------------------------------------------------
>>   * Image Save
>>   */
>> diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
>> index 59fa2d9..4606fe4 100644
>> --- a/src/qcam/main_window.h
>> +++ b/src/qcam/main_window.h
>> @@ -32,6 +32,8 @@ using namespace libcamera;
>>  class QAction;
>>  class QComboBox;
>>  
>> +class HotplugEvent;
>> +
>>  enum {
>>  	OptCamera = 'c',
>>  	OptHelp = 'h',
>> @@ -87,8 +89,12 @@ private:
>>  	int startCapture();
>>  	void stopCapture();
>>  
>> +	void addCamera(std::shared_ptr<Camera> camera);
>> +	void removeCamera(std::shared_ptr<Camera> camera);
>> +
>>  	void requestComplete(Request *request);
>>  	void processCapture();
>> +	void processHotplug(HotplugEvent *e);
>>  	void processViewfinder(FrameBuffer *buffer);
>>  
>>  	/* UI elements */
>

Patch

diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 2960259..7bc1360 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -59,6 +59,36 @@  public:
 	}
 };
 
+/**
+ * \brief Custom QEvent to signal hotplug or unplug
+ */
+class HotplugEvent : public QEvent
+{
+public:
+	enum PlugEvent {
+		HotPlug,
+		HotUnplug
+	};
+
+	HotplugEvent(std::shared_ptr<Camera> camera, PlugEvent event)
+		: QEvent(type()), camera_(std::move(camera)), plugEvent_(event)
+	{
+	}
+
+	static Type type()
+	{
+		static int type = QEvent::registerEventType();
+		return static_cast<Type>(type);
+	}
+
+	PlugEvent hotplugEvent() const { return plugEvent_; }
+	Camera *camera() const { return camera_.get(); }
+
+private:
+	std::shared_ptr<Camera> camera_;
+	PlugEvent plugEvent_;
+};
+
 MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
 	: saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr),
 	  isCapturing_(false), captureRaw_(false)
@@ -81,6 +111,10 @@  MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
 	setCentralWidget(viewfinder_);
 	adjustSize();
 
+	/* Hotplug/unplug support */
+	cm_->cameraAdded.connect(this, &MainWindow::addCamera);
+	cm_->cameraRemoved.connect(this, &MainWindow::removeCamera);
+
 	/* Open the camera and start capture. */
 	ret = openCamera();
 	if (ret < 0) {
@@ -105,6 +139,9 @@  bool MainWindow::event(QEvent *e)
 	if (e->type() == CaptureEvent::type()) {
 		processCapture();
 		return true;
+	} else if (e->type() == HotplugEvent::type()) {
+		processHotplug(static_cast<HotplugEvent *>(e));
+		return true;
 	}
 
 	return QMainWindow::event(e);
@@ -535,6 +572,45 @@  void MainWindow::stopCapture()
 	setWindowTitle(title_);
 }
 
+/* -----------------------------------------------------------------------------
+ * Camera hotplugging support
+ */
+
+void MainWindow::processHotplug(HotplugEvent *e)
+{
+	Camera *camera = e->camera();
+	HotplugEvent::PlugEvent event = e->hotplugEvent();
+
+	if (event == HotplugEvent::HotPlug) {
+		cameraCombo_->addItem(QString::fromStdString(camera->name()));
+	} else if (event == HotplugEvent::HotUnplug) {
+		/* Check if the currently-streaming camera is removed. */
+		if (camera == camera_.get()) {
+			toggleCapture(false);
+			cameraCombo_->setCurrentIndex(0);
+		}
+
+		int camIndex = cameraCombo_->findText(QString::fromStdString(camera->name()));
+		cameraCombo_->removeItem(camIndex);
+	}
+}
+
+void MainWindow::addCamera(std::shared_ptr<Camera> camera)
+{
+	qInfo() << "Adding new camera:" << camera->name().c_str();
+	QCoreApplication::postEvent(this,
+				    new HotplugEvent(std::move(camera),
+						     HotplugEvent::HotPlug));
+}
+
+void MainWindow::removeCamera(std::shared_ptr<Camera> camera)
+{
+	qInfo() << "Removing camera:" << camera->name().c_str();
+	QCoreApplication::postEvent(this,
+				    new HotplugEvent(std::move(camera),
+						     HotplugEvent::HotUnplug));
+}
+
 /* -----------------------------------------------------------------------------
  * Image Save
  */
diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
index 59fa2d9..4606fe4 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -32,6 +32,8 @@  using namespace libcamera;
 class QAction;
 class QComboBox;
 
+class HotplugEvent;
+
 enum {
 	OptCamera = 'c',
 	OptHelp = 'h',
@@ -87,8 +89,12 @@  private:
 	int startCapture();
 	void stopCapture();
 
+	void addCamera(std::shared_ptr<Camera> camera);
+	void removeCamera(std::shared_ptr<Camera> camera);
+
 	void requestComplete(Request *request);
 	void processCapture();
+	void processHotplug(HotplugEvent *e);
 	void processViewfinder(FrameBuffer *buffer);
 
 	/* UI elements */