summaryrefslogtreecommitdiff
path: root/src/libcamera
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcamera')
-rw-r--r--src/libcamera/buffer.cpp164
-rw-r--r--src/libcamera/include/v4l2_videodevice.h8
-rw-r--r--src/libcamera/request.cpp35
-rw-r--r--src/libcamera/stream.cpp24
-rw-r--r--src/libcamera/v4l2_videodevice.cpp40
5 files changed, 179 insertions, 92 deletions
diff --git a/src/libcamera/buffer.cpp b/src/libcamera/buffer.cpp
index c0a02094..ecbf2524 100644
--- a/src/libcamera/buffer.cpp
+++ b/src/libcamera/buffer.cpp
@@ -173,12 +173,78 @@ void *Plane::mem()
*/
/**
- * \class Buffer
+ * \class BufferMemory
* \brief A memory buffer to store an image
*
- * The Buffer class represents the memory buffers used to store a
- * full frame image, which may contain multiple separate memory Plane
- * objects if the image format is multi-planar.
+ * The BufferMemory class represents the memory buffers used to store full frame
+ * images, which may contain multiple separate memory Plane objects if the
+ * image format is multi-planar.
+ */
+
+/**
+ * \fn BufferMemory::planes()
+ * \brief Retrieve the planes within the buffer
+ * \return A reference to a vector holding all Planes within the buffer
+ */
+
+/**
+ * \class BufferPool
+ * \brief A pool of buffers
+ *
+ * The BufferPool class groups together a collection of Buffers to store frames.
+ * The buffers must be exported by a device before they can be imported into
+ * another device for further use.
+ */
+
+BufferPool::~BufferPool()
+{
+ destroyBuffers();
+}
+
+/**
+ * \brief Create buffers in the Pool
+ * \param[in] count The number of buffers to create
+ */
+void BufferPool::createBuffers(unsigned int count)
+{
+ buffers_.resize(count);
+}
+
+/**
+ * \brief Release all buffers from pool
+ *
+ * If no buffers have been created or if buffers have already been released no
+ * operation is performed.
+ */
+void BufferPool::destroyBuffers()
+{
+ buffers_.resize(0);
+}
+
+/**
+ * \fn BufferPool::count()
+ * \brief Retrieve the number of buffers contained within the pool
+ * \return The number of buffers contained in the pool
+ */
+
+/**
+ * \fn BufferPool::buffers()
+ * \brief Retrieve all the buffers in the pool
+ * \return A vector containing all the buffers in the pool.
+ */
+
+/**
+ * \class Buffer
+ * \brief A buffer handle and dynamic metadata
+ *
+ * The Buffer class references a buffer memory and associates dynamic metadata
+ * related to the frame contained in the buffer. It allows referencing buffer
+ * memory through a single interface regardless of whether the memory is
+ * allocated internally in libcamera or provided externally through dmabuf.
+ *
+ * Buffer instances are allocated dynamically for a stream through
+ * Stream::createBuffer(), added to a request with Request::addBuffer() and
+ * deleted automatically after the request complete handler returns.
*/
/**
@@ -195,9 +261,26 @@ void *Plane::mem()
* invalid and shall not be used.
*/
-Buffer::Buffer()
- : index_(-1), request_(nullptr)
+/**
+ * \brief Construct a buffer not associated with any stream
+ *
+ * This method constructs an orphaned buffer not associated with any stream. It
+ * is not meant to be called by applications, they should instead create buffers
+ * for a stream with Stream::createBuffer().
+ */
+Buffer::Buffer(unsigned int index, const Buffer *metadata)
+ : index_(index), status_(Buffer::BufferSuccess), request_(nullptr),
+ stream_(nullptr)
{
+ if (metadata) {
+ bytesused_ = metadata->bytesused_;
+ sequence_ = metadata->sequence_;
+ timestamp_ = metadata->timestamp_;
+ } else {
+ bytesused_ = 0;
+ sequence_ = 0;
+ timestamp_ = 0;
+ }
}
/**
@@ -207,12 +290,6 @@ Buffer::Buffer()
*/
/**
- * \fn Buffer::planes()
- * \brief Retrieve the planes within the buffer
- * \return A reference to a vector holding all Planes within the buffer
- */
-
-/**
* \fn Buffer::bytesused()
* \brief Retrieve the number of bytes occupied by the data in the buffer
* \return Number of bytes occupied in the buffer
@@ -265,6 +342,19 @@ Buffer::Buffer()
*/
/**
+ * \fn Buffer::stream()
+ * \brief Retrieve the stream this buffer is associated with
+ *
+ * A Buffer is associated to the stream that created it with
+ * Stream::createBuffer() and the association is valid until the buffer is
+ * destroyed. Buffer instances that are created directly are not associated
+ * with any stream.
+ *
+ * \return The Stream the Buffer is associated with, or nullptr if the buffer
+ * is not associated with a stream
+ */
+
+/**
* \brief Mark a buffer as cancel by setting its status to BufferCancelled
*/
void Buffer::cancel()
@@ -282,54 +372,4 @@ void Buffer::cancel()
* The intended callers are Request::prepare() and Request::completeBuffer().
*/
-/**
- * \class BufferPool
- * \brief A pool of buffers
- *
- * The BufferPool class groups together a collection of Buffers to store frames.
- * The buffers must be exported by a device before they can be imported into
- * another device for further use.
- */
-
-BufferPool::~BufferPool()
-{
- destroyBuffers();
-}
-
-/**
- * \brief Create buffers in the Pool
- * \param[in] count The number of buffers to create
- */
-void BufferPool::createBuffers(unsigned int count)
-{
- unsigned int index = 0;
-
- buffers_.resize(count);
- for (Buffer &buffer : buffers_)
- buffer.index_ = index++;
-}
-
-/**
- * \brief Release all buffers from pool
- *
- * If no buffers have been created or if buffers have already been released no
- * operation is performed.
- */
-void BufferPool::destroyBuffers()
-{
- buffers_.resize(0);
-}
-
-/**
- * \fn BufferPool::count()
- * \brief Retrieve the number of buffers contained within the pool
- * \return The number of buffers contained in the pool
- */
-
-/**
- * \fn BufferPool::buffers()
- * \brief Retrieve all the buffers in the pool
- * \return A vector containing all the buffers in the pool.
- */
-
} /* namespace libcamera */
diff --git a/src/libcamera/include/v4l2_videodevice.h b/src/libcamera/include/v4l2_videodevice.h
index 2996a609..f5c8da93 100644
--- a/src/libcamera/include/v4l2_videodevice.h
+++ b/src/libcamera/include/v4l2_videodevice.h
@@ -7,7 +7,6 @@
#ifndef __LIBCAMERA_V4L2_VIDEODEVICE_H__
#define __LIBCAMERA_V4L2_VIDEODEVICE_H__
-#include <atomic>
#include <string>
#include <vector>
@@ -23,6 +22,7 @@
namespace libcamera {
class Buffer;
+class BufferMemory;
class BufferPool;
class EventNotifier;
class MediaDevice;
@@ -165,8 +165,8 @@ private:
std::vector<SizeRange> enumSizes(unsigned int pixelFormat);
int requestBuffers(unsigned int count);
- int createPlane(Buffer *buffer, unsigned int plane,
- unsigned int length);
+ int createPlane(BufferMemory *buffer, unsigned int index,
+ unsigned int plane, unsigned int length);
Buffer *dequeueBuffer();
void bufferAvailable(EventNotifier *notifier);
@@ -177,7 +177,7 @@ private:
enum v4l2_memory memoryType_;
BufferPool *bufferPool_;
- std::atomic<unsigned int> queuedBuffersCount_;
+ std::map<unsigned int, Buffer *> queuedBuffers_;
EventNotifier *fdEvent_;
};
diff --git a/src/libcamera/request.cpp b/src/libcamera/request.cpp
index 8cf41a43..45e7133f 100644
--- a/src/libcamera/request.cpp
+++ b/src/libcamera/request.cpp
@@ -60,6 +60,14 @@ Request::Request(Camera *camera, uint64_t cookie)
{
}
+Request::~Request()
+{
+ for (auto it : bufferMap_) {
+ Buffer *buffer = it.second;
+ delete buffer;
+ }
+}
+
/**
* \fn Request::controls()
* \brief Retrieve the request's ControlList
@@ -87,19 +95,30 @@ Request::Request(Camera *camera, uint64_t cookie)
*/
/**
- * \brief Set the streams to capture with associated buffers
- * \param[in] streamMap The map of streams to buffers
+ * \brief Store a Buffer with its associated Stream in the Request
+ * \param[in] buffer The Buffer to store in the request
+ *
+ * Ownership of the buffer is passed to the request. It will be deleted when
+ * the request is destroyed after completing.
+ *
+ * A request can only contain one buffer per stream. If a buffer has already
+ * been added to the request for the same stream, this method returns -EEXIST.
+ *
* \return 0 on success or a negative error code otherwise
- * \retval -EBUSY Buffers have already been set
+ * \retval -EEXIST The request already contains a buffer for the stream
*/
-int Request::setBuffers(const std::map<Stream *, Buffer *> &streamMap)
+int Request::addBuffer(std::unique_ptr<Buffer> buffer)
{
- if (!bufferMap_.empty()) {
- LOG(Request, Error) << "Buffers already set";
- return -EBUSY;
+ Stream *stream = buffer->stream();
+
+ auto it = bufferMap_.find(stream);
+ if (it != bufferMap_.end()) {
+ LOG(Request, Error) << "Buffer already set for stream";
+ return -EEXIST;
}
- bufferMap_ = streamMap;
+ bufferMap_[stream] = buffer.release();
+
return 0;
}
diff --git a/src/libcamera/stream.cpp b/src/libcamera/stream.cpp
index d8e87c62..6d80646b 100644
--- a/src/libcamera/stream.cpp
+++ b/src/libcamera/stream.cpp
@@ -408,6 +408,30 @@ Stream::Stream()
}
/**
+ * \brief Create a Buffer instance
+ * \param[in] index The desired buffer index
+ *
+ * This method creates a Buffer instance that references a BufferMemory from
+ * the stream's buffers pool by its \a index. The index shall be lower than the
+ * number of buffers in the pool.
+ *
+ * \return A newly created Buffer on success or nullptr otherwise
+ */
+std::unique_ptr<Buffer> Stream::createBuffer(unsigned int index)
+{
+ if (index >= bufferPool_.count()) {
+ LOG(Stream, Error) << "Invalid buffer index " << index;
+ return nullptr;
+ }
+
+ Buffer *buffer = new Buffer();
+ buffer->index_ = index;
+ buffer->stream_ = this;
+
+ return std::unique_ptr<Buffer>(buffer);
+}
+
+/**
* \fn Stream::bufferPool()
* \brief Retrieve the buffer pool for the stream
*
diff --git a/src/libcamera/v4l2_videodevice.cpp b/src/libcamera/v4l2_videodevice.cpp
index 0ab92b3a..86e299c0 100644
--- a/src/libcamera/v4l2_videodevice.cpp
+++ b/src/libcamera/v4l2_videodevice.cpp
@@ -268,8 +268,7 @@ const std::string V4L2DeviceFormat::toString() const
* \param[in] deviceNode The file-system path to the video device node
*/
V4L2VideoDevice::V4L2VideoDevice(const std::string &deviceNode)
- : V4L2Device(deviceNode), bufferPool_(nullptr),
- queuedBuffersCount_(0), fdEvent_(nullptr)
+ : V4L2Device(deviceNode), bufferPool_(nullptr), fdEvent_(nullptr)
{
/*
* We default to an MMAP based CAPTURE video device, however this will
@@ -764,7 +763,7 @@ int V4L2VideoDevice::exportBuffers(BufferPool *pool)
for (i = 0; i < pool->count(); ++i) {
struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
struct v4l2_buffer buf = {};
- Buffer &buffer = pool->buffers()[i];
+ BufferMemory &buffer = pool->buffers()[i];
buf.index = i;
buf.type = bufferType_;
@@ -782,13 +781,13 @@ int V4L2VideoDevice::exportBuffers(BufferPool *pool)
if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
for (unsigned int p = 0; p < buf.length; ++p) {
- ret = createPlane(&buffer, p,
+ ret = createPlane(&buffer, i, p,
buf.m.planes[p].length);
if (ret)
break;
}
} else {
- ret = createPlane(&buffer, 0, buf.length);
+ ret = createPlane(&buffer, i, 0, buf.length);
}
if (ret) {
@@ -808,19 +807,19 @@ int V4L2VideoDevice::exportBuffers(BufferPool *pool)
return 0;
}
-int V4L2VideoDevice::createPlane(Buffer *buffer, unsigned int planeIndex,
- unsigned int length)
+int V4L2VideoDevice::createPlane(BufferMemory *buffer, unsigned int index,
+ unsigned int planeIndex, unsigned int length)
{
struct v4l2_exportbuffer expbuf = {};
int ret;
LOG(V4L2, Debug)
- << "Buffer " << buffer->index()
+ << "Buffer " << index
<< " plane " << planeIndex
<< ": length=" << length;
expbuf.type = bufferType_;
- expbuf.index = buffer->index();
+ expbuf.index = index;
expbuf.plane = planeIndex;
expbuf.flags = O_RDWR;
@@ -904,7 +903,8 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)
buf.field = V4L2_FIELD_NONE;
bool multiPlanar = V4L2_TYPE_IS_MULTIPLANAR(buf.type);
- const std::vector<Plane> &planes = buffer->planes();
+ BufferMemory *mem = &bufferPool_->buffers()[buf.index];
+ const std::vector<Plane> &planes = mem->planes();
if (buf.memory == V4L2_MEMORY_DMABUF) {
if (multiPlanar) {
@@ -937,9 +937,11 @@ int V4L2VideoDevice::queueBuffer(Buffer *buffer)
return ret;
}
- if (queuedBuffersCount_++ == 0)
+ if (queuedBuffers_.empty())
fdEvent_->setEnabled(true);
+ queuedBuffers_[buf.index] = buffer;
+
return 0;
}
@@ -970,7 +972,7 @@ std::vector<std::unique_ptr<Buffer>> V4L2VideoDevice::queueAllBuffers()
{
int ret;
- if (queuedBuffersCount_)
+ if (!queuedBuffers_.empty())
return {};
if (V4L2_TYPE_IS_OUTPUT(bufferType_))
@@ -979,8 +981,7 @@ std::vector<std::unique_ptr<Buffer>> V4L2VideoDevice::queueAllBuffers()
std::vector<std::unique_ptr<Buffer>> buffers;
for (unsigned int i = 0; i < bufferPool_->count(); ++i) {
- Buffer *buffer = new Buffer();
- buffer->index_ = i;
+ Buffer *buffer = new Buffer(i);
buffers.emplace_back(buffer);
ret = queueBuffer(buffer);
if (ret)
@@ -1021,11 +1022,14 @@ Buffer *V4L2VideoDevice::dequeueBuffer()
ASSERT(buf.index < bufferPool_->count());
- if (--queuedBuffersCount_ == 0)
- fdEvent_->setEnabled(false);
+ auto it = queuedBuffers_.find(buf.index);
+ Buffer *buffer = it->second;
+ queuedBuffers_.erase(it);
- Buffer *buffer = &bufferPool_->buffers()[buf.index];
+ if (queuedBuffers_.empty())
+ fdEvent_->setEnabled(false);
+ buffer->index_ = buf.index;
buffer->bytesused_ = buf.bytesused;
buffer->timestamp_ = buf.timestamp.tv_sec * 1000000000ULL
+ buf.timestamp.tv_usec * 1000ULL;
@@ -1100,7 +1104,7 @@ int V4L2VideoDevice::streamOff()
return ret;
}
- queuedBuffersCount_ = 0;
+ queuedBuffers_.clear();
fdEvent_->setEnabled(false);
return 0;