[{"id":31156,"web_url":"https://patchwork.libcamera.org/comment/31156/","msgid":"<ZuClezCfQGDq9sUM@pyrite.rasen.tech>","date":"2024-09-10T20:00:59","subject":"Re: [PATCH v4] v4l2: Support setting frame rate in the V4L2\n\tAdaptation layer","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"On Tue, Sep 10, 2024 at 07:33:27PM +0200, Kieran Bingham wrote:\n> From: Nejc Galof <galof.nejc@gmail.com>\n> \n> The V4L2 adaptation layer can already support streaming with components\n> such as OpenCV, however it is not accepting, or handling any requests to\n> configure the frame rate.\n> \n> In V4L2 the frame rate is set by configuring the timeperframe component\n> of the v4l2_streamparm structure through the VIDIOC_S_PARM ioctl.\n> \n> Extend the V4L2 compatibility layer to accept the VIDIOC_S_PARM ioctls\n> and provide an interface for setting controls on the V4L2Camera class to\n> set the requested rate when starting the camera.\n> \n> Signed-off-by: Nejc Galof <galof.nejc@gmail.com>\n> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>\n\nReviewed-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n> \n> v4: Handle rebase conflicts only.\n> \n>  src/v4l2/v4l2_camera.cpp       | 12 +++++++++---\n>  src/v4l2/v4l2_camera.h         |  5 +++++\n>  src/v4l2/v4l2_camera_proxy.cpp | 24 ++++++++++++++++++++++++\n>  src/v4l2/v4l2_camera_proxy.h   |  1 +\n>  4 files changed, 39 insertions(+), 3 deletions(-)\n> \n> \n> diff --git a/src/v4l2/v4l2_camera.cpp b/src/v4l2/v4l2_camera.cpp\n> index 0f3b862f5bc3..94d138cd5710 100644\n> --- a/src/v4l2/v4l2_camera.cpp\n> +++ b/src/v4l2/v4l2_camera.cpp\n> @@ -12,13 +12,15 @@\n>  \n>  #include <libcamera/base/log.h>\n>  \n> +#include <libcamera/control_ids.h>\n> +\n>  using namespace libcamera;\n>  \n>  LOG_DECLARE_CATEGORY(V4L2Compat)\n>  \n>  V4L2Camera::V4L2Camera(std::shared_ptr<Camera> camera)\n> -\t: camera_(camera), isRunning_(false), bufferAllocator_(nullptr),\n> -\t  efd_(-1), bufferAvailableCount_(0)\n> +\t: camera_(camera), controls_(controls::controls), isRunning_(false),\n> +\t  bufferAllocator_(nullptr), efd_(-1), bufferAvailableCount_(0)\n>  {\n>  \tcamera_->requestCompleted.connect(this, &V4L2Camera::requestComplete);\n>  }\n> @@ -202,10 +204,12 @@ int V4L2Camera::streamOn()\n>  \tif (isRunning_)\n>  \t\treturn 0;\n>  \n> -\tint ret = camera_->start();\n> +\tint ret = camera_->start(&controls_);\n>  \tif (ret < 0)\n>  \t\treturn ret == -EACCES ? -EBUSY : ret;\n>  \n> +\tcontrols_.clear();\n> +\n>  \tisRunning_ = true;\n>  \n>  \tfor (Request *req : pendingRequests_) {\n> @@ -265,6 +269,8 @@ int V4L2Camera::qbuf(unsigned int index)\n>  \t\treturn 0;\n>  \t}\n>  \n> +\trequest->controls().merge(std::move(controls_));\n> +\n>  \tret = camera_->queueRequest(request);\n>  \tif (ret < 0) {\n>  \t\tLOG(V4L2Compat, Error) << \"Can't queue request\";\n> diff --git a/src/v4l2/v4l2_camera.h b/src/v4l2/v4l2_camera.h\n> index 9a0b04551c9d..e54371fb4e00 100644\n> --- a/src/v4l2/v4l2_camera.h\n> +++ b/src/v4l2/v4l2_camera.h\n> @@ -16,6 +16,7 @@\n>  #include <libcamera/base/shared_fd.h>\n>  \n>  #include <libcamera/camera.h>\n> +#include <libcamera/controls.h>\n>  #include <libcamera/framebuffer.h>\n>  #include <libcamera/framebuffer_allocator.h>\n>  \n> @@ -50,6 +51,8 @@ public:\n>  \t\t\t\t  const libcamera::Size &size,\n>  \t\t\t\t  libcamera::StreamConfiguration *streamConfigOut);\n>  \n> +\tlibcamera::ControlList &controls() { return controls_; }\n> +\n>  \tint allocBuffers(unsigned int count);\n>  \tvoid freeBuffers();\n>  \tint getBufferFd(unsigned int index);\n> @@ -71,6 +74,8 @@ private:\n>  \tstd::shared_ptr<libcamera::Camera> camera_;\n>  \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n>  \n> +\tlibcamera::ControlList controls_;\n> +\n>  \tbool isRunning_;\n>  \n>  \tlibcamera::Mutex bufferLock_;\n> diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp\n> index da1170536a8f..00ba9ed360eb 100644\n> --- a/src/v4l2/v4l2_camera_proxy.cpp\n> +++ b/src/v4l2/v4l2_camera_proxy.cpp\n> @@ -22,6 +22,8 @@\n>  #include <libcamera/base/utils.h>\n>  \n>  #include <libcamera/camera.h>\n> +#include <libcamera/controls.h>\n> +#include <libcamera/control_ids.h>\n>  #include <libcamera/formats.h>\n>  \n>  #include \"libcamera/internal/v4l2_pixelformat.h\"\n> @@ -33,6 +35,7 @@\n>  #define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))\n>  \n>  using namespace libcamera;\n> +using namespace std::literals::chrono_literals;\n>  \n>  LOG_DECLARE_CATEGORY(V4L2Compat)\n>  \n> @@ -755,6 +758,23 @@ int V4L2CameraProxy::vidioc_streamoff(V4L2CameraFile *file, int *arg)\n>  \treturn ret;\n>  }\n>  \n> +int V4L2CameraProxy::vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg)\n> +{\n> +\tLOG(V4L2Compat, Debug)\n> +\t\t<< \"[\" << file->description() << \"] \" << __func__ << \"()\";\n> +\n> +\tif (!validateBufferType(arg->type))\n> +\t\treturn -EINVAL;\n> +\n> +\tstruct v4l2_fract *timeperframe = &arg->parm.capture.timeperframe;\n> +\tutils::Duration frameDuration = 1.0s * timeperframe->numerator / timeperframe->denominator;\n> +\n> +\tint64_t uDuration = frameDuration.get<std::micro>();\n> +\tvcam_->controls().set(controls::FrameDurationLimits, { uDuration, uDuration });\n> +\n> +\treturn 0;\n> +}\n> +\n>  const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n>  \tVIDIOC_QUERYCAP,\n>  \tVIDIOC_ENUM_FRAMESIZES,\n> @@ -775,6 +795,7 @@ const std::set<unsigned long> V4L2CameraProxy::supportedIoctls_ = {\n>  \tVIDIOC_EXPBUF,\n>  \tVIDIOC_STREAMON,\n>  \tVIDIOC_STREAMOFF,\n> +\tVIDIOC_S_PARM,\n>  };\n>  \n>  int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void *arg)\n> @@ -862,6 +883,9 @@ int V4L2CameraProxy::ioctl(V4L2CameraFile *file, unsigned long longRequest, void\n>  \tcase VIDIOC_STREAMOFF:\n>  \t\tret = vidioc_streamoff(file, static_cast<int *>(arg));\n>  \t\tbreak;\n> +\tcase VIDIOC_S_PARM:\n> +\t\tret = vidioc_s_parm(file, static_cast<struct v4l2_streamparm *>(arg));\n> +\t\tbreak;\n>  \tdefault:\n>  \t\tret = -ENOTTY;\n>  \t\tbreak;\n> diff --git a/src/v4l2/v4l2_camera_proxy.h b/src/v4l2/v4l2_camera_proxy.h\n> index 3d8784dfdbf1..c957db5349cc 100644\n> --- a/src/v4l2/v4l2_camera_proxy.h\n> +++ b/src/v4l2/v4l2_camera_proxy.h\n> @@ -67,6 +67,7 @@ private:\n>  \tint vidioc_expbuf(V4L2CameraFile *file, struct v4l2_exportbuffer *arg);\n>  \tint vidioc_streamon(V4L2CameraFile *file, int *arg);\n>  \tint vidioc_streamoff(V4L2CameraFile *file, int *arg);\n> +\tint vidioc_s_parm(V4L2CameraFile *file, struct v4l2_streamparm *arg);\n>  \n>  \tbool hasOwnership(V4L2CameraFile *file);\n>  \tint acquire(V4L2CameraFile *file);\n> -- \n> 2.46.0\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 86571C324C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 10 Sep 2024 20:01:05 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 7A9C9634FC;\n\tTue, 10 Sep 2024 22:01:04 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 7F85A634E4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 10 Sep 2024 22:01:03 +0200 (CEST)","from pyrite.rasen.tech (213-229-8-243.static.upcbusiness.at\n\t[213.229.8.243])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EC94D3EA;\n\tTue, 10 Sep 2024 21:59:45 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"GHrUMvDt\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1725998386;\n\tbh=hF+obxrvM1GncotrTdg0ncBihD8wG6eW3slW7LYnomA=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=GHrUMvDtRlbHvw3qLDr4Hz4zTWNM/dowhHbObe3Avs1XvLNX+OkFA3kw2HdYdckOx\n\tOEDoRqYEhTuV9ePLbJOW0Fr/4zV6o/YTfoKK7FlCtqpgKfTOxvyGC6pznCWLgSNhdm\n\tYpBQ67yx4B5pJRUZMFWni3mwVePzNhqZJjMap1pE=","Date":"Tue, 10 Sep 2024 22:00:59 +0200","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"Kieran Bingham <kieran.bingham@ideasonboard.com>","Cc":"libcamera devel <libcamera-devel@lists.libcamera.org>,\n\tNejc Galof <galof.nejc@gmail.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>","Subject":"Re: [PATCH v4] v4l2: Support setting frame rate in the V4L2\n\tAdaptation layer","Message-ID":"<ZuClezCfQGDq9sUM@pyrite.rasen.tech>","References":"<20240910173327.49377-1-kieran.bingham@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20240910173327.49377-1-kieran.bingham@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]