[v4] v4l2: Support setting frame rate in the V4L2 Adaptation layer
diff mbox series

Message ID 20240910173327.49377-1-kieran.bingham@ideasonboard.com
State Accepted
Headers show
Series
  • [v4] v4l2: Support setting frame rate in the V4L2 Adaptation layer
Related show

Commit Message

Kieran Bingham Sept. 10, 2024, 5:33 p.m. UTC
From: Nejc Galof <galof.nejc@gmail.com>

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 <galof.nejc@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
---

v4: Handle rebase conflicts only.

 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(-)

Comments

Paul Elder Sept. 10, 2024, 8 p.m. UTC | #1
On Tue, Sep 10, 2024 at 07:33:27PM +0200, Kieran Bingham wrote:
> From: Nejc Galof <galof.nejc@gmail.com>
> 
> 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 <galof.nejc@gmail.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>

> ---
> 
> v4: Handle rebase conflicts only.
> 
>  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 0f3b862f5bc3..94d138cd5710 100644
> --- a/src/v4l2/v4l2_camera.cpp
> +++ b/src/v4l2/v4l2_camera.cpp
> @@ -12,13 +12,15 @@
>  
>  #include <libcamera/base/log.h>
>  
> +#include <libcamera/control_ids.h>
> +
>  using namespace libcamera;
>  
>  LOG_DECLARE_CATEGORY(V4L2Compat)
>  
>  V4L2Camera::V4L2Camera(std::shared_ptr<Camera> 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 9a0b04551c9d..e54371fb4e00 100644
> --- a/src/v4l2/v4l2_camera.h
> +++ b/src/v4l2/v4l2_camera.h
> @@ -16,6 +16,7 @@
>  #include <libcamera/base/shared_fd.h>
>  
>  #include <libcamera/camera.h>
> +#include <libcamera/controls.h>
>  #include <libcamera/framebuffer.h>
>  #include <libcamera/framebuffer_allocator.h>
>  
> @@ -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<libcamera::Camera> camera_;
>  	std::unique_ptr<libcamera::CameraConfiguration> 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 da1170536a8f..00ba9ed360eb 100644
> --- a/src/v4l2/v4l2_camera_proxy.cpp
> +++ b/src/v4l2/v4l2_camera_proxy.cpp
> @@ -22,6 +22,8 @@
>  #include <libcamera/base/utils.h>
>  
>  #include <libcamera/camera.h>
> +#include <libcamera/controls.h>
> +#include <libcamera/control_ids.h>
>  #include <libcamera/formats.h>
>  
>  #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<std::micro>();
> +	vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });
> +
> +	return 0;
> +}
> +
>  const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
>  	VIDIOC_QUERYCAP,
>  	VIDIOC_ENUM_FRAMESIZES,
> @@ -775,6 +795,7 @@ const std::set<unsigned long> 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<int *>(arg));
>  		break;
> +	case VIDIOC_S_PARM:
> +		ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));
> +		break;
>  	default:
>  		ret = -ENOTTY;
>  		break;
> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
> index 3d8784dfdbf1..c957db5349cc 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);
> -- 
> 2.46.0
>

Patch
diff mbox series

diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp
index 0f3b862f5bc3..94d138cd5710 100644
--- a/src/v4l2/v4l2_camera.cpp
+++ b/src/v4l2/v4l2_camera.cpp
@@ -12,13 +12,15 @@ 
 
 #include <libcamera/base/log.h>
 
+#include <libcamera/control_ids.h>
+
 using namespace libcamera;
 
 LOG_DECLARE_CATEGORY(V4L2Compat)
 
 V4L2Camera::V4L2Camera(std::shared_ptr<Camera> 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 9a0b04551c9d..e54371fb4e00 100644
--- a/src/v4l2/v4l2_camera.h
+++ b/src/v4l2/v4l2_camera.h
@@ -16,6 +16,7 @@ 
 #include <libcamera/base/shared_fd.h>
 
 #include <libcamera/camera.h>
+#include <libcamera/controls.h>
 #include <libcamera/framebuffer.h>
 #include <libcamera/framebuffer_allocator.h>
 
@@ -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<libcamera::Camera> camera_;
 	std::unique_ptr<libcamera::CameraConfiguration> 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 da1170536a8f..00ba9ed360eb 100644
--- a/src/v4l2/v4l2_camera_proxy.cpp
+++ b/src/v4l2/v4l2_camera_proxy.cpp
@@ -22,6 +22,8 @@ 
 #include <libcamera/base/utils.h>
 
 #include <libcamera/camera.h>
+#include <libcamera/controls.h>
+#include <libcamera/control_ids.h>
 #include <libcamera/formats.h>
 
 #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<std::micro>();
+	vcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });
+
+	return 0;
+}
+
 const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
 	VIDIOC_QUERYCAP,
 	VIDIOC_ENUM_FRAMESIZES,
@@ -775,6 +795,7 @@  const std::set<unsigned long> 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<int *>(arg));
 		break;
+	case VIDIOC_S_PARM:
+		ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));
+		break;
 	default:
 		ret = -ENOTTY;
 		break;
diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h
index 3d8784dfdbf1..c957db5349cc 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);