summaryrefslogtreecommitdiff
path: root/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
diff options
context:
space:
mode:
authorNaushir Patuck <naush@raspberrypi.com>2020-09-18 10:42:27 +0100
committerNiklas Söderlund <niklas.soderlund@ragnatech.se>2020-09-21 13:10:48 +0200
commit2df7bf168105d02e7f2cb8090938d58eccd208f1 (patch)
tree711fff9f67387d49015721c75894e7f47af043b1 /src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
parent3e7ee080d6dcc3f674ccdd14e08b7cf25df06ddd (diff)
libcamera: pipeline: raspberrypi: Rework stream buffer logic for zero-copy
Stop using v4l2_videodevice::allocateBuffer() for internal buffers and instead export/import all buffers. This allows the pipeline to return any stream buffer requested by the application as zero-copy. Advertise the Unicam Image stream as the RAW capture stream now. The RPiStream object now maintains a new list of buffers that are available to queue into a device. This is needed to distinguish between FrameBuffers allocated for internal use vs externally provided buffers. When a Request comes in, if a buffer is not provided for an exported stream, we re-use a buffer from this list. 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>
Diffstat (limited to 'src/libcamera/pipeline/raspberrypi/rpi_stream.cpp')
-rw-r--r--src/libcamera/pipeline/raspberrypi/rpi_stream.cpp118
1 files changed, 83 insertions, 35 deletions
diff --git a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
index 2e52bd5c..b4d737db 100644
--- a/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
+++ b/src/libcamera/pipeline/raspberrypi/rpi_stream.cpp
@@ -27,78 +27,120 @@ std::string RPiStream::name() const
void RPiStream::reset()
{
external_ = false;
- internalBuffers_.clear();
-}
-
-bool RPiStream::isImporter() const
-{
- return importOnly_;
+ clearBuffers();
}
void RPiStream::setExternal(bool external)
{
+ /* Import streams cannot be external. */
+ ASSERT(!external || !importOnly_);
external_ = external;
}
bool RPiStream::isExternal() const
{
- /*
- * Import streams cannot be external.
- *
- * RAW capture is a special case where we simply copy the RAW
- * buffer out of the request. All other buffer handling happens
- * as if the stream is internal.
- */
- return external_ && !importOnly_;
+ return external_;
}
-void RPiStream::setExternalBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
+void RPiStream::setExportedBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
{
- externalBuffers_ = buffers;
+ std::transform(buffers->begin(), buffers->end(), std::back_inserter(bufferList_),
+ [](std::unique_ptr<FrameBuffer> &b) { return b.get(); });
}
-const std::vector<std::unique_ptr<FrameBuffer>> *RPiStream::getBuffers() const
+const std::vector<FrameBuffer *> &RPiStream::getBuffers() const
{
- return external_ ? externalBuffers_ : &internalBuffers_;
+ return bufferList_;
}
bool RPiStream::findFrameBuffer(FrameBuffer *buffer) const
{
- auto start = external_ ? externalBuffers_->begin() : internalBuffers_.begin();
- auto end = external_ ? externalBuffers_->end() : internalBuffers_.end();
-
if (importOnly_)
return false;
- if (std::find_if(start, end,
- [buffer](std::unique_ptr<FrameBuffer> const &ref) { return ref.get() == buffer; }) != end)
+ if (std::find(bufferList_.begin(), bufferList_.end(), buffer) != bufferList_.end())
return true;
return false;
}
-int RPiStream::importBuffers(unsigned int count)
+int RPiStream::prepareBuffers(unsigned int count)
{
+ int ret;
+
+ if (!importOnly_) {
+ if (count) {
+ /* Export some frame buffers for internal use. */
+ ret = dev_->exportBuffers(count, &internalBuffers_);
+ if (ret < 0)
+ return ret;
+
+ /* Add these exported buffers to the internal/external buffer list. */
+ setExportedBuffers(&internalBuffers_);
+
+ /* Add these buffers to the queue of internal usable buffers. */
+ for (auto const &buffer : internalBuffers_)
+ availableBuffers_.push(buffer.get());
+ }
+
+ /* We must import all internal/external exported buffers. */
+ count = bufferList_.size();
+ }
+
return dev_->importBuffers(count);
}
-int RPiStream::allocateBuffers(unsigned int count)
+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.
+ */
+ if (!buffer) {
+ if (availableBuffers_.empty()) {
+ LOG(RPISTREAM, Warning) << "No buffers available for "
+ << name_;
+ return -EINVAL;
+ }
+
+ 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_;
+ }
+
+ return ret;
+}
+
+void RPiStream::returnBuffer(FrameBuffer *buffer)
{
- return dev_->allocateBuffers(count, &internalBuffers_);
+ /* This can only be called for external streams. */
+ assert(external_);
+
+ availableBuffers_.push(buffer);
}
-int RPiStream::queueBuffers()
+int RPiStream::queueAllBuffers()
{
+ int ret;
+
if (external_)
return 0;
- for (auto &b : internalBuffers_) {
- int ret = dev_->queueBuffer(b.get());
- if (ret) {
- LOG(RPISTREAM, Error) << "Failed to queue buffers for "
- << name_;
+ while (!availableBuffers_.empty()) {
+ ret = queueBuffer(availableBuffers_.front());
+ if (ret < 0)
return ret;
- }
+
+ availableBuffers_.pop();
}
return 0;
@@ -107,8 +149,14 @@ int RPiStream::queueBuffers()
void RPiStream::releaseBuffers()
{
dev_->releaseBuffers();
- if (!external_ && !importOnly_)
- internalBuffers_.clear();
+ clearBuffers();
+}
+
+void RPiStream::clearBuffers()
+{
+ availableBuffers_ = std::queue<FrameBuffer *>{};
+ internalBuffers_.clear();
+ bufferList_.clear();
}
} /* namespace RPi */