summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2024-08-30 13:12:07 +0200
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2024-08-30 15:17:27 +0300
commit7a36d05795fddf66f3ddaec710a8cace5af5623a (patch)
tree195708fce5bd80ccbab7819aa5d0e0d917f7cbfa
parent11e396bf9faf708bedc785a3ac5a4d3cc69f4c75 (diff)
pipeline: uvcvideo: Implement acquireDevice() + releaseDevice()
The uvcvideo pipeline handler always keeps the uvcvideo /dev/video# node for a pipeline open after enumerating the camera. This is a problem for uvcvideo, as keeping the /dev/video# node open stops the underlying USB device and the USB bus controller from being able to enter runtime-suspend causing significant unnecessary power-usage. Implement acquireDevice() + releaseDevice(), openening /dev/video# on acquire and closing it on release to fix this. And make validate do a local video_->open() + close() around validate() when not open yet, to keep validate() working on unacquired cameras. Bug: https://bugs.libcamera.org/show_bug.cgi?id=168 Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-rw-r--r--src/libcamera/pipeline/uvcvideo/uvcvideo.cpp54
1 files changed, 51 insertions, 3 deletions
diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
index 8a7409fc..e9faa1a9 100644
--- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
+++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp
@@ -13,6 +13,7 @@
#include <tuple>
#include <libcamera/base/log.h>
+#include <libcamera/base/mutex.h>
#include <libcamera/base/utils.h>
#include <libcamera/camera.h>
@@ -48,6 +49,7 @@ public:
const std::string &id() const { return id_; }
+ Mutex openLock_;
std::unique_ptr<V4L2VideoDevice> video_;
Stream stream_;
std::map<PixelFormat, std::vector<SizeRange>> formats_;
@@ -93,6 +95,9 @@ private:
const ControlValue &value);
int processControls(UVCCameraData *data, Request *request);
+ bool acquireDevice(Camera *camera) override;
+ void releaseDevice(Camera *camera) override;
+
UVCCameraData *cameraData(Camera *camera)
{
return static_cast<UVCCameraData *>(camera->_d());
@@ -158,9 +163,29 @@ CameraConfiguration::Status UVCCameraConfiguration::validate()
format.fourcc = data_->video_->toV4L2PixelFormat(cfg.pixelFormat);
format.size = cfg.size;
- int ret = data_->video_->tryFormat(&format);
- if (ret)
- return Invalid;
+ /*
+ * For power-consumption reasons video_ is closed when the camera is not
+ * acquired. Open it here if necessary.
+ */
+ {
+ bool opened = false;
+
+ MutexLocker locker(data_->openLock_);
+
+ if (!data_->video_->isOpen()) {
+ int ret = data_->video_->open();
+ if (ret)
+ return Invalid;
+
+ opened = true;
+ }
+
+ int ret = data_->video_->tryFormat(&format);
+ if (opened)
+ data_->video_->close();
+ if (ret)
+ return Invalid;
+ }
cfg.stride = format.planes[0].bpl;
cfg.frameSize = format.planes[0].size;
@@ -411,6 +436,23 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)
return true;
}
+bool PipelineHandlerUVC::acquireDevice(Camera *camera)
+{
+ UVCCameraData *data = cameraData(camera);
+
+ MutexLocker locker(data->openLock_);
+
+ return data->video_->open() == 0;
+}
+
+void PipelineHandlerUVC::releaseDevice(Camera *camera)
+{
+ UVCCameraData *data = cameraData(camera);
+
+ MutexLocker locker(data->openLock_);
+ data->video_->close();
+}
+
int UVCCameraData::init(MediaDevice *media)
{
int ret;
@@ -512,6 +554,12 @@ int UVCCameraData::init(MediaDevice *media)
controlInfo_ = ControlInfoMap(std::move(ctrls), controls::controls);
+ /*
+ * Close to allow camera to go into runtime-suspend, video_ will be
+ * re-opened from acquireDevice() and validate().
+ */
+ video_->close();
+
return 0;
}