{"id":25182,"url":"https://patchwork.libcamera.org/api/patches/25182/?format=json","web_url":"https://patchwork.libcamera.org/patch/25182/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20251125162851.2301793-4-stefan.klug@ideasonboard.com>","date":"2025-11-25T16:28:15","name":"[v3,03/29] libcamera: Add support for V4L2 requests","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"2d567293bcce944a3811ee64c141572c23d27099","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/people/184/?format=json","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/25182/mbox/","series":[{"id":5613,"url":"https://patchwork.libcamera.org/api/series/5613/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5613","date":"2025-11-25T16:28:12","name":"Full dewarper support on imx8mp","version":3,"mbox":"https://patchwork.libcamera.org/series/5613/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/25182/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/25182/checks/","tags":{},"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 9197BC333C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 25 Nov 2025 16:29:06 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 394E860AA2;\n\tTue, 25 Nov 2025 17:29:06 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A5D83609E0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 25 Nov 2025 17:29:04 +0100 (CET)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:bae1:340c:573c:570b])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 7AD721E2A; \n\tTue, 25 Nov 2025 17:26:55 +0100 (CET)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"V2/+SzEe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1764088015;\n\tbh=pawi4pqbrOgvyYKGn7ePAXaGTNuE7Yk0khC5rT9bJAU=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=V2/+SzEeNrY69HslYGYUbAUpmfi6nFRAWuGCQ27EHp84NjLfUfY/ycUgyNfst0Daq\n\tAMZniCBfBsuS1YgzZSgYvl2Qlmgkgc+mRRoflC3i/nm51j7FRO1wz9NlHvlk16lDcd\n\tLc3sI5eRyAFbgsyVmfGAP9FrQbER5VZc5uOlpXLM=","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","Subject":"[PATCH v3 03/29] libcamera: Add support for V4L2 requests","Date":"Tue, 25 Nov 2025 17:28:15 +0100","Message-ID":"<20251125162851.2301793-4-stefan.klug@ideasonboard.com>","X-Mailer":"git-send-email 2.51.0","In-Reply-To":"<20251125162851.2301793-1-stefan.klug@ideasonboard.com>","References":"<20251125162851.2301793-1-stefan.klug@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","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>"},"content":"The V4L2 requests API provides support to atomically tie controls to a\nset of buffers. This is especially common for m2m devices. Such a\nrequest is represented by an fd that is allocated via\nMEDIA_IOC_REQUEST_ALLOC and then passed to the various V4L2 functions.\n\nImplement a V4L2Request class to wrap such an fd and add the\ncorresponding utility functions.\n\nSigned-off-by: Stefan Klug <stefan.klug@ideasonboard.com>\n\n---\n\nChanges in v3:\n- Replaced int by UniqueFD\n- Fixed lots if typos from review\n\nChanges in v2:\n- Added documentation\n---\n include/libcamera/internal/media_device.h     |   8 ++\n include/libcamera/internal/meson.build        |   1 +\n include/libcamera/internal/v4l2_device.h      |   5 +-\n include/libcamera/internal/v4l2_request.h     |  44 ++++++\n include/libcamera/internal/v4l2_videodevice.h |   3 +-\n src/libcamera/media_device.cpp                |  47 +++++++\n src/libcamera/meson.build                     |   1 +\n src/libcamera/v4l2_device.cpp                 |  30 +++-\n src/libcamera/v4l2_request.cpp                | 128 ++++++++++++++++++\n src/libcamera/v4l2_videodevice.cpp            |  10 +-\n 10 files changed, 268 insertions(+), 9 deletions(-)\n create mode 100644 include/libcamera/internal/v4l2_request.h\n create mode 100644 src/libcamera/v4l2_request.cpp","diff":"diff --git a/include/libcamera/internal/media_device.h b/include/libcamera/internal/media_device.h\nindex b3a48b98d64b..2eb3ad988b09 100644\n--- a/include/libcamera/internal/media_device.h\n+++ b/include/libcamera/internal/media_device.h\n@@ -8,6 +8,7 @@\n #pragma once\n \n #include <map>\n+#include <optional>\n #include <string>\n #include <vector>\n \n@@ -18,6 +19,7 @@\n #include <libcamera/base/unique_fd.h>\n \n #include \"libcamera/internal/media_object.h\"\n+#include \"libcamera/internal/v4l2_request.h\"\n \n namespace libcamera {\n \n@@ -57,6 +59,11 @@ public:\n \n \tstd::vector<MediaEntity *> locateEntities(unsigned int function);\n \n+\tint allocateRequests(unsigned int count,\n+\t\t\t     std::vector<std::unique_ptr<V4L2Request>> *requests);\n+\n+\tbool supportsRequests();\n+\n protected:\n \tstd::string logPrefix() const override;\n \n@@ -87,6 +94,7 @@ private:\n \tUniqueFD fd_;\n \tbool valid_;\n \tbool acquired_;\n+\tstd::optional<bool> supportsRequests_;\n \n \tstd::map<unsigned int, MediaObject *> objects_;\n \tstd::vector<MediaEntity *> entities_;\ndiff --git a/include/libcamera/internal/meson.build b/include/libcamera/internal/meson.build\nindex 45c299f6a332..e9540a2f734f 100644\n--- a/include/libcamera/internal/meson.build\n+++ b/include/libcamera/internal/meson.build\n@@ -44,6 +44,7 @@ libcamera_internal_headers = files([\n     'sysfs.h',\n     'v4l2_device.h',\n     'v4l2_pixelformat.h',\n+    'v4l2_request.h',\n     'v4l2_subdevice.h',\n     'v4l2_videodevice.h',\n     'vector.h',\ndiff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h\nindex 5bc9da96677d..dbbd118abd00 100644\n--- a/include/libcamera/internal/v4l2_device.h\n+++ b/include/libcamera/internal/v4l2_device.h\n@@ -24,6 +24,7 @@\n #include <libcamera/controls.h>\n \n #include \"libcamera/internal/formats.h\"\n+#include \"libcamera/internal/v4l2_request.h\"\n \n namespace libcamera {\n \n@@ -37,8 +38,8 @@ public:\n \n \tconst ControlInfoMap &controls() const { return controls_; }\n \n-\tControlList getControls(Span<const uint32_t> ids);\n-\tint setControls(ControlList *ctrls);\n+\tControlList getControls(Span<const uint32_t> ids, const V4L2Request *request = nullptr);\n+\tint setControls(ControlList *ctrls, const V4L2Request *request = nullptr);\n \n \tconst struct v4l2_query_ext_ctrl *controlInfo(uint32_t id) const;\n \ndiff --git a/include/libcamera/internal/v4l2_request.h b/include/libcamera/internal/v4l2_request.h\nnew file mode 100644\nindex 000000000000..376c79ceedba\n--- /dev/null\n+++ b/include/libcamera/internal/v4l2_request.h\n@@ -0,0 +1,44 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas On Board\n+ *\n+ * V4L2 requests\n+ */\n+\n+#pragma once\n+\n+#include <string>\n+\n+#include <linux/videodev2.h>\n+\n+#include <libcamera/base/event_notifier.h>\n+#include <libcamera/base/log.h>\n+#include <libcamera/base/signal.h>\n+#include <libcamera/base/unique_fd.h>\n+\n+namespace libcamera {\n+\n+class V4L2Request : protected Loggable\n+{\n+public:\n+\tbool isValid() const { return fd_.isValid(); }\n+\tint fd() const { return fd_.get(); }\n+\n+\tint reinit();\n+\tint queue();\n+\n+\tV4L2Request(UniqueFD &&fd);\n+\n+\tSignal<V4L2Request *> requestDone;\n+\n+private:\n+\tLIBCAMERA_DISABLE_COPY_AND_MOVE(V4L2Request)\n+\n+\tvoid requestReady();\n+\tstd::string logPrefix() const override;\n+\n+\tUniqueFD fd_;\n+\tEventNotifier fdNotifier_;\n+};\n+\n+} /* namespace libcamera */\ndiff --git a/include/libcamera/internal/v4l2_videodevice.h b/include/libcamera/internal/v4l2_videodevice.h\nindex 6caafc4dcf08..57db0036db6b 100644\n--- a/include/libcamera/internal/v4l2_videodevice.h\n+++ b/include/libcamera/internal/v4l2_videodevice.h\n@@ -33,6 +33,7 @@\n #include \"libcamera/internal/formats.h\"\n #include \"libcamera/internal/v4l2_device.h\"\n #include \"libcamera/internal/v4l2_pixelformat.h\"\n+#include \"libcamera/internal/v4l2_request.h\"\n \n namespace libcamera {\n \n@@ -217,7 +218,7 @@ public:\n \tint importBuffers(unsigned int count);\n \tint releaseBuffers();\n \n-\tint queueBuffer(FrameBuffer *buffer);\n+\tint queueBuffer(FrameBuffer *buffer, const V4L2Request *request = nullptr);\n \tSignal<FrameBuffer *> bufferReady;\n \n \tint streamOn();\ndiff --git a/src/libcamera/media_device.cpp b/src/libcamera/media_device.cpp\nindex 353f34a81eca..2a848ebed998 100644\n--- a/src/libcamera/media_device.cpp\n+++ b/src/libcamera/media_device.cpp\n@@ -20,6 +20,7 @@\n #include <linux/media.h>\n \n #include <libcamera/base/log.h>\n+#include \"libcamera/internal/v4l2_request.h\"\n \n /**\n  * \\file media_device.h\n@@ -851,4 +852,50 @@ std::vector<MediaEntity *> MediaDevice::locateEntities(unsigned int function)\n \treturn found;\n }\n \n+/**\n+ * \\brief Allocate requests\n+ * \\param[in] count Number of requests to allocate\n+ * \\param[out] requests Vector to store allocated requests\n+ *\n+ * Allocates and stores \\a count requests in \\a requests. If allocation fails,\n+ * an error is returned and \\a requests is cleared.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int MediaDevice::allocateRequests(unsigned int count,\n+\t\t\t\t  std::vector<std::unique_ptr<V4L2Request>> *requests)\n+{\n+\trequests->resize(count);\n+\tfor (unsigned int i = 0; i < count; i++) {\n+\t\tint requestFd;\n+\t\tint ret = ::ioctl(fd_.get(), MEDIA_IOC_REQUEST_ALLOC, &requestFd);\n+\t\tif (ret < 0) {\n+\t\t\trequests->clear();\n+\t\t\treturn -errno;\n+\t\t}\n+\t\t(*requests)[i] = std::make_unique<V4L2Request>(UniqueFD(requestFd));\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\brief Check if requests are supported\n+ *\n+ * Checks if the device supports V4L2 requests by trying to allocate a single\n+ * request. The result is cached, so the allocation is only tried once.\n+ *\n+ * \\return True if the device supports requests, false otherwise\n+ */\n+bool MediaDevice::supportsRequests()\n+{\n+\tif (supportsRequests_.has_value())\n+\t\treturn supportsRequests_.value();\n+\n+\tstd::vector<std::unique_ptr<V4L2Request>> requests;\n+\tsupportsRequests_ = (allocateRequests(1, &requests) == 0);\n+\n+\treturn supportsRequests_.value();\n+}\n+\n } /* namespace libcamera */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex 5b9b86f211f1..34e20f557514 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -54,6 +54,7 @@ libcamera_internal_sources = files([\n     'sysfs.cpp',\n     'v4l2_device.cpp',\n     'v4l2_pixelformat.cpp',\n+    'v4l2_request.cpp',\n     'v4l2_subdevice.cpp',\n     'v4l2_videodevice.cpp',\n     'vector.cpp',\ndiff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp\nindex 8c78b8c424e5..8dcd5e618938 100644\n--- a/src/libcamera/v4l2_device.cpp\n+++ b/src/libcamera/v4l2_device.cpp\n@@ -162,6 +162,7 @@ void V4L2Device::close()\n /**\n  * \\brief Read controls from the device\n  * \\param[in] ids The list of controls to read, specified by their ID\n+ * \\param[in] request An optional request\n  *\n  * This function reads the value of all controls contained in \\a ids, and\n  * returns their values as a ControlList.\n@@ -171,10 +172,12 @@ void V4L2Device::close()\n  * during validation of the requested controls, no control is read and this\n  * function returns an empty control list.\n  *\n+ * If \\a request is specified the controls tied to that request are read.\n+ *\n  * \\return The control values in a ControlList on success, or an empty list on\n  * error\n  */\n-ControlList V4L2Device::getControls(Span<const uint32_t> ids)\n+ControlList V4L2Device::getControls(Span<const uint32_t> ids, const V4L2Request *request)\n {\n \tif (ids.empty())\n \t\treturn {};\n@@ -242,10 +245,16 @@ ControlList V4L2Device::getControls(Span<const uint32_t> ids)\n \t}\n \n \tstruct v4l2_ext_controls v4l2ExtCtrls = {};\n-\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL;\n \tv4l2ExtCtrls.controls = v4l2Ctrls.data();\n \tv4l2ExtCtrls.count = v4l2Ctrls.size();\n \n+\tif (request) {\n+\t\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;\n+\t\tv4l2ExtCtrls.request_fd = request->fd();\n+\t} else {\n+\t\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL;\n+\t}\n+\n \tint ret = ioctl(VIDIOC_G_EXT_CTRLS, &v4l2ExtCtrls);\n \tif (ret) {\n \t\tunsigned int errorIdx = v4l2ExtCtrls.error_idx;\n@@ -273,6 +282,7 @@ ControlList V4L2Device::getControls(Span<const uint32_t> ids)\n /**\n  * \\brief Write controls to the device\n  * \\param[in] ctrls The list of controls to write\n+ * \\param[in] request An optional request\n  *\n  * This function writes the value of all controls contained in \\a ctrls, and\n  * stores the values actually applied to the device in the corresponding\n@@ -288,11 +298,15 @@ ControlList V4L2Device::getControls(Span<const uint32_t> ids)\n  * are written and their values are updated in \\a ctrls, while all other\n  * controls are not written and their values are not changed.\n  *\n+ * If \\a request is set, the controls will be applied to that request. If the\n+ * device doesn't support requests, -EACCESS will be returned. If \\a request is\n+ * invalid, -EINVAL will be returned.\n+ *\n  * \\return 0 on success or an error code otherwise\n- * \\retval -EINVAL One of the control is not supported or not accessible\n+ * \\retval -EINVAL One of the controls is not supported or not accessible\n  * \\retval i The index of the control that failed\n  */\n-int V4L2Device::setControls(ControlList *ctrls)\n+int V4L2Device::setControls(ControlList *ctrls, const V4L2Request *request)\n {\n \tif (ctrls->empty())\n \t\treturn 0;\n@@ -377,10 +391,16 @@ int V4L2Device::setControls(ControlList *ctrls)\n \t}\n \n \tstruct v4l2_ext_controls v4l2ExtCtrls = {};\n-\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL;\n \tv4l2ExtCtrls.controls = v4l2Ctrls.data();\n \tv4l2ExtCtrls.count = v4l2Ctrls.size();\n \n+\tif (request) {\n+\t\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_REQUEST_VAL;\n+\t\tv4l2ExtCtrls.request_fd = request->fd();\n+\t} else {\n+\t\tv4l2ExtCtrls.which = V4L2_CTRL_WHICH_CUR_VAL;\n+\t}\n+\n \tint ret = ioctl(VIDIOC_S_EXT_CTRLS, &v4l2ExtCtrls);\n \tif (ret) {\n \t\tunsigned int errorIdx = v4l2ExtCtrls.error_idx;\ndiff --git a/src/libcamera/v4l2_request.cpp b/src/libcamera/v4l2_request.cpp\nnew file mode 100644\nindex 000000000000..9441d7c4017b\n--- /dev/null\n+++ b/src/libcamera/v4l2_request.cpp\n@@ -0,0 +1,128 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2025, Ideas On Board\n+ *\n+ * V4L2 Request API\n+ */\n+\n+#include \"libcamera/internal/v4l2_request.h\"\n+\n+#include <fcntl.h>\n+#include <stdlib.h>\n+#include <sys/ioctl.h>\n+#include <sys/syscall.h>\n+#include <unistd.h>\n+\n+#include <linux/media.h>\n+\n+#include <libcamera/base/event_notifier.h>\n+#include <libcamera/base/log.h>\n+\n+/**\n+ * \\file v4l2_request.h\n+ * \\brief V4L2 Request\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DECLARE_CATEGORY(V4L2)\n+\n+/**\n+ * \\class V4L2Request\n+ * \\brief V4L2Request object and API\n+ *\n+ * The V4L2Request class wraps a V4L2 request fd and provides some convenience\n+ * functions to handle request.\n+ *\n+ * It is usually constructed by calling \\a MediaDevice::allocateRequests().\n+ *\n+ * A request can then be passed to the V4L2Device::setControls(),\n+ * V4L2Device::getControls() and V4L2VideoDevice::queueBuffer().\n+ */\n+\n+/**\n+ * \\brief Construct a V4L2Request\n+ * \\param[in] fd The request fd\n+ */\n+V4L2Request::V4L2Request(UniqueFD &&fd)\n+\t: fd_(std::move(fd)), fdNotifier_(fd_.get(), EventNotifier::Exception)\n+{\n+\tif (!fd_.isValid())\n+\t\treturn;\n+\n+\tfdNotifier_.activated.connect(this, &V4L2Request::requestReady);\n+\tfdNotifier_.setEnabled(false);\n+}\n+\n+/**\n+ * \\fn V4L2Request::isValid()\n+ * \\brief Check if the request is valid\n+ *\n+ * Checks if the underlying fd is valid.\n+ *\n+ * \\return True if the request is valid, false otherwise\n+ */\n+\n+/**\n+ * \\fn V4L2Request::fd()\n+ * \\brief Get the file descriptor\n+ *\n+ * \\return The file descriptor wrapped by this V4L2Request\n+ */\n+\n+/**\n+ * \\var V4L2Request::requestDone\n+ * \\brief Signal that is emitted when the request is done\n+ */\n+\n+/**\n+ * \\brief Reinit the request\n+ *\n+ * Calls MEDIA_REQUEST_IOC_REINIT on the request fd.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2Request::reinit()\n+{\n+\tfdNotifier_.setEnabled(false);\n+\n+\tif (::ioctl(fd_.get(), MEDIA_REQUEST_IOC_REINIT) < 0)\n+\t\treturn -errno;\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\brief Queue the request\n+ *\n+ * Calls MEDIA_REQUEST_IOC_QUEUE on the request fd.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int V4L2Request::queue()\n+{\n+\tif (::ioctl(fd_.get(), MEDIA_REQUEST_IOC_QUEUE) < 0)\n+\t\treturn -errno;\n+\n+\tfdNotifier_.setEnabled(true);\n+\n+\treturn 0;\n+}\n+\n+std::string V4L2Request::logPrefix() const\n+{\n+\treturn \"Request [\" + std::to_string(fd()) + \"]\";\n+}\n+\n+/**\n+ * \\brief Slot to handle request done events\n+ *\n+ * When this slot is called, the request is done and the requestDone will be\n+ * emitted.\n+ */\n+void V4L2Request::requestReady()\n+{\n+\trequestDone.emit(this);\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp\nindex 7b48d911db73..25b61d049a0e 100644\n--- a/src/libcamera/v4l2_videodevice.cpp\n+++ b/src/libcamera/v4l2_videodevice.cpp\n@@ -30,6 +30,7 @@\n #include \"libcamera/internal/framebuffer.h\"\n #include \"libcamera/internal/media_device.h\"\n #include \"libcamera/internal/media_object.h\"\n+#include \"libcamera/internal/v4l2_request.h\"\n \n /**\n  * \\file v4l2_videodevice.h\n@@ -1629,6 +1630,7 @@ int V4L2VideoDevice::releaseBuffers()\n /**\n  * \\brief Queue a buffer to the video device\n  * \\param[in] buffer The buffer to be queued\n+ * \\param[in] request An optional request\n  *\n  * For capture video devices the \\a buffer will be filled with data by the\n  * device. For output video devices the \\a buffer shall contain valid data and\n@@ -1641,9 +1643,11 @@ int V4L2VideoDevice::releaseBuffers()\n  * Note that queueBuffer() will fail if the device is in the process of being\n  * stopped from a streaming state through streamOff().\n  *\n+ * If \\a request is specified, the buffer will be tied to that request.\n+ *\n  * \\return 0 on success or a negative error code otherwise\n  */\n-int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)\n+int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer, const V4L2Request *request)\n {\n \tstruct v4l2_plane v4l2Planes[VIDEO_MAX_PLANES] = {};\n \tstruct v4l2_buffer buf = {};\n@@ -1674,6 +1678,10 @@ int V4L2VideoDevice::queueBuffer(FrameBuffer *buffer)\n \tbuf.type = bufferType_;\n \tbuf.memory = memoryType_;\n \tbuf.field = V4L2_FIELD_NONE;\n+\tif (request) {\n+\t\tbuf.flags = V4L2_BUF_FLAG_REQUEST_FD;\n+\t\tbuf.request_fd = request->fd();\n+\t}\n \n \tbool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);\n \tSpan<const FrameBuffer::Plane> planes = buffer->planes();\n","prefixes":["v3","03/29"]}