@@ -71,10 +71,10 @@ public:
void free();
unsigned int count() const { return buffers_.size(); };
- const std::vector<Buffer *> &buffers() { return buffers_; };
+ std::vector<Buffer *> &buffers() { return buffers_; };
private:
- virtual int allocateMemory() = 0;
+ virtual int allocateMemory() { return 0; };
BufferPool::Memory memory_;
std::vector<Buffer *> buffers_;
@@ -8,6 +8,7 @@
#define __LIBCAMERA_V4L2_DEVICE_H__
#include <string>
+#include <vector>
#include <linux/videodev2.h>
@@ -76,6 +77,7 @@ public:
};
class MediaEntity;
+
class V4L2Device
{
public:
@@ -97,6 +99,8 @@ public:
int format(V4L2DeviceFormat *fmt);
int setFormat(V4L2DeviceFormat *fmt);
+ BufferPool *requestBuffers(unsigned int qty = 8);
+
private:
int getFormatSingleplane(V4L2DeviceFormat *fmt);
int setFormatSingleplane(V4L2DeviceFormat *fmt);
@@ -104,10 +108,16 @@ private:
int getFormatMultiplane(V4L2DeviceFormat *fmt);
int setFormatMultiplane(V4L2DeviceFormat *fmt);
+ int requestBuffers(unsigned int qty, std::vector<Buffer *> &buffers);
+
std::string deviceNode_;
int fd_;
V4L2Capability caps_;
+
enum v4l2_buf_type bufferType_;
+ enum v4l2_memory memoryType_;
+
+ BufferPool *bufferPool_;
};
} /* namespace libcamera */
@@ -10,6 +10,9 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
+#include <vector>
+
+#include <libcamera/buffer.h>
#include "log.h"
#include "media_object.h"
@@ -187,8 +190,14 @@ V4L2Buffer::V4L2Buffer(struct v4l2_buffer &vb)
* \param deviceNode The file-system path to the video device node
*/
V4L2Device::V4L2Device(const std::string &deviceNode)
- : deviceNode_(deviceNode), fd_(-1)
+ : deviceNode_(deviceNode), fd_(-1), bufferPool_(nullptr)
{
+ /*
+ * We default to an MMAP based CAPTURE device, however this will be
+ * updated based upon the device capabilities.
+ */
+ bufferType_ = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ memoryType_ = V4L2_MEMORY_MMAP;
}
/**
@@ -205,6 +214,8 @@ V4L2Device::V4L2Device(const MediaEntity &entity)
V4L2Device::~V4L2Device()
{
close();
+
+ delete bufferPool_;
}
/**
@@ -305,6 +316,104 @@ void V4L2Device::close()
* \return The string containing the device location
*/
+/**
+ * \brief Request \a qty buffers to be allocated from the device and returned
+ * as a BufferPool
+ * \return A BufferPool containing the device buffers, or nullptr if the
+ * allocation fails
+ */
+BufferPool *V4L2Device::requestBuffers(unsigned int qty)
+{
+ int ret;
+
+ if (bufferPool_) {
+ LOG(V4L2, Warning) << "Pre-existing buffer pool will be lost";
+ delete bufferPool_;
+ }
+
+ bufferPool_ = new BufferPool(BufferPool::Internal);
+
+ ret = requestBuffers(qty, bufferPool_->buffers());
+ if (ret) {
+ delete bufferPool_;
+ bufferPool_ = nullptr;
+ return nullptr;
+ }
+
+ return bufferPool_;
+}
+
+/**
+ * \brief Request \a qty buffers from the V4L2Device and track Buffer
+ * representations within the specified \a buffers target.
+ */
+int V4L2Device::requestBuffers(unsigned int qty, std::vector<Buffer *> &buffers)
+{
+ struct v4l2_requestbuffers rb = {};
+ unsigned int i;
+ int ret;
+
+ rb.count = qty;
+ rb.type = bufferType_;
+ rb.memory = memoryType_; /** \todo Support dmaBuf memoryTypes */
+
+ ret = ioctl(fd_, VIDIOC_REQBUFS, &rb);
+ if (ret < 0) {
+ ret = -errno;
+ LOG(V4L2, Error)
+ << "Unable to request " << qty << " buffers: "
+ << strerror(-ret);
+ return ret;
+ }
+
+ LOG(V4L2, Debug)
+ << deviceNode_ << ":" << rb.count << " buffers requested.";
+
+ if (memoryType_ != V4L2_MEMORY_MMAP) {
+ LOG(V4L2, Error)
+ << "Non-mmap allocations are not yet supported.";
+ return -EINVAL;
+ }
+
+ /* Map the buffers. */
+ for (i = 0; i < rb.count; ++i) {
+ struct v4l2_plane planes[VIDEO_MAX_PLANES] = {};
+ struct v4l2_buffer buf = {};
+ struct Buffer *buffer;
+
+ buf.index = i;
+ buf.type = bufferType_;
+ buf.memory = memoryType_;
+ buf.length = VIDEO_MAX_PLANES;
+ buf.m.planes = planes;
+
+ ret = ioctl(fd_, VIDIOC_QUERYBUF, &buf);
+ if (ret < 0) {
+ LOG(V4L2, Error)
+ << "Unable to query buffer " << i << ": "
+ << strerror(errno);
+ return ret;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(buf.type)) {
+ for (unsigned int p = 0; p < buf.length; ++p)
+ LOG(V4L2, Debug)
+ << "plane: " << p
+ << " length: " << buf.m.planes[p].length
+ << " offset: "
+ << buf.m.planes[p].data_offset;
+ } else {
+ LOG(V4L2, Debug) << "length: " << buf.length
+ << " offset: " << buf.m.offset;
+ }
+
+ buffer = new V4L2Buffer(buf);
+ buffers.push_back(buffer);
+ }
+
+ return 0;
+}
+
/**
* \brief Retrieve the image format set on the V4L2 device
* \return 0 for success, a negative error code otherwise
Provide a requestBuffers() interface to allocate buffers from the V4L2Device and keep a vector of the buffers in the V4L2Device object for later queue and dequeue operations. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- include/libcamera/buffer.h | 4 +- src/libcamera/include/v4l2_device.h | 10 +++ src/libcamera/v4l2_device.cpp | 111 +++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 3 deletions(-)