{"id":24733,"url":"https://patchwork.libcamera.org/api/1.1/patches/24733/?format=json","web_url":"https://patchwork.libcamera.org/patch/24733/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/1.1/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":"<20251023144841.403689-6-stefan.klug@ideasonboard.com>","date":"2025-10-23T14:48:06","name":"[v2,05/35] libcamera: Add support for V4L2 requests","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"3ab9f51d175e5e95e5cf8c76808ac42d8ca62329","submitter":{"id":184,"url":"https://patchwork.libcamera.org/api/1.1/people/184/?format=json","name":"Stefan Klug","email":"stefan.klug@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/24733/mbox/","series":[{"id":5520,"url":"https://patchwork.libcamera.org/api/1.1/series/5520/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=5520","date":"2025-10-23T14:48:01","name":"Full dewarper support on imx8mp","version":2,"mbox":"https://patchwork.libcamera.org/series/5520/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/24733/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/24733/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 43E24C3334\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu, 23 Oct 2025 14:49:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id BC2F7607F3;\n\tThu, 23 Oct 2025 16:49:02 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2D82E607ED\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 23 Oct 2025 16:49:01 +0200 (CEST)","from ideasonboard.com (unknown\n\t[IPv6:2a00:6020:448c:6c00:7328:357b:4ce1:72b6])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 27C321127; \n\tThu, 23 Oct 2025 16:47:16 +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=\"NmfaY7Lb\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1761230836;\n\tbh=ii1ugYfLMAI//VqbVDO7XTRzNSKRFP1iGseToSeFtkw=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=NmfaY7Lb3WYWdF6MM2HX1Y8krZR3gm8BTu13YZdjBz/Nn25eGO3ZqeTnBFdEEVSWo\n\tt+QTuuQK9REb1VgJzb44fgjs8G6JCeeiTepJcVhEWEBWvLOhg8Jqj6EMBjg/wwzyYQ\n\tKZsrajZfGRR/pHpgnH/NrQH56vDe7C6kCsgDkNb0=","From":"Stefan Klug <stefan.klug@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Cc":"Stefan Klug <stefan.klug@ideasonboard.com>","Subject":"[PATCH v2 05/35] libcamera: Add support for V4L2 requests","Date":"Thu, 23 Oct 2025 16:48:06 +0200","Message-ID":"<20251023144841.403689-6-stefan.klug@ideasonboard.com>","X-Mailer":"git-send-email 2.48.1","In-Reply-To":"<20251023144841.403689-1-stefan.klug@ideasonboard.com>","References":"<20251023144841.403689-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 a fd that is allocated vi\nMEDIA_IOC_REQUEST_ALLOC and then passed to various V4L2 function.\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 v2:\n- Added documentation\n---\n include/libcamera/internal/media_device.h     |   7 +\n include/libcamera/internal/meson.build        |   1 +\n include/libcamera/internal/v4l2_device.h      |   5 +-\n include/libcamera/internal/v4l2_request.h     |  49 +++++++\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                 |  28 +++-\n src/libcamera/v4l2_request.cpp                | 128 ++++++++++++++++++\n src/libcamera/v4l2_videodevice.cpp            |  10 +-\n 10 files changed, 271 insertions(+), 8 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..74cb9ba1542d 100644\n--- a/include/libcamera/internal/media_device.h\n+++ b/include/libcamera/internal/media_device.h\n@@ -18,6 +18,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 +58,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 +93,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..bf1bea3261af\n--- /dev/null\n+++ b/include/libcamera/internal/v4l2_request.h\n@@ -0,0 +1,49 @@\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/span.h>\n+#include <libcamera/base/unique_fd.h>\n+\n+#include <libcamera/color_space.h>\n+#include <libcamera/controls.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(int fd = -1);\n+\t~V4L2Request() = default;\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 5a7dcfdda118..2d290971a0ee 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..673c53fefdd7 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+ * and 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>(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..7a669a0303c1 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 And 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 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..708250d86f61\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(int fd)\n+\t: fd_(fd), fdNotifier_(fd, 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 om 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 Reinit the request\n+ *\n+ * Calls MEDIA_REQUEST_IOC_QUEUE om 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 bb57c1b76a5b..8ce739f4bc65 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":["v2","05/35"]}