From c05e45ac7743c60a78ebee1b9e341fa5e089285d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 30 Aug 2024 13:12:05 +0200 Subject: pipeline_handler: Add acquireDevice() function to mirror releaseDevice() libcamera always keeps all /dev/video# and /dev/v4l2_subdev# nodes for a pipeline open after enumerating the camera. This is a problem for the uvcvideo pipeline handler. Keeping /dev/video# open stops the UVC USB device from being able to enter runtime-suspend causing significant unnecessary power-usage. Add a stub acquireDevice() function to the PipelineHandler class which pipeline handlers can override. The uvcvideo pipeline handler will use this to delay opening /dev/video# until the device is acquired. This is a special case because the kernel uvcvideo driver powers on the USB device as soon as /dev/video# is opened. This behavior should *not* be copied by other pipeline handlers. Reviewed-by: Laurent Pinchart Reviewed-by: Harvey Yang Signed-off-by: Hans de Goede Signed-off-by: Laurent Pinchart --- src/libcamera/camera.cpp | 2 +- src/libcamera/pipeline_handler.cpp | 48 +++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 382a68f7..4e393f89 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -995,7 +995,7 @@ int Camera::acquire() if (ret < 0) return ret == -EACCES ? -EBUSY : ret; - if (!d->pipe_->acquire()) { + if (!d->pipe_->acquire(this)) { LOG(Camera, Info) << "Pipeline handler in use by another process"; return -EBUSY; diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 1fc22d6a..861815cb 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -163,20 +163,24 @@ MediaDevice *PipelineHandler::acquireMediaDevice(DeviceEnumerator *enumerator, * has already acquired it * \sa release() */ -bool PipelineHandler::acquire() +bool PipelineHandler::acquire(Camera *camera) { MutexLocker locker(lock_); - if (useCount_) { - ++useCount_; - return true; + if (useCount_ == 0) { + for (std::shared_ptr &media : mediaDevices_) { + if (!media->lock()) { + unlockMediaDevices(); + return false; + } + } } - for (std::shared_ptr &media : mediaDevices_) { - if (!media->lock()) { + if (!acquireDevice(camera)) { + if (useCount_ == 0) unlockMediaDevices(); - return false; - } + + return false; } ++useCount_; @@ -213,12 +217,40 @@ void PipelineHandler::release(Camera *camera) --useCount_; } +/** + * \brief Acquire resources associated with this camera + * \param[in] camera The camera for which to acquire resources + * + * Pipeline handlers may override this in order to get resources such as opening + * devices and allocating buffers when a camera is acquired. + * + * This is used by the uvcvideo pipeline handler to delay opening /dev/video# + * until the camera is acquired to avoid excess power consumption. The delayed + * opening of /dev/video# is a special case because the kernel uvcvideo driver + * powers on the USB device as soon as /dev/video# is opened. This behavior + * should *not* be copied by other pipeline handlers. + * + * \return True on success, false on failure + * \sa releaseDevice() + */ +bool PipelineHandler::acquireDevice([[maybe_unused]] Camera *camera) +{ + return true; +} + /** * \brief Release resources associated with this camera * \param[in] camera The camera for which to release resources * * Pipeline handlers may override this in order to perform cleanup operations * when a camera is released, such as freeing memory. + * + * This is called once for every camera that is released. If there are resources + * shared by multiple cameras then the pipeline handler must take care to not + * release them until releaseDevice() has been called for all previously + * acquired cameras. + * + * \sa acquireDevice() */ void PipelineHandler::releaseDevice([[maybe_unused]] Camera *camera) { -- cgit v1.2.1