7#include <qloggingcategory.h>
18v4l2_buffer makeV4l2Buffer(quint32 memoryType, quint32 index = 0)
21 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
22 buf.memory = memoryType;
32 quint32 buffersCount = 2;
33 if (!fileDescriptor->requestBuffers(V4L2_MEMORY_USERPTR, buffersCount)) {
34 qCWarning(qLcV4L2MemoryTransfer) <<
"Cannot request V4L2_MEMORY_USERPTR buffers";
38 std::unique_ptr<UserPtrMemoryTransfer> result(
39 new UserPtrMemoryTransfer(
std::move(fileDescriptor), buffersCount, imageSize));
41 return result->enqueueBuffers() ?
std::move(result) :
nullptr;
44 std::optional<
Buffer> dequeueBuffer() override
46 auto v4l2Buffer = makeV4l2Buffer(V4L2_MEMORY_USERPTR);
50 Q_ASSERT(v4l2Buffer.index < m_byteArrays.size());
52 auto &byteArray = m_byteArrays[v4l2Buffer.index];
54 Q_ASSERT(!byteArray.isEmpty());
55 Q_ASSERT(qsizetype(v4l2Buffer.bytesused) <= byteArray.size());
58 byteArray.resize(v4l2Buffer.bytesused);
59 return Buffer{ v4l2Buffer,
std::move(byteArray) };
62 bool enqueueBuffer(quint32 index)
override
64 Q_ASSERT(index < m_byteArrays.size());
65 Q_ASSERT(m_byteArrays[index].isEmpty());
67 auto buf = makeV4l2Buffer(V4L2_MEMORY_USERPTR, index);
68 static_assert(
sizeof(
decltype(buf.m.userptr)) ==
sizeof(size_t),
"Not compatible sizes");
70 m_byteArrays[index] = QByteArray(
static_cast<
int>(m_imageSize), Qt::Uninitialized);
72 buf.m.userptr = (
decltype(buf.m.userptr))m_byteArrays[index].data();
73 buf.length = m_byteArrays[index].size();
76 qWarning() <<
"Couldn't add V4L2 buffer" << errno << strerror(errno) << index;
83 quint32 buffersCount()
const override {
return static_cast<quint32>(m_byteArrays.size()); }
89 m_imageSize(imageSize),
90 m_byteArrays(buffersCount)
96 std::vector<QByteArray> m_byteArrays;
104 void *data =
nullptr;
106 bool inQueue =
false;
111 quint32 buffersCount = 2;
112 if (!fileDescriptor->requestBuffers(V4L2_MEMORY_MMAP, buffersCount)) {
113 qCWarning(qLcV4L2MemoryTransfer) <<
"Cannot request V4L2_MEMORY_MMAP buffers";
117 std::unique_ptr<MMapMemoryTransfer> result(
118 new MMapMemoryTransfer(
std::move(fileDescriptor)));
120 return result->init(buffersCount) ?
std::move(result) :
nullptr;
123 bool init(quint32 buffersCount)
125 for (quint32 index = 0; index < buffersCount; ++index) {
126 auto buf = makeV4l2Buffer(V4L2_MEMORY_MMAP, index);
129 qWarning() <<
"Can't map buffer" << index;
133 auto mappedData = mmap(
nullptr, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
134 fileDescriptor().get(), buf.m.offset);
137 qWarning() <<
"mmap failed" << index << buf.length << buf.m.offset;
141 m_spans.push_back(MemorySpan{ mappedData, buf.length,
false });
144 m_spans.shrink_to_fit();
149 ~MMapMemoryTransfer()
override
151 for (
const auto &span : m_spans)
152 munmap(span.data, span.size);
155 std::optional<
Buffer> dequeueBuffer() override
157 auto v4l2Buffer = makeV4l2Buffer(V4L2_MEMORY_MMAP);
161 const auto index = v4l2Buffer.index;
163 Q_ASSERT(index < m_spans.size());
165 auto &span = m_spans[index];
167 Q_ASSERT(span.inQueue);
168 span.inQueue =
false;
170 Q_ASSERT(v4l2Buffer.bytesused <= span.size);
173 QByteArray byteArray(
reinterpret_cast<
const char *>(span.data), v4l2Buffer.bytesused);
175 return Buffer{ v4l2Buffer,
std::move(byteArray) };
178 bool enqueueBuffer(quint32 index)
override
180 Q_ASSERT(index < m_spans.size());
181 Q_ASSERT(!m_spans[index].inQueue);
183 auto buf = makeV4l2Buffer(V4L2_MEMORY_MMAP, index);
187 m_spans[index].inQueue =
true;
191 quint32 buffersCount()
const override {
return static_cast<quint32>(m_spans.size()); }
197 std::vector<MemorySpan> m_spans;
204 Q_ASSERT(m_fileDescriptor);
205 Q_ASSERT(!m_fileDescriptor->streamStarted());
210 Q_ASSERT(!m_fileDescriptor->streamStarted());
215 for (quint32 i = 0; i < buffersCount(); ++i)
216 if (!enqueueBuffer(i))
225 return UserPtrMemoryTransfer::create(
std::move(fileDescriptor), imageSize);
230 return MMapMemoryTransfer::create(
std::move(fileDescriptor));
const QV4L2FileDescriptor & fileDescriptor() const
QV4L2MemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor)
virtual ~QV4L2MemoryTransfer()
#define qCWarning(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
QV4L2MemoryTransferUPtr makeUserPtrMemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor, quint32 imageSize)
std::shared_ptr< QV4L2FileDescriptor > QV4L2FileDescriptorPtr
QV4L2MemoryTransferUPtr makeMMapMemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor)