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 <galof.nejc@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Nejc Galof 2024-09-10 19:33:27 +02:00 committed by Paul Elder
parent 5c5bc85082
commit 5456e02d3f
4 changed files with 39 additions and 3 deletions

View file

@ -12,13 +12,15 @@
#include <libcamera/base/log.h> #include <libcamera/base/log.h>
#include <libcamera/control_ids.h>
using namespace libcamera; using namespace libcamera;
LOG_DECLARE_CATEGORY(V4L2Compat) LOG_DECLARE_CATEGORY(V4L2Compat)
V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera) V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)
: camera_(camera), isRunning_(false), bufferAllocator_(nullptr), : camera_(camera), controls_(controls::controls), isRunning_(false),
efd_(-1), bufferAvailableCount_(0) bufferAllocator_(nullptr), efd_(-1), bufferAvailableCount_(0)
{ {
camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete); camera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);
} }
@ -202,10 +204,12 @@ int V4L2Camera::streamOn()
if (isRunning_) if (isRunning_)
return 0; return 0;
int ret = camera_->start(); int ret = camera_->start(&controls_);
if (ret < 0) if (ret < 0)
return ret == -EACCES ? -EBUSY : ret; return ret == -EACCES ? -EBUSY : ret;
controls_.clear();
isRunning_ = true; isRunning_ = true;
for (Request *req : pendingRequests_) { for (Request *req : pendingRequests_) {
@ -265,6 +269,8 @@ int V4L2Camera::qbuf(unsigned int index)
return 0; return 0;
} }
request->controls().merge(std::move(controls_));
ret = camera_->queueRequest(request); ret = camera_->queueRequest(request);
if (ret < 0) { if (ret < 0) {
LOG(V4L2Compat, Error) << "Can't queue request"; LOG(V4L2Compat, Error) << "Can't queue request";

View file

@ -16,6 +16,7 @@
#include <libcamera/base/shared_fd.h> #include <libcamera/base/shared_fd.h>
#include <libcamera/camera.h> #include <libcamera/camera.h>
#include <libcamera/controls.h>
#include <libcamera/framebuffer.h> #include <libcamera/framebuffer.h>
#include <libcamera/framebuffer_allocator.h> #include <libcamera/framebuffer_allocator.h>
@ -50,6 +51,8 @@ public:
const libcamera::Size &size, const libcamera::Size &size,
libcamera::StreamConfiguration *streamConfigOut); libcamera::StreamConfiguration *streamConfigOut);
libcamera::ControlList &controls() { return controls_; }
int allocBuffers(unsigned int count); int allocBuffers(unsigned int count);
void freeBuffers(); void freeBuffers();
int getBufferFd(unsigned int index); int getBufferFd(unsigned int index);
@ -71,6 +74,8 @@ private:
std::shared_ptr<libcamera::Camera> camera_; std::shared_ptr<libcamera::Camera> camera_;
std::unique_ptr<libcamera::CameraConfiguration> config_; std::unique_ptr<libcamera::CameraConfiguration> config_;
libcamera::ControlList controls_;
bool isRunning_; bool isRunning_;
libcamera::Mutex bufferLock_; libcamera::Mutex bufferLock_;

View file

@ -22,6 +22,8 @@
#include <libcamera/base/utils.h> #include <libcamera/base/utils.h>
#include <libcamera/camera.h> #include <libcamera/camera.h>
#include <libcamera/control_ids.h>
#include <libcamera/controls.h>
#include <libcamera/formats.h> #include <libcamera/formats.h>
#include "libcamera/internal/v4l2_pixelformat.h" #include "libcamera/internal/v4l2_pixelformat.h"
@ -33,6 +35,7 @@
#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
using namespace libcamera; using namespace libcamera;
using namespace std::literals::chrono_literals;
LOG_DECLARE_CATEGORY(V4L2Compat) LOG_DECLARE_CATEGORY(V4L2Compat)
@ -755,6 +758,23 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)
return ret; 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_ = { const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
VIDIOC_QUERYCAP, VIDIOC_QUERYCAP,
VIDIOC_ENUM_FRAMESIZES, VIDIOC_ENUM_FRAMESIZES,
@ -775,6 +795,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {
VIDIOC_EXPBUF, VIDIOC_EXPBUF,
VIDIOC_STREAMON, VIDIOC_STREAMON,
VIDIOC_STREAMOFF, VIDIOC_STREAMOFF,
VIDIOC_S_PARM,
}; };
int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void *arg) 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: case VIDIOC_STREAMOFF:
ret = vidioc_streamoff(file, static_cast<int *>(arg)); ret = vidioc_streamoff(file, static_cast<int *>(arg));
break; break;
case VIDIOC_S_PARM:
ret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));
break;
default: default:
ret = -ENOTTY; ret = -ENOTTY;
break; break;

View file

@ -67,6 +67,7 @@ private:
int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg); int vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);
int vidioc_streamon(V4L2CameraFile *file, int *arg); int vidioc_streamon(V4L2CameraFile *file, int *arg);
int vidioc_streamoff(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); bool hasOwnership(V4L2CameraFile *file);
int acquire(V4L2CameraFile *file); int acquire(V4L2CameraFile *file);