[libcamera-devel] [PATCH v3 08/10] libcamera: pipeline: raspberrypi: Add more robust stream buffer logic
Niklas Söderlund
niklas.soderlund at ragnatech.se
Sat Jul 18 17:41:59 CEST 2020
Hi Naushir,
Thanks for your work,
On 2020-07-17 09:54:08 +0100, Naushir Patuck wrote:
> Add further queueing into the RPiStream object to ensure that we always
> follow the buffer ordering (be it internal or external) given by
> incoming Requests.
>
> This is essential, otherwise we risk dropping frames that are meant to
> be part of a Request, and can cause the pipeline to stall indefinitely.
> This also prevents any possibility of mismatched frame buffers going
> through the pipeline and out to the application.
>
> Signed-off-by: Naushir Patuck <naush at raspberrypi.com>
> ---
> .../pipeline/raspberrypi/rpi_stream.cpp | 73 ++++++++++++++++---
> .../pipeline/raspberrypi/rpi_stream.h | 12 ++-
> 2 files changed, 73 insertions(+), 12 deletions(-)
>
> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> index 53a335e3..4818117e 100644
> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> @@ -112,25 +112,34 @@ int RPiStream::queueBuffer(FrameBuffer *buffer)
> */
> if (!buffer) {
> if (availableBuffers_.empty()) {
> - LOG(RPISTREAM, Warning) << "No buffers available for "
> + LOG(RPISTREAM, Info) << "No buffers available for "
> << name_;
> - return -EINVAL;
> + /*
> + * Note that we need to requeue an internal buffer as soon
> + * as one becomes available.
> + */
> + requeueBuffers_.push(nullptr);
> + return 0;
> }
>
> buffer = availableBuffers_.front();
> availableBuffers_.pop();
> }
>
> - LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie()
> - << " for " << name_;
> -
> - int ret = dev_->queueBuffer(buffer);
> - if (ret) {
> - LOG(RPISTREAM, Error) << "Failed to queue buffer for "
> - << name_;
> + if (requeueBuffers_.empty()) {
> + /*
> + * No earlier requests are pending to be queued, so we can
> + * go ahead and queue the buffer into the device.
> + */
> + return queueToDevice(buffer);
> + } else {
> + /*
> + * There are earlier buffers to be queued, so this buffer
> + * must go on the waiting list.
> + */
> + requeueBuffers_.push(buffer);
> + return 0;
> }
This could possibly be made easier to read,
/*
* If no earlier requests are pending to be queued we can
* go ahead and queue the buffer into the device.
/
if (requeueBuffers_.empty())
return queueToDevice(buffer);
/*
* There are earlier buffers to be queued, so this buffer
* must go on the waiting list.
*/
requeueBuffers_.push(buffer);
return 0;
> -
> - return ret;
> }
>
> void RPiStream::returnBuffer(FrameBuffer *buffer)
> @@ -138,7 +147,36 @@ void RPiStream::returnBuffer(FrameBuffer *buffer)
> /* This can only be called for external streams. */
> assert(external_);
>
> + /* Push this buffer back into the queue to be used again. */
> availableBuffers_.push(buffer);
> +
> + /*
> + * Do we have any buffers that are waiting to be queued?
> + * If so, do it now as availableBuffers_ will not be empty.
> + */
> + while (!requeueBuffers_.empty()) {
> + FrameBuffer *buffer = requeueBuffers_.front();
> +
> + if (!buffer && availableBuffers_.empty()) {
> + /*
> + * We want to queue an internal buffer, but none
> + * are available. Can't do anything, quit the loop.
> + */
> + break;
> + }
> +
> + if (!buffer) {
> + /*
> + * We want to queue an internal buffer, and at least one
> + * is available.
> + */
> + buffer = availableBuffers_.front();
> + availableBuffers_.pop();
> + }
Also this could be made easier to read.
if (!buffer) {
/*
* We want to queue an internal buffer, but none
* are available. Can't do anything, quit the loop.
*/
if (availableBuffers_.empty())
break;
/*
* We want to queue an internal buffer, and at least one
* is available.
*/
buffer = availableBuffers_.front();
availableBuffers_.pop();
}
Both my comments are nit on styler so with or without them addressed,
Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> +
> + requeueBuffers_.pop();
> + queueToDevice(buffer);
> + }
> }
>
> bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const
> @@ -155,10 +193,23 @@ bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const
> void RPiStream::clearBuffers()
> {
> availableBuffers_ = std::queue<FrameBuffer *>{};
> + requeueBuffers_ = std::queue<FrameBuffer *>{};
> internalBuffers_.clear();
> bufferList_.clear();
> }
>
> +int RPiStream::queueToDevice(FrameBuffer *buffer)
> +{
> + LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie()
> + << " for " << name_;
> +
> + int ret = dev_->queueBuffer(buffer);
> + if (ret)
> + LOG(RPISTREAM, Error) << "Failed to queue buffer for "
> + << name_;
> + return ret;
> +}
> +
> } /* namespace RPi */
>
> } /* namespace libcamera */
> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.h b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> index 019e236d..6c8dfa83 100644
> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> @@ -51,6 +51,7 @@ public:
>
> private:
> void clearBuffers();
> + int queueToDevice(FrameBuffer *buffer);
> /*
> * Indicates that this stream is active externally, i.e. the buffers
> * might be provided by (and returned to) the application.
> @@ -62,7 +63,7 @@ private:
> std::string name_;
> /* The actual device stream. */
> std::unique_ptr<V4L2VideoDevice> dev_;
> - /* All framebuffers associated with this device stream. */
> + /* All frame buffers associated with this device stream. */
> std::vector<FrameBuffer *> bufferList_;
> /*
> * List of frame buffer that we can use if none have been provided by
> @@ -70,6 +71,15 @@ private:
> * buffers exported internally.
> */
> std::queue<FrameBuffer *> availableBuffers_;
> + /*
> + * List of frame buffer that are to be re-queued into the device.
> + * A nullptr indicates any internal buffer can be used (from availableBuffers_),
> + * whereas a valid pointer indicates an external buffer to be queued.
> + *
> + * Ordering buffers to be queued is important here as it must match the
> + * requests coming from the application.
> + */
> + std::queue<FrameBuffer *> requeueBuffers_;
> /*
> * This is a list of buffers exported internally. Need to keep this around
> * as the stream needs to maintain ownership of these buffers.
> --
> 2.25.1
>
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel at lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel
--
Regards,
Niklas Söderlund
More information about the libcamera-devel
mailing list