diff options
author | Niklas Söderlund <niklas.soderlund@ragnatech.se> | 2019-01-22 16:47:40 +0100 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2019-01-25 01:59:28 +0200 |
commit | 607a9d7f5698fa514b66b0f0a53393fb8435ed12 (patch) | |
tree | 9d9ee3d111f0d877c9ca08c9a19a2abd5f8e45cf /src | |
parent | 889726097613ae5ed4d83a6fd0cc3b0b562f8659 (diff) |
libcamera: pipeline_handler: Add camera disconnection support
Pipeline handlers are responsible for creating camera instances, but
also for destroying them when devices are unplugged. As camera objects
are reference-counted this isn't a straightforward operation and
involves the camera manager and camera object itself. Add two helper
methods in the PipelineHandler base class to register a camera and to
register a media device with the pipeline handler.
When registering a camera, the registerCamera() helper method will add
it to the camera manager. When registering a media device, the
registerMediaDevice() helper method will listen to device disconnection
events, and disconnect all cameras created by the pipeline handler as a
response.
Under the hood the PipelineHandler class needs to keep track of
registered cameras in order to handle disconnection. They can't be
stored as shared pointers as this would create a circular dependency
(the Camera class owns a shared pointer to the pipeline handler). Store
them as weak pointers instead. This is safe as a reference to the camera
is stored in the camera manager, and doesn't get removed until the
camera is unregistered from the manager by the PipelineHandler.
Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/libcamera/include/pipeline_handler.h | 10 | ||||
-rw-r--r-- | src/libcamera/pipeline/ipu3/ipu3.cpp | 3 | ||||
-rw-r--r-- | src/libcamera/pipeline/uvcvideo.cpp | 3 | ||||
-rw-r--r-- | src/libcamera/pipeline/vimc.cpp | 3 | ||||
-rw-r--r-- | src/libcamera/pipeline_handler.cpp | 71 |
5 files changed, 84 insertions, 6 deletions
diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index e1d6369e..804cce48 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -16,6 +16,7 @@ namespace libcamera { class CameraManager; class DeviceEnumerator; +class MediaDevice; class PipelineHandler : public std::enable_shared_from_this<PipelineHandler> { @@ -27,6 +28,15 @@ public: protected: CameraManager *manager_; + + void registerCamera(std::shared_ptr<Camera> camera); + void hotplugMediaDevice(MediaDevice *media); + +private: + virtual void disconnect(); + void mediaDeviceDisconnected(MediaDevice *media); + + std::vector<std::weak_ptr<Camera>> cameras_; }; class PipelineHandlerFactory diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index 9831f74f..3161e714 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -9,7 +9,6 @@ #include <vector> #include <libcamera/camera.h> -#include <libcamera/camera_manager.h> #include "device_enumerator.h" #include "log.h" @@ -169,7 +168,7 @@ void PipelineHandlerIPU3::registerCameras() std::string cameraName = sensor->name() + " " + std::to_string(id); std::shared_ptr<Camera> camera = Camera::create(this, cameraName); - manager_->addCamera(std::move(camera)); + registerCamera(std::move(camera)); LOG(IPU3, Info) << "Registered Camera[" << numCameras << "] \"" diff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp index 73bad671..c8f1bf55 100644 --- a/src/libcamera/pipeline/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo.cpp @@ -6,7 +6,6 @@ */ #include <libcamera/camera.h> -#include <libcamera/camera_manager.h> #include "device_enumerator.h" #include "media_device.h" @@ -49,7 +48,7 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) dev_->acquire(); std::shared_ptr<Camera> camera = Camera::create(this, dev_->model()); - manager_->addCamera(std::move(camera)); + registerCamera(std::move(camera)); return true; } diff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp index 521b20d3..b714a076 100644 --- a/src/libcamera/pipeline/vimc.cpp +++ b/src/libcamera/pipeline/vimc.cpp @@ -6,7 +6,6 @@ */ #include <libcamera/camera.h> -#include <libcamera/camera_manager.h> #include "device_enumerator.h" #include "media_device.h" @@ -58,7 +57,7 @@ bool PipeHandlerVimc::match(DeviceEnumerator *enumerator) dev_->acquire(); std::shared_ptr<Camera> camera = Camera::create(this, "Dummy VIMC Camera"); - manager_->addCamera(std::move(camera)); + registerCamera(std::move(camera)); return true; } diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 3850ea8f..23631314 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -5,7 +5,11 @@ * pipeline_handler.cpp - Pipeline handler infrastructure */ +#include <libcamera/camera.h> +#include <libcamera/camera_manager.h> + #include "log.h" +#include "media_device.h" #include "pipeline_handler.h" /** @@ -98,6 +102,73 @@ PipelineHandler::~PipelineHandler() */ /** + * \brief Register a camera to the camera manager and pipeline handler + * \param[in] camera The camera to be added + * + * This function is called by pipeline handlers to register the cameras they + * handle with the camera manager. + */ +void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera) +{ + cameras_.push_back(camera); + manager_->addCamera(std::move(camera)); +} + +/** + * \brief Enable hotplug handling for a media device + * \param[in] media The media device + * + * This function enables hotplug handling, and especially hot-unplug handling, + * of the \a media device. It shall be called by pipeline handlers for all the + * media devices that can be disconnected. + * + * When a media device passed to this function is later unplugged, the pipeline + * handler gets notified and automatically disconnects all the cameras it has + * registered without requiring any manual intervention. + */ +void PipelineHandler::hotplugMediaDevice(MediaDevice *media) +{ + media->disconnected.connect(this, &PipelineHandler::mediaDeviceDisconnected); +} + +/** + * \brief Device disconnection handler + * + * This virtual function is called to notify the pipeline handler that the + * device it handles has been disconnected. It notifies all cameras created by + * the pipeline handler that they have been disconnected, and unregisters them + * from the camera manager. + * + * The function can be overloaded by pipeline handlers to perform custom + * operations at disconnection time. Any overloaded version shall call the + * PipelineHandler::disconnect() base function for proper hot-unplug operation. + */ +void PipelineHandler::disconnect() +{ + for (std::weak_ptr<Camera> ptr : cameras_) { + std::shared_ptr<Camera> camera = ptr.lock(); + if (!camera) + continue; + + camera->disconnect(); + manager_->removeCamera(camera.get()); + } + + cameras_.clear(); +} + +/** + * \brief Slot for the MediaDevice disconnected signal + */ +void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media) +{ + if (cameras_.empty()) + return; + + disconnect(); +} + +/** * \class PipelineHandlerFactory * \brief Registration of PipelineHandler classes and creation of instances * |