diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index 8331898c4..094197668 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -7,8 +7,10 @@ #ifndef __LIBCAMERA_CAMERA_MANAGER_H__ #define __LIBCAMERA_CAMERA_MANAGER_H__ +#include #include #include +#include #include #include @@ -33,8 +35,9 @@ public: const std::vector> &cameras() const { return cameras_; } std::shared_ptr get(const std::string &name); + std::shared_ptr get(dev_t devnum); - void addCamera(std::shared_ptr camera); + void addCamera(std::shared_ptr camera, dev_t devnum); void removeCamera(Camera *camera); static const std::string &version() { return version_; } @@ -46,6 +49,7 @@ private: std::unique_ptr enumerator_; std::vector> pipes_; std::vector> cameras_; + std::map> camerasByDevnum_; static const std::string version_; static CameraManager *self_; diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 7c6f72bbe..a71caf853 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -180,15 +180,42 @@ std::shared_ptr CameraManager::get(const std::string &name) return nullptr; } +/** + * \brief Retrieve a camera based on device number + * \param[in] devnum Device number of camera to get + * + * This method is meant solely for the use of the V4L2 compatibility + * layer, to map device nodes to Camera instances. Applications shall + * not use it and shall instead retrieve cameras by name. + * + * Before calling this function the caller is responsible for ensuring that + * the camera manager is running. + * + * \return Shared pointer to Camera object, which is empty if the camera is + * not found + */ +std::shared_ptr CameraManager::get(dev_t devnum) +{ + auto iter = camerasByDevnum_.find(devnum); + if (iter == camerasByDevnum_.end()) + return nullptr; + + return iter->second.lock(); +} + /** * \brief Add a camera to the camera manager * \param[in] camera The camera to be added + * \param[in] devnum The device number to associate with \a camera * * This function is called by pipeline handlers to register the cameras they * handle with the camera manager. Registered cameras are immediately made * available to the system. + * + * \a devnum is used by the V4L2 compatibility layer to map V4L2 device nodes + * to Camera instances. */ -void CameraManager::addCamera(std::shared_ptr camera) +void CameraManager::addCamera(std::shared_ptr camera, dev_t devnum) { for (std::shared_ptr c : cameras_) { if (c->name() == camera->name()) { @@ -200,6 +227,11 @@ void CameraManager::addCamera(std::shared_ptr camera) } cameras_.push_back(std::move(camera)); + + if (devnum) { + unsigned int index = cameras_.size() - 1; + camerasByDevnum_[devnum] = cameras_[index]; + } } /** @@ -212,15 +244,24 @@ void CameraManager::addCamera(std::shared_ptr camera) */ void CameraManager::removeCamera(Camera *camera) { - for (auto iter = cameras_.begin(); iter != cameras_.end(); ++iter) { - if (iter->get() == camera) { - LOG(Camera, Debug) - << "Unregistering camera '" - << camera->name() << "'"; - cameras_.erase(iter); - return; - } - } + auto iter = std::find_if(cameras_.begin(), cameras_.end(), + [camera](std::shared_ptr &c) { + return c.get() == camera; + }); + if (iter == cameras_.end()) + return; + + LOG(Camera, Debug) + << "Unregistering camera '" << camera->name() << "'"; + + auto iter_d = std::find_if(camerasByDevnum_.begin(), camerasByDevnum_.end(), + [camera](const std::pair> &p) { + return p.second.lock().get() == camera; + }); + if (iter_d != camerasByDevnum_.end()) + camerasByDevnum_.erase(iter_d); + + cameras_.erase(iter); } /** diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h index f36226310..067baef56 100644 --- a/src/libcamera/include/pipeline_handler.h +++ b/src/libcamera/include/pipeline_handler.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -86,7 +87,7 @@ public: protected: void registerCamera(std::shared_ptr camera, - std::unique_ptr data); + std::unique_ptr data, dev_t devnum = 0); void hotplugMediaDevice(MediaDevice *media); virtual int queueRequestDevice(Camera *camera, Request *request) = 0; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 5badf31ce..698dd5256 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -7,6 +7,8 @@ #include "pipeline_handler.h" +#include + #include #include #include @@ -438,19 +440,26 @@ void PipelineHandler::completeRequest(Camera *camera, Request *request) * \brief Register a camera to the camera manager and pipeline handler * \param[in] camera The camera to be added * \param[in] data Pipeline-specific data for the camera + * \param[in] devnum Device number of the camera (optional) * * This method is called by pipeline handlers to register the cameras they * handle with the camera manager. It associates the pipeline-specific \a data * with the camera, for later retrieval with cameraData(). Ownership of \a data * is transferred to the PipelineHandler. + * + * \a devnum is the device number (as returned by makedev) that the \a camera + * is to be associated with. This is for the V4L2 compatibility layer to map + * device nodes to Camera instances based on the device number + * registered by this method in \a devnum. */ void PipelineHandler::registerCamera(std::shared_ptr camera, - std::unique_ptr data) + std::unique_ptr data, + dev_t devnum) { data->camera_ = camera.get(); cameraData_[camera.get()] = std::move(data); cameras_.push_back(camera); - manager_->addCamera(std::move(camera)); + manager_->addCamera(std::move(camera), devnum); } /**