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>
This commit is contained in:
Niklas Söderlund
2019-01-22 16:47:40 +01:00
committed by Laurent Pinchart
parent 8897260976
commit 607a9d7f56
5 changed files with 84 additions and 6 deletions

View File

@@ -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"
/**
@@ -97,6 +101,73 @@ PipelineHandler::~PipelineHandler()
* constant for the whole lifetime of the pipeline handler.
*/
/**
* \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