From 9fb4d454d2b747cd1e97de363e16dda16934f2e2 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 5 Aug 2024 14:26:01 +0200 Subject: HACK: acquire media device non-exclusiveley Signed-off-by: Jacopo Mondi --- include/libcamera/internal/device_enumerator.h | 1 + include/libcamera/internal/media_device.h | 10 +++++++ include/libcamera/internal/pipeline_handler.h | 2 ++ src/libcamera/device_enumerator.cpp | 17 +++++++++++ src/libcamera/media_device.cpp | 34 ++++++++++++++++++++-- src/libcamera/pipeline/rpi/pisp/pisp.cpp | 23 ++++++++++++++- src/libcamera/pipeline_handler.cpp | 39 +++++++++++++++++++++++++- src/libcamera/v4l2_videodevice.cpp | 2 ++ 8 files changed, 124 insertions(+), 4 deletions(-) diff --git a/include/libcamera/internal/device_enumerator.h b/include/libcamera/internal/device_enumerator.h index db3532a9..4bc3a27d 100644 --- a/include/libcamera/internal/device_enumerator.h +++ b/include/libcamera/internal/device_enumerator.h @@ -42,6 +42,7 @@ public: virtual int enumerate() = 0; std::shared_ptr search(const DeviceMatch &dm); + std::shared_ptr searchNonExclusive(const DeviceMatch &dm); Signal<> devicesAdded; diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h index 992184ed..bcbedf5c 100644 --- a/include/libcamera/internal/media_device.h +++ b/include/libcamera/internal/media_device.h @@ -29,9 +29,14 @@ public: ~MediaDevice(); bool acquire(); + bool acquireNonExclusive(); void release(); bool busy() const { return acquired_; } + /* HACKS */ + unsigned int get() { return ++users_; } + unsigned int put() { return --users_; } + bool lock(); void unlock(); @@ -55,6 +60,8 @@ public: int disableLinks(); int fd() const { return fd_.get(); } + int fd(unsigned int context) const { return fds_[context - 1].get(); } + unsigned int numContexts() const { return fds_.size(); } Signal<> disconnected; @@ -63,6 +70,7 @@ protected: private: int open(); + int openMultiple(); void close(); MediaObject *object(unsigned int id); @@ -86,8 +94,10 @@ private: unsigned int hwRevision_; UniqueFD fd_; + std::vector fds_; bool valid_; bool acquired_; + unsigned int users_; std::map objects_; std::vector entities_; diff --git a/include/libcamera/internal/pipeline_handler.h b/include/libcamera/internal/pipeline_handler.h index 746a34f8..7c316cb9 100644 --- a/include/libcamera/internal/pipeline_handler.h +++ b/include/libcamera/internal/pipeline_handler.h @@ -44,6 +44,8 @@ public: virtual bool match(DeviceEnumerator *enumerator) = 0; MediaDevice *acquireMediaDevice(DeviceEnumerator *enumerator, const DeviceMatch &dm); + MediaDevice *acquireMediaDeviceNonExclusive(DeviceEnumerator *enumerator, + const DeviceMatch &dm); bool acquire(); void release(Camera *camera); diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index ae17862f..f8a8a5f6 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -325,4 +325,21 @@ std::shared_ptr DeviceEnumerator::search(const DeviceMatch &dm) return nullptr; } +/** + * HACK + */ +std::shared_ptr DeviceEnumerator::searchNonExclusive(const DeviceMatch &dm) +{ + for (std::shared_ptr &media : devices_) { + if (dm.match(media.get())) { + LOG(DeviceEnumerator, Debug) + << "Successful match for media device \"" + << media->driver() << "\""; + return media; + } + } + + return nullptr; +} + } /* namespace libcamera */ diff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp index bd054552..b8c5aca7 100644 --- a/src/libcamera/media_device.cpp +++ b/src/libcamera/media_device.cpp @@ -63,7 +63,7 @@ LOG_DEFINE_CATEGORY(MediaDevice) * populate() before the media graph can be queried. */ MediaDevice::MediaDevice(const std::string &deviceNode) - : deviceNode_(deviceNode), valid_(false), acquired_(false) + : deviceNode_(deviceNode), valid_(false), acquired_(false), users_(0) { } @@ -112,6 +112,15 @@ bool MediaDevice::acquire() return true; } +bool MediaDevice::acquireNonExclusive() +{ + if (openMultiple()) + return false; + + acquired_ = true; + return true; +} + /** * \brief Release a device previously claimed for exclusive use * \sa acquire(), busy() @@ -474,7 +483,7 @@ int MediaDevice::open() { if (fd_.isValid()) { LOG(MediaDevice, Error) << "MediaDevice already open"; - return -EBUSY; + //return -EBUSY; } fd_ = UniqueFD(::open(deviceNode_.c_str(), O_RDWR | O_CLOEXEC)); @@ -489,6 +498,27 @@ int MediaDevice::open() return 0; } +int MediaDevice::openMultiple() +{ + auto fd = UniqueFD(::open(deviceNode_.c_str(), O_RDWR | O_CLOEXEC)); + + if (!fd.isValid()) { + int ret = -errno; + LOG(MediaDevice, Error) + << "Failed to open media device at " + << deviceNode_ << ": " << strerror(-ret); + return ret; + } + + if (!fd_.isValid()) + fd_ = UniqueFD(fd.get()); + + fds_.push_back(std::move(fd)); + + return 0; +} + + /** * \brief Close the media device * diff --git a/src/libcamera/pipeline/rpi/pisp/pisp.cpp b/src/libcamera/pipeline/rpi/pisp/pisp.cpp index 09cc0178..a8ec495d 100644 --- a/src/libcamera/pipeline/rpi/pisp/pisp.cpp +++ b/src/libcamera/pipeline/rpi/pisp/pisp.cpp @@ -736,6 +736,8 @@ public: RPi::Device cfe_; RPi::Device isp_; + MediaDevice *ispMediaDevice_; + const libpisp::PiSPVariant &pispVariant_; /* Frontend/Backend objects shared with the IPA. */ @@ -875,7 +877,7 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator) isp.add("pispbe-tdn_input"); isp.add("pispbe-stitch_output"); isp.add("pispbe-stitch_input"); - MediaDevice *ispDevice = acquireMediaDevice(enumerator, isp); + MediaDevice *ispDevice = acquireMediaDeviceNonExclusive(enumerator, isp); if (!ispDevice) { LOG(RPI, Debug) << "Unable to acquire ISP instance"; @@ -906,6 +908,8 @@ bool PipelineHandlerPiSP::match(DeviceEnumerator *enumerator) PiSPCameraData *pisp = static_cast(cameraData.get()); + pisp->ispMediaDevice_ = ispDevice; + pisp->fe_ = SharedMemObject ("pisp_frontend", true, pisp->pispVariant_); pisp->be_ = SharedMemObject @@ -1124,12 +1128,29 @@ int PipelineHandlerPiSP::platformRegister(std::unique_ptr &came data->streams_.push_back(&data->isp_[Isp::StitchInput]); data->streams_.push_back(&data->isp_[Isp::StitchOutput]); + LOG(Error); for (auto stream : data->streams_) { ret = stream->dev()->open(); if (ret) return ret; } + LOG(Error); + + unsigned int numContexts = data->ispMediaDevice_->numContexts(); + LOG(Error) << "CONTEXTS: " << numContexts; + unsigned int contextFd = data->ispMediaDevice_->fd(numContexts); + LOG(Error) << "CONTEXT FD: " << contextFd; + + data->isp_[Isp::Input].dev()->bindContext(contextFd); + data->isp_[Isp::Output0].dev()->bindContext(contextFd); + data->isp_[Isp::Output1].dev()->bindContext(contextFd); + data->isp_[Isp::Config].dev()->bindContext(contextFd); + data->isp_[Isp::TdnInput].dev()->bindContext(contextFd); + data->isp_[Isp::TdnOutput].dev()->bindContext(contextFd); + data->isp_[Isp::StitchInput].dev()->bindContext(contextFd); + data->isp_[Isp::StitchOutput].dev()->bindContext(contextFd); + LOG(Error); /* Write up all the IPA connections. */ data->ipa_->prepareIspComplete.connect(data, &PiSPCameraData::prepareIspComplete); data->ipa_->processStatsComplete.connect(data, &PiSPCameraData::processStatsComplete); diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 5ea2ca78..69d88226 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -75,8 +75,12 @@ PipelineHandler::PipelineHandler(CameraManager *manager) PipelineHandler::~PipelineHandler() { - for (std::shared_ptr media : mediaDevices_) + for (std::shared_ptr media : mediaDevices_) { + if (media->put()) + continue; + media->release(); + } } /** @@ -138,6 +142,39 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator, if (!media->acquire()) return nullptr; + media->get(); + mediaDevices_.push_back(media); + + return media.get(); +} + +/** + * \brief Search and acquire non-exclusively a MediaDevice matching a device pattern + * \param[in] enumerator Enumerator containing all media devices in the system + * \param[in] dm Device match pattern + * + * \todo Just and hack for the PiSP BE + * + * \return A pointer to the matching MediaDevice, or nullptr if no match is found + */ +MediaDevice *PipelineHandler::acquireMediaDeviceNonExclusive(DeviceEnumerator *enumerator, + const DeviceMatch &dm) +{ + std::shared_ptr media = enumerator->searchNonExclusive(dm); + if (!media) + return nullptr; + + bool busy = media->busy(); + if (!media->acquireNonExclusive()) + return nullptr; + + /* If it was busy already, just get it. */ + if (busy) { + media->get(); + return media.get(); + } + + /* Otherwise add it to the list of media devs */ mediaDevices_.push_back(media); return media.get(); diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp index a1d9f0ce..8cc3f5a2 100644 --- a/src/libcamera/v4l2_videodevice.cpp +++ b/src/libcamera/v4l2_videodevice.cpp @@ -800,6 +800,8 @@ int V4L2VideoDevice::bindContext(unsigned int context) { struct v4l2_context c = {}; + LOG(Error) << "Bind to context " << context; + c.context_fd = context; int ret = ioctl(VIDIOC_BIND_CONTEXT, &c); if (ret) -- cgit v1.2.1