@@ -888,7 +888,7 @@ void PipelineHandlerBase::mapBuffers(Camera *camera, const BufferMap &buffers, u
*/
for (auto const &it : buffers) {
bufferIds.push_back(IPABuffer(mask | it.first,
- it.second->planes()));
+ it.second.buffer->planes()));
data->bufferIds_.insert(mask | it.first);
}
@@ -6,6 +6,10 @@
*/
#include "rpi_stream.h"
+#include <algorithm>
+#include <tuple>
+#include <utility>
+
#include <libcamera/base/log.h>
/* Maximum number of buffer slots to allocate in the V4L2 device driver. */
@@ -17,8 +21,13 @@ LOG_DEFINE_CATEGORY(RPISTREAM)
namespace RPi {
+const BufferObject Stream::errorBufferObject{ nullptr, false };
+
void Stream::setFlags(StreamFlags flags)
{
+ /* We don't want dynamic mmapping. */
+ ASSERT(!(flags & StreamFlag::RequiresMmap));
+
flags_ |= flags;
/* Import streams cannot be external. */
@@ -27,6 +36,9 @@ void Stream::setFlags(StreamFlags flags)
void Stream::clearFlags(StreamFlags flags)
{
+ /* We don't want dynamic mmapping. */
+ ASSERT(!(flags & StreamFlag::RequiresMmap));
+
flags_ &= ~flags;
}
@@ -56,7 +68,7 @@ void Stream::resetBuffers()
void Stream::setExportedBuffers(std::vector<std::unique_ptr<FrameBuffer>> *buffers)
{
for (auto const &buffer : *buffers)
- bufferMap_.emplace(++id_, buffer.get());
+ bufferEmplace(++id_, buffer.get());
}
const BufferMap &Stream::getBuffers() const
@@ -71,7 +83,7 @@ unsigned int Stream::getBufferId(FrameBuffer *buffer) const
/* Find the buffer in the map, and return the buffer id. */
auto it = std::find_if(bufferMap_.begin(), bufferMap_.end(),
- [&buffer](auto const &p) { return p.second == buffer; });
+ [&buffer](auto const &p) { return p.second.buffer == buffer; });
if (it == bufferMap_.end())
return 0;
@@ -81,7 +93,7 @@ unsigned int Stream::getBufferId(FrameBuffer *buffer) const
void Stream::setExportedBuffer(FrameBuffer *buffer)
{
- bufferMap_.emplace(++id_, buffer);
+ bufferEmplace(++id_, buffer);
}
int Stream::prepareBuffers(unsigned int count)
@@ -180,6 +192,27 @@ void Stream::returnBuffer(FrameBuffer *buffer)
}
}
+const BufferObject &Stream::getBuffer(unsigned int id)
+{
+ auto const &it = bufferMap_.find(id);
+ if (it == bufferMap_.end())
+ return errorBufferObject;
+
+ return it->second;
+}
+
+const BufferObject &Stream::acquireBuffer()
+{
+ /* No id provided, so pick up the next available buffer if possible. */
+ if (availableBuffers_.empty())
+ return errorBufferObject;
+
+ unsigned int id = getBufferId(availableBuffers_.front());
+ availableBuffers_.pop();
+
+ return getBuffer(id);
+}
+
int Stream::queueAllBuffers()
{
int ret;
@@ -204,6 +237,16 @@ void Stream::releaseBuffers()
clearBuffers();
}
+void Stream::bufferEmplace(unsigned int id, FrameBuffer *buffer)
+{
+ if (flags_ & StreamFlag::RequiresMmap)
+ bufferMap_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
+ std::forward_as_tuple(buffer, true));
+ else
+ bufferMap_.emplace(std::piecewise_construct, std::forward_as_tuple(id),
+ std::forward_as_tuple(buffer, false));
+}
+
void Stream::clearBuffers()
{
availableBuffers_ = std::queue<FrameBuffer *>{};
@@ -7,22 +7,23 @@
#pragma once
+#include <optional>
#include <queue>
#include <string>
#include <unordered_map>
#include <vector>
#include <libcamera/base/flags.h>
+
#include <libcamera/stream.h>
+#include "libcamera/internal/mapped_framebuffer.h"
#include "libcamera/internal/v4l2_videodevice.h"
namespace libcamera {
namespace RPi {
-using BufferMap = std::unordered_map<unsigned int, FrameBuffer *>;
-
enum BufferMask {
MaskID = 0x00ffff,
MaskStats = 0x010000,
@@ -30,6 +31,21 @@ enum BufferMask {
MaskBayerData = 0x040000,
};
+struct BufferObject {
+ BufferObject(FrameBuffer *b, bool requiresMmap)
+ : buffer(b), mapped(std::nullopt)
+ {
+ if (requiresMmap)
+ mapped = std::make_optional<MappedFrameBuffer>
+ (b, MappedFrameBuffer::MapFlag::ReadWrite);
+ }
+
+ FrameBuffer *buffer;
+ std::optional<MappedFrameBuffer> mapped;
+};
+
+using BufferMap = std::unordered_map<unsigned int, BufferObject>;
+
/*
* Device stream abstraction for either an internal or external stream.
* Used for both Unicam and the ISP.
@@ -49,6 +65,11 @@ public:
* buffers might be provided by (and returned to) the application.
*/
External = (1 << 1),
+ /*
+ * Indicates that the stream buffers need to be mmaped and returned
+ * to the pipeline handler when requested.
+ */
+ RequiresMmap = (1 << 2),
};
using StreamFlags = Flags<StreamFlag>;
@@ -82,10 +103,17 @@ public:
int queueBuffer(FrameBuffer *buffer);
void returnBuffer(FrameBuffer *buffer);
+ const BufferObject &getBuffer(unsigned int id);
+ const BufferObject &acquireBuffer();
+
int queueAllBuffers();
void releaseBuffers();
+ /* For error handling. */
+ static const BufferObject errorBufferObject;
+
private:
+ void bufferEmplace(unsigned int id, FrameBuffer *buffer);
void clearBuffers();
int queueToDevice(FrameBuffer *buffer);
@@ -825,7 +825,7 @@ void Vc4CameraData::processStatsComplete(const ipa::RPi::BufferIds &buffers)
if (!isRunning())
return;
- FrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(buffers.stats & RPi::MaskID);
+ FrameBuffer *buffer = isp_[Isp::Stats].getBuffers().at(buffers.stats & RPi::MaskID).buffer;
handleStreamBuffer(buffer, &isp_[Isp::Stats]);
@@ -842,7 +842,7 @@ void Vc4CameraData::prepareIspComplete(const ipa::RPi::BufferIds &buffers)
if (!isRunning())
return;
- buffer = unicam_[Unicam::Image].getBuffers().at(bayer & RPi::MaskID);
+ buffer = unicam_[Unicam::Image].getBuffers().at(bayer & RPi::MaskID).buffer;
LOG(RPI, Debug) << "Input re-queue to ISP, buffer id " << (bayer & RPi::MaskID)
<< ", timestamp: " << buffer->metadata().timestamp;
@@ -850,7 +850,7 @@ void Vc4CameraData::prepareIspComplete(const ipa::RPi::BufferIds &buffers)
ispOutputCount_ = 0;
if (sensorMetadata_ && embeddedId) {
- buffer = unicam_[Unicam::Embedded].getBuffers().at(embeddedId & RPi::MaskID);
+ buffer = unicam_[Unicam::Embedded].getBuffers().at(embeddedId & RPi::MaskID).buffer;
handleStreamBuffer(buffer, &unicam_[Unicam::Embedded]);
}