Show a patch.

GET /api/1.1/patches/23289/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 23289,
    "url": "https://patchwork.libcamera.org/api/1.1/patches/23289/?format=api",
    "web_url": "https://patchwork.libcamera.org/patch/23289/",
    "project": {
        "id": 1,
        "url": "https://patchwork.libcamera.org/api/1.1/projects/1/?format=api",
        "name": "libcamera",
        "link_name": "libcamera",
        "list_id": "libcamera_core",
        "list_email": "libcamera-devel@lists.libcamera.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20250428090413.38234-19-s.pueschel@pengutronix.de>",
    "date": "2025-04-28T09:02:43",
    "name": "[v11,18/19] Documentation: guides: pipeline-handler: Document internal queue pattern",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "24e015c440630233fdf5098153792aa200198b9a",
    "submitter": {
        "id": 225,
        "url": "https://patchwork.libcamera.org/api/1.1/people/225/?format=api",
        "name": "Sven Püschel",
        "email": "s.pueschel@pengutronix.de"
    },
    "delegate": null,
    "mbox": "https://patchwork.libcamera.org/patch/23289/mbox/",
    "series": [
        {
            "id": 5148,
            "url": "https://patchwork.libcamera.org/api/1.1/series/5148/?format=api",
            "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=5148",
            "date": "2025-04-28T09:02:25",
            "name": "lc-compliance: Add test to queue more requests than hardware depth",
            "version": 11,
            "mbox": "https://patchwork.libcamera.org/series/5148/mbox/"
        }
    ],
    "comments": "https://patchwork.libcamera.org/api/patches/23289/comments/",
    "check": "pending",
    "checks": "https://patchwork.libcamera.org/api/patches/23289/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 9004AC3328\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 28 Apr 2025 09:05:40 +0000 (UTC)",
            "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 885EC68B3E;\n\tMon, 28 Apr 2025 11:05:39 +0200 (CEST)",
            "from metis.whiteo.stw.pengutronix.de\n\t(metis.whiteo.stw.pengutronix.de [IPv6:2a0a:edc0:2:b01:1d::104])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 354A068B2B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 28 Apr 2025 11:05:09 +0200 (CEST)",
            "from ptz.office.stw.pengutronix.de ([2a0a:edc0:0:900:1d::77]\n\thelo=peter.guest.stw.pengutronix.de)\n\tby metis.whiteo.stw.pengutronix.de with esmtp (Exim 4.92)\n\t(envelope-from <s.pueschel@pengutronix.de>)\n\tid 1u9KQG-0001au-Qr; Mon, 28 Apr 2025 11:05:08 +0200"
        ],
        "From": "=?utf-8?q?Sven_P=C3=BCschel?= <s.pueschel@pengutronix.de>",
        "To": "libcamera-devel@lists.libcamera.org",
        "Cc": "=?utf-8?b?TsOtY29sYXMgRi4gUi4gQS4gUHJhZG8=?= <nfraprado@collabora.com>, \n\t=?utf-8?q?Sven_P=C3=BCschel?= <s.pueschel@pengutronix.de>",
        "Subject": "[PATCH v11 18/19] Documentation: guides: pipeline-handler: Document\n\tinternal queue pattern",
        "Date": "Mon, 28 Apr 2025 11:02:43 +0200",
        "Message-ID": "<20250428090413.38234-19-s.pueschel@pengutronix.de>",
        "X-Mailer": "git-send-email 2.49.0",
        "In-Reply-To": "<20250428090413.38234-1-s.pueschel@pengutronix.de>",
        "References": "<20250428090413.38234-1-s.pueschel@pengutronix.de>",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=UTF-8",
        "Content-Transfer-Encoding": "8bit",
        "X-SA-Exim-Connect-IP": "2a0a:edc0:0:900:1d::77",
        "X-SA-Exim-Mail-From": "s.pueschel@pengutronix.de",
        "X-SA-Exim-Scanned": "No (on metis.whiteo.stw.pengutronix.de);\n\tSAEximRunCond expanded to false",
        "X-PTX-Original-Recipient": "libcamera-devel@lists.libcamera.org",
        "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": "From: Nícolas F. R. A. Prado <nfraprado@collabora.com>\n\nPipeline handlers need to implement a common pattern of adding queued\nrequests to an internal queue and queuing them to the video devices as\nthe buffer slots there become available.\n\nAdd this pattern to the vivid example in the pipeline-handler guide so\nit's clear that new pipeline handlers should also implement it.\n\nSigned-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>\nSigned-off-by: Sven Püschel <s.pueschel@pengutronix.de>\n\n---\nChanges in v11:\n- Added from https://lists.libcamera.org/pipermail/libcamera-devel/2021-September/024121.html\n---\n Documentation/guides/pipeline-handler.rst | 129 +++++++++++++++++-----\n 1 file changed, 99 insertions(+), 30 deletions(-)",
    "diff": "diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst\nindex 725e35e6..a42d1aca 100644\n--- a/Documentation/guides/pipeline-handler.rst\n+++ b/Documentation/guides/pipeline-handler.rst\n@@ -452,11 +452,27 @@ it will be used:\n           int init();\n           void bufferReady(FrameBuffer *buffer);\n \n+          void queuePendingRequests();\n+          void cancelPendingRequests();\n+\n+          void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; }\n+\n           MediaDevice *media_;\n           V4L2VideoDevice *video_;\n           Stream stream_;\n+\n+          std::queue<Request *> pendingRequests_;\n+\n+   private:\n+          unsigned int availableBufferSlotCount_;\n    };\n \n+And the following include needs to be added:\n+\n+.. code-block:: cpp\n+\n+   #include <queue>\n+\n This example pipeline handler handles a single video device and supports a\n single stream, represented by the ``VividCameraData`` class members. More\n complex pipeline handlers might register cameras composed of several video\n@@ -1274,7 +1290,8 @@ algorithms, or other devices you should also stop them.\n \n Of course we also need to handle the corresponding actions to stop streaming on\n a device, Add the following to the ``stop`` function, to stop the stream with\n-the `streamOff`_ function and release all buffers.\n+the `streamOff`_ function and release all buffers. Additionally we need to\n+cancel pending requests, the reason will become clearer in the next section.\n \n .. _streamOff: https://libcamera.org/api-html/classlibcamera_1_1V4L2VideoDevice.html#a61998710615bdf7aa25a046c8565ed66\n \n@@ -1282,6 +1299,7 @@ the `streamOff`_ function and release all buffers.\n \n    VividCameraData *data = cameraData(camera);\n    data->video_->streamOff();\n+   data->cancelPendingRequests();\n    data->video_->releaseBuffers();\n \n Queuing requests between applications and hardware\n@@ -1302,25 +1320,76 @@ directly with the `queueBuffer`_ function provided by the V4L2VideoDevice.\n .. _findBuffer: https://libcamera.org/api-html/classlibcamera_1_1Request.html#ac66050aeb9b92c64218945158559c4d4\n .. _queueBuffer: https://libcamera.org/api-html/classlibcamera_1_1V4L2VideoDevice.html#a594cd594686a8c1cf9ae8dba0b2a8a75\n \n+Since the pipeline handler has a finite number of buffer slots allocated through\n+importBuffers(), in order to not drop frames when more requests than that are\n+queued by the application, we need to implement a queue to hold the requests and\n+queue them to the devices as slots become available.\n+\n Replace the stubbed contents of ``queueRequestDevice`` with the following:\n \n .. code-block:: cpp\n \n    VividCameraData *data = cameraData(camera);\n-   FrameBuffer *buffer = request->findBuffer(&data->stream_);\n-   if (!buffer) {\n+   if (!request->findBuffer(&data->stream_)) {\n           LOG(VIVID, Error)\n                   << \"Attempt to queue request with invalid stream\";\n \n           return -ENOENT;\n    }\n \n-   int ret = data->video_->queueBuffer(buffer);\n-   if (ret < 0)\n-          return ret;\n+   data->pendingRequests_.push(request);\n+   data->queuePendingRequests();\n \n    return 0;\n \n+Now create the ``queuePendingRequests`` function for ``VividCameraData`` and\n+inside it add:\n+\n+.. code-block:: cpp\n+\n+   while (!pendingRequests_.empty() && availableBufferSlotCount_) {\n+           Request *request = pendingRequests_.front();\n+           FrameBuffer *buffer = request->findBuffer(&stream_);\n+\n+           ret = video_->queueBuffer(buffer);\n+           if (ret < 0) {\n+                   LOG(UVC, Error) << \"Failed to queue buffer with error \"\n+                                   << ret << \". Cancelling buffer.\";\n+                   buffer->_d()->cancel();\n+                   pipe()->completeBuffer(request, buffer);\n+                   pipe()->completeRequest(request);\n+                   pendingRequests_.pop();\n+\n+                   continue;\n+           }\n+\n+           availableBufferSlotCount_--;\n+\n+           pendingRequests_.pop();\n+   }\n+\n+Create ``cancelPendingRequests`` as well with:\n+\n+.. code-block:: cpp\n+\n+   while (!pendingRequests_.empty()) {\n+           Request *request = pendingRequests_.front();\n+           FrameBuffer *buffer = request->findBuffer(&stream_);\n+\n+           buffer->_d()->cancel();\n+           pipe()->completeBuffer(request, buffer);\n+           pipe()->completeRequest(request);\n+\n+           pendingRequests_.pop();\n+   }\n+\n+Finally we need to initialize the buffer slot count in ``start()``. Add the\n+following line there:\n+\n+.. code-block:: cpp\n+\n+   data->setAvailableBufferSlotCount(count);\n+\n Processing controls\n ~~~~~~~~~~~~~~~~~~~\n \n@@ -1395,31 +1464,27 @@ where appropriate by setting controls on V4L2Subdevices directly. Each pipeline\n handler is responsible for understanding the correct procedure for applying\n controls to the device they support.\n \n-This example pipeline handler applies controls during the `queueRequestDevice`_\n-function for each request, and applies them to the capture device through the\n-capture node.\n-\n-.. _queueRequestDevice: https://libcamera.org/api-html/classlibcamera_1_1PipelineHandler.html#a106914cca210640c9da9ee1f0419e83c\n+This example pipeline handler applies controls as soon as the request is queued\n+to the device from ``queuePendingRequests``, and applies them to the capture\n+device through the capture node.\n \n-In the ``queueRequestDevice`` function, replace the following:\n+In the ``queuePendingRequests`` function, before the line ``ret =\n+video_->queueBuffer(buffer);``, add the following:\n \n .. code-block:: cpp\n \n-   int ret = data->video_->queueBuffer(buffer);\n-   if (ret < 0)\n-        return ret;\n-\n-With the following code:\n-\n-.. code-block:: cpp\n-\n-   int ret = processControls(data, request);\n-   if (ret < 0)\n-        return ret;\n-\n-   ret = data->video_->queueBuffer(buffer);\n-   if (ret < 0)\n-        return ret;\n+   int ret = processControls(request);\n+   if (ret < 0) {\n+           LOG(UVC, Error) << \"Failed to process controls with\"\n+                           << \" error \" << ret << \". Cancelling\"\n+                           << \" buffer.\";\n+           buffer->_d()->cancel();\n+           pipe()->completeBuffer(request, buffer);\n+           pipe()->completeRequest(request);\n+           pendingRequests_.pop();\n+\n+           continue;\n+   }\n \n We also need to add the following include directive to support the control\n value translation operations:\n@@ -1483,9 +1548,10 @@ VividCameradata::init() implementation.\n The ``bufferReady`` function obtains the request from the buffer using the\n ``request`` function, and notifies the ``Camera`` that the buffer and\n request are completed. In this simpler pipeline handler, there is only one\n-stream, so it completes the request immediately. You can find a more complex\n-example of event handling with supporting multiple streams in the libcamera\n-code-base.\n+stream, so it completes the request immediately. It also updates the number of\n+available buffer slots and tries to queue any pending requests. You can find a\n+more complex example of event handling with support to multiple streams in the\n+libcamera code-base.\n \n .. TODO: Add link\n \n@@ -1497,6 +1563,9 @@ code-base.\n \n           pipe_->completeBuffer(request, buffer);\n           pipe_->completeRequest(request);\n+\n+          availableBufferSlotCount_++;\n+          queuePendingRequests();\n    }\n \n Testing a pipeline handler\n",
    "prefixes": [
        "v11",
        "18/19"
    ]
}