From 5456e02d3f5bafca1ac76e75eb5a1b5c56c042b5 Mon Sep 17 00:00:00 2001 From: Nejc Galof Date: Tue, 10 Sep 2024 19:33:27 +0200 Subject: v4l2: Support setting frame rate in the V4L2 Adaptation layer The V4L2 adaptation layer can already support streaming with components such as OpenCV, however it is not accepting, or handling any requests to configure the frame rate. In V4L2 the frame rate is set by configuring the timeperframe component of the v4l2_streamparm structure through the VIDIOC_S_PARM ioctl. Extend the V4L2 compatibility layer to accept the VIDIOC_S_PARM ioctls and provide an interface for setting controls on the V4L2Camera class to set the requested rate when starting the camera. Signed-off-by: Nejc Galof Reviewed-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Paul Elder Signed-off-by: Kieran Bingham Signed-off-by: Paul Elder --- src/v4l2/v4l2_camera.cpp | 12 +++++++++--- src/v4l2/v4l2_camera.h | 5 +++++ src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++ src/v4l2/v4l2_camera_proxy.h | 1 + 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp index 0f3b862f..94d138cd 100644 --- a/src/v4l2/v4l2_camera.cpp +++ b/src/v4l2/v4l2_camera.cpp @@ -12,13 +12,15 @@ #include +#include + using namespace libcamera; LOG_DECLARE_CATEGORY(V4L2Compat) V4L2Camera::V4L2Camera(std::shared_ptr camera) - : camera_(camera), isRunning_(false), bufferAllocator_(nullptr), - efd_(-1), bufferAvailableCount_(0) + : camera_(camera), controls_(controls::controls), isRunning_(false), + bufferAllocator_(nullptr), efd_(-1), bufferAvailableCount_(0) { camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); } @@ -202,10 +204,12 @@ int V4L2Camera::streamOn() if (isRunning_) return 0; - int ret = camera_->start(); + int ret = camera_->start(&controls_); if (ret < 0) return ret == -EACCES ? -EBUSY : ret; + controls_.clear(); + isRunning_ = true; for (Request *req : pendingRequests_) { @@ -265,6 +269,8 @@ int V4L2Camera::qbuf(unsigned int index) return 0; } + request->controls().merge(std::move(controls_)); + ret = camera_->queueRequest(request); if (ret < 0) { LOG(V4L2Compat, Error) << "Can't queue request"; diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h index 9a0b0455..e54371fb 100644 --- a/src/v4l2/v4l2_camera.h +++ b/src/v4l2/v4l2_camera.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -50,6 +51,8 @@ public: const libcamera::Size &size, libcamera::StreamConfiguration *streamConfigOut); + libcamera::ControlList &controls() { return controls_; } + int allocBuffers(unsigned int count); void freeBuffers(); int getBufferFd(unsigned int index); @@ -71,6 +74,8 @@ private: std::shared_ptr camera_; std::unique_ptr config_; + libcamera::ControlList controls_; + bool isRunning_; libcamera::Mutex bufferLock_; diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index da117053..5ac8df4c 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -22,6 +22,8 @@ #include #include +#include +#include #include #include "libcamera/internal/v4l2_pixelformat.h" @@ -33,6 +35,7 @@ #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) using namespace libcamera; +using namespace std::literals::chrono_literals; LOG_DECLARE_CATEGORY(V4L2Compat) @@ -755,6 +758,23 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg) return ret; } +int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg) +{ + LOG(V4L2Compat, Debug) + << "[" << file->description() << "] " << __func__ << "()"; + + if (!validateBufferType(arg->type)) + return -EINVAL; + + struct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe; + utils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator; + + int64_t uDuration = frameDuration.get(); + vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration }); + + return 0; +} + const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_QUERYCAP, VIDIOC_ENUM_FRAMESIZES, @@ -775,6 +795,7 @@ const std::set V4L2CameraProxy::supportedIoctls_ = { VIDIOC_EXPBUF, VIDIOC_STREAMON, VIDIOC_STREAMOFF, + VIDIOC_S_PARM, }; int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void *arg) @@ -862,6 +883,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void case VIDIOC_STREAMOFF: ret = vidioc_streamoff(file, static_cast(arg)); break; + case VIDIOC_S_PARM: + ret = vidioc_s_parm(file, static_cast(arg)); + break; default: ret = -ENOTTY; break; diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h index 3d8784df..c957db53 100644 --- a/src/v4l2/v4l2_camera_proxy.h +++ b/src/v4l2/v4l2_camera_proxy.h @@ -67,6 +67,7 @@ private: int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg); int vidioc_streamon(V4L2CameraFile *file, int *arg); int vidioc_streamoff(V4L2CameraFile *file, int *arg); + int vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg); bool hasOwnership(V4L2CameraFile *file); int acquire(V4L2CameraFile *file); -- cgit v1.2.1