[libcamera-devel] [PATCH v7 08/12] libcamera: pipeline: raspberrypi: Add more robust stream buffer logic
Kieran Bingham
kieran.bingham at ideasonboard.com
Tue Sep 15 15:17:06 CEST 2020
Hi Naush,
On 08/09/2020 08:49, 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>
> Reviewed-by: Niklas Söderlund <niklas.soderlund at ragnatech.se>
> Tested-by: David Plowman <david.plowman at raspberrypi.com>
Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
> ---
> .../pipeline/raspberrypi/rpi_stream.cpp | 76 +++++++++++++++----
> .../pipeline/raspberrypi/rpi_stream.h | 13 +++-
> 2 files changed, 75 insertions(+), 14 deletions(-)
>
> diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> index b4d737db..b2a5dfa7 100644
> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
> @@ -94,38 +94,75 @@ int RPiStream::queueBuffer(FrameBuffer *buffer)
> {
> /*
> * A nullptr buffer implies an external stream, but no external
> - * buffer has been supplied. So, pick one from the availableBuffers_
> - * queue.
> + * buffer has been supplied in the Request. So, pick one from the
> + * availableBuffers_ queue.
> */
> 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 queue an internal buffer as soon
> + * as one becomes available.
> + */
> + requestBuffers_.push(nullptr);
> + return 0;
> }
>
> buffer = availableBuffers_.front();
> availableBuffers_.pop();
> }
>
> - LOG(RPISTREAM, Debug) << "Queuing buffer " << buffer->cookie()
> - << " for " << name_;
> + /*
> + * If no earlier requests are pending to be queued we can go ahead and
> + * queue this buffer into the device.
> + */
> + if (requestBuffers_.empty())
> + return queueToDevice(buffer);
>
> - int ret = dev_->queueBuffer(buffer);
> - if (ret) {
> - LOG(RPISTREAM, Error) << "Failed to queue buffer for "
> - << name_;
> - }
> + /*
> + * There are earlier Request buffers to be queued, so this buffer must go
> + * on the waiting list.
> + */
> + requestBuffers_.push(buffer);
>
> - return ret;
> + return 0;
> }
>
> void RPiStream::returnBuffer(FrameBuffer *buffer)
> {
> /* This can only be called for external streams. */
> - assert(external_);
> + ASSERT(external_);
>
> + /* Push this buffer back into the queue to be used again. */
> availableBuffers_.push(buffer);
> +
> + /*
> + * Do we have any Request buffers that are waiting to be queued?
> + * If so, do it now as availableBuffers_ will not be empty.
> + */
> + while (!requestBuffers_.empty()) {
> + FrameBuffer *buffer = requestBuffers_.front();
> +
> + 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();
> + }
> +
> + requestBuffers_.pop();
> + queueToDevice(buffer);
> + }
> }
>
> int RPiStream::queueAllBuffers()
> @@ -155,10 +192,23 @@ void RPiStream::releaseBuffers()
> void RPiStream::clearBuffers()
> {
> availableBuffers_ = std::queue<FrameBuffer *>{};
> + requestBuffers_ = 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 73954ec7..f42e25b9 100644
> --- a/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> +++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.h
> @@ -57,6 +57,7 @@ public:
>
> private:
> void clearBuffers();
> + int queueToDevice(FrameBuffer *buffer);
>
> /*
> * Indicates that this stream is active externally, i.e. the buffers
> @@ -73,7 +74,7 @@ private:
> /* 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_;
>
> /*
> @@ -83,6 +84,16 @@ private:
> */
> std::queue<FrameBuffer *> availableBuffers_;
>
> + /*
> + * List of frame buffers that are to be queued into the device from a Request.
> + * 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 *> requestBuffers_;
> +
> /*
> * This is a list of buffers exported internally. Need to keep this around
> * as the stream needs to maintain ownership of these buffers.
>
--
Regards
--
Kieran
More information about the libcamera-devel
mailing list