libcamera: pipeline: raspberrypi: Add more robust stream buffer logic
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@raspberrypi.com> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Tested-by: David Plowman <david.plowman@raspberrypi.com> Signed-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>
This commit is contained in:
parent
45430e12ee
commit
b752c57c33
2 changed files with 75 additions and 14 deletions
|
@ -94,38 +94,75 @@ int RPiStream::queueBuffer(FrameBuffer *buffer)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* A nullptr buffer implies an external stream, but no external
|
* A nullptr buffer implies an external stream, but no external
|
||||||
* buffer has been supplied. So, pick one from the availableBuffers_
|
* buffer has been supplied in the Request. So, pick one from the
|
||||||
* queue.
|
* availableBuffers_ queue.
|
||||||
*/
|
*/
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
if (availableBuffers_.empty()) {
|
if (availableBuffers_.empty()) {
|
||||||
LOG(RPISTREAM, Warning) << "No buffers available for "
|
LOG(RPISTREAM, Info) << "No buffers available for "
|
||||||
<< name_;
|
<< 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();
|
buffer = availableBuffers_.front();
|
||||||
availableBuffers_.pop();
|
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) {
|
* There are earlier Request buffers to be queued, so this buffer must go
|
||||||
LOG(RPISTREAM, Error) << "Failed to queue buffer for "
|
* on the waiting list.
|
||||||
<< name_;
|
*/
|
||||||
}
|
requestBuffers_.push(buffer);
|
||||||
|
|
||||||
return ret;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPiStream::returnBuffer(FrameBuffer *buffer)
|
void RPiStream::returnBuffer(FrameBuffer *buffer)
|
||||||
{
|
{
|
||||||
/* This can only be called for external streams. */
|
/* 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);
|
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()
|
int RPiStream::queueAllBuffers()
|
||||||
|
@ -155,10 +192,23 @@ void RPiStream::releaseBuffers()
|
||||||
void RPiStream::clearBuffers()
|
void RPiStream::clearBuffers()
|
||||||
{
|
{
|
||||||
availableBuffers_ = std::queue<FrameBuffer *>{};
|
availableBuffers_ = std::queue<FrameBuffer *>{};
|
||||||
|
requestBuffers_ = std::queue<FrameBuffer *>{};
|
||||||
internalBuffers_.clear();
|
internalBuffers_.clear();
|
||||||
bufferList_.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 RPi */
|
||||||
|
|
||||||
} /* namespace libcamera */
|
} /* namespace libcamera */
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void clearBuffers();
|
void clearBuffers();
|
||||||
|
int queueToDevice(FrameBuffer *buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Indicates that this stream is active externally, i.e. the buffers
|
* Indicates that this stream is active externally, i.e. the buffers
|
||||||
|
@ -73,7 +74,7 @@ private:
|
||||||
/* The actual device stream. */
|
/* The actual device stream. */
|
||||||
std::unique_ptr<V4L2VideoDevice> dev_;
|
std::unique_ptr<V4L2VideoDevice> dev_;
|
||||||
|
|
||||||
/* All framebuffers associated with this device stream. */
|
/* All frame buffers associated with this device stream. */
|
||||||
std::vector<FrameBuffer *> bufferList_;
|
std::vector<FrameBuffer *> bufferList_;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -83,6 +84,16 @@ private:
|
||||||
*/
|
*/
|
||||||
std::queue<FrameBuffer *> availableBuffers_;
|
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
|
* This is a list of buffers exported internally. Need to keep this around
|
||||||
* as the stream needs to maintain ownership of these buffers.
|
* as the stream needs to maintain ownership of these buffers.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue