diff --git a/Documentation/guides/pipeline-handler.rst b/Documentation/guides/pipeline-handler.rst
index 3ee79b98c4dc..96d4490d06fa 100644
--- a/Documentation/guides/pipeline-handler.rst
+++ b/Documentation/guides/pipeline-handler.rst
@@ -447,11 +447,27 @@ it will be used:
           int init();
           void bufferReady(FrameBuffer *buffer);
 
+          void queuePendingRequests();
+          void cancelPendingRequests();
+
+          void setAvailableBufferSlotCount(unsigned int count) { availableBufferSlotCount_ = count; }
+
           MediaDevice *media_;
           V4L2VideoDevice *video_;
           Stream stream_;
+
+          std::queue<Request *> pendingRequests_;
+
+   private:
+          unsigned int availableBufferSlotCount_;
    };
 
+And the following include needs to be added:
+
+.. code-block:: cpp
+
+   #include <queue>
+
 This example pipeline handler handles a single video device and supports a
 single stream, represented by the ``VividCameraData`` class members. More
 complex pipeline handlers might register cameras composed of several video
@@ -1218,7 +1234,8 @@ algorithms, or other devices you should also stop them.
 
 Of course we also need to handle the corresponding actions to stop streaming on
 a device, Add the following to the ``stop`` function, to stop the stream with
-the `streamOff`_ function and release all buffers.
+the `streamOff`_ function and release all buffers. Additionally we need to
+cancel pending requests, the reason will become clearer in the next section.
 
 .. _streamOff: http://libcamera.org/api-html/classlibcamera_1_1V4L2VideoDevice.html#a61998710615bdf7aa25a046c8565ed66
 
@@ -1226,6 +1243,7 @@ the `streamOff`_ function and release all buffers.
 
    VividCameraData *data = cameraData(camera);
    data->video_->streamOff();
+   data->cancelPendingRequests();
    data->video_->releaseBuffers();
 
 Queuing requests between applications and hardware
@@ -1246,25 +1264,76 @@ directly with the `queueBuffer`_ function provided by the V4L2VideoDevice.
 .. _findBuffer: http://libcamera.org/api-html/classlibcamera_1_1Request.html#ac66050aeb9b92c64218945158559c4d4
 .. _queueBuffer: http://libcamera.org/api-html/classlibcamera_1_1V4L2VideoDevice.html#a594cd594686a8c1cf9ae8dba0b2a8a75
 
+Since the pipeline handler has a finite number of buffer slots allocated through
+importBuffers(), in order to not drop frames when more requests than that are
+queued by the application, we need to implement a queue to hold the requests and
+queue them to the devices as slots become available.
+
 Replace the stubbed contents of ``queueRequestDevice`` with the following:
 
 .. code-block:: cpp
 
    VividCameraData *data = cameraData(camera);
-   FrameBuffer *buffer = request->findBuffer(&data->stream_);
-   if (!buffer) {
+   if (!request->findBuffer(&data->stream_)) {
           LOG(VIVID, Error)
                   << "Attempt to queue request with invalid stream";
 
           return -ENOENT;
    }
 
-   int ret = data->video_->queueBuffer(buffer);
-   if (ret < 0)
-          return ret;
+   data->pendingRequests_.push(request);
+   data->queuePendingRequests();
 
    return 0;
 
+Now create the ``queuePendingRequests`` function for ``VividCameraData`` and
+inside it add:
+
+.. code-block:: cpp
+
+   while (!pendingRequests_.empty() && availableBufferSlotCount_) {
+           Request *request = pendingRequests_.front();
+           FrameBuffer *buffer = request->findBuffer(&stream_);
+
+           ret = video_->queueBuffer(buffer);
+           if (ret < 0) {
+                   LOG(UVC, Error) << "Failed to queue buffer with error "
+                                   << ret << ". Cancelling buffer.";
+                   buffer->cancel();
+                   pipe()->completeBuffer(request, buffer);
+                   pipe()->completeRequest(request);
+                   pendingRequests_.pop();
+
+                   continue;
+           }
+
+           availableBufferSlotCount_--;
+
+           pendingRequests_.pop();
+   }
+
+Create ``cancelPendingRequests`` as well with:
+
+.. code-block:: cpp
+
+   while (!pendingRequests_.empty()) {
+           Request *request = pendingRequests_.front();
+           FrameBuffer *buffer = request->findBuffer(&stream_);
+
+           buffer->cancel();
+           pipe()->completeBuffer(request, buffer);
+           pipe()->completeRequest(request);
+
+           pendingRequests_.pop();
+   }
+
+Finally we need to initialize the buffer slot count in ``start()``. Add the
+following line there:
+
+.. code-block:: cpp
+
+   data->setAvailableBufferSlotCount(count);
+
 Processing controls
 ~~~~~~~~~~~~~~~~~~~
 
@@ -1339,31 +1408,27 @@ where appropriate by setting controls on V4L2Subdevices directly. Each pipeline
 handler is responsible for understanding the correct procedure for applying
 controls to the device they support.
 
-This example pipeline handler applies controls during the `queueRequestDevice`_
-function for each request, and applies them to the capture device through the
-capture node.
-
-.. _queueRequestDevice: http://libcamera.org/api-html/classlibcamera_1_1PipelineHandler.html#a106914cca210640c9da9ee1f0419e83c
+This example pipeline handler applies controls as soon as the request is queued
+to the device from ``queuePendingRequests``, and applies them to the capture
+device through the capture node.
 
-In the ``queueRequestDevice`` function, replace the following:
+In the ``queuePendingRequests`` function, before the line ``ret =
+video_->queueBuffer(buffer);``, add the following:
 
 .. code-block:: cpp
 
-   int ret = data->video_->queueBuffer(buffer);
-   if (ret < 0)
-        return ret;
-
-With the following code:
-
-.. code-block:: cpp
-
-   int ret = processControls(data, request);
-   if (ret < 0)
-        return ret;
-
-   ret = data->video_->queueBuffer(buffer);
-   if (ret < 0)
-        return ret;
+   int ret = processControls(request);
+   if (ret < 0) {
+           LOG(UVC, Error) << "Failed to process controls with"
+                           << " error " << ret << ". Cancelling"
+                           << " buffer.";
+           buffer->cancel();
+           pipe()->completeBuffer(request, buffer);
+           pipe()->completeRequest(request);
+           pendingRequests_.pop();
+
+           continue;
+   }
 
 We also need to add the following include directive to support the control
 value translation operations:
@@ -1427,9 +1492,10 @@ VividCameradata::init() impelementation.
 The ``bufferReady`` function obtains the request from the buffer using the
 ``request`` function, and notifies the ``Camera`` that the buffer and
 request are completed. In this simpler pipeline handler, there is only one
-stream, so it completes the request immediately. You can find a more complex
-example of event handling with supporting multiple streams in the libcamera
-code-base.
+stream, so it completes the request immediately. It also updates the number of
+available buffer slots and tries to queue any pending requests. You can find a
+more complex example of event handling with support to multiple streams in the
+libcamera code-base.
 
 .. TODO: Add link
 
@@ -1441,6 +1507,9 @@ code-base.
 
           pipe_->completeBuffer(request, buffer);
           pipe_->completeRequest(request);
+
+          availableBufferSlotCount_++;
+          queuePendingRequests();
    }
 
 Testing a pipeline handler
