6#include <QtMultimedia/private/qv4l2filedescriptor_p.h>
7#include <QtCore/qdebug.h>
8#include <QtCore/qloggingcategory.h>
22v4l2_buffer makeV4l2Buffer(quint32 memoryType, quint32 index = 0)
25 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
26 buf.memory = memoryType;
36 quint32 buffersCount = 2;
37 if (!fileDescriptor->requestBuffers(V4L2_MEMORY_USERPTR, buffersCount)) {
38 qCDebug(qLcV4L2MemoryTransfer) <<
"Cannot request V4L2_MEMORY_USERPTR buffers";
42 std::unique_ptr<UserPtrMemoryTransfer> result(
43 new UserPtrMemoryTransfer(
std::move(fileDescriptor), buffersCount, imageSize));
45 return result->enqueueBuffers() ?
std::move(result) :
nullptr;
48 std::optional<
Buffer> dequeueBuffer() override
50 auto v4l2Buffer = makeV4l2Buffer(V4L2_MEMORY_USERPTR);
54 Q_ASSERT(v4l2Buffer.index < m_byteArrays.size());
56 auto &byteArray = m_byteArrays[v4l2Buffer.index];
58 Q_ASSERT(!byteArray.isEmpty());
59 Q_ASSERT(qsizetype(v4l2Buffer.bytesused) <= byteArray.size());
62 byteArray.resize(v4l2Buffer.bytesused);
63 return Buffer{ v4l2Buffer,
std::move(byteArray) };
66 bool enqueueBuffer(quint32 index)
override
68 Q_ASSERT(index < m_byteArrays.size());
69 Q_ASSERT(m_byteArrays[index].isEmpty());
71 auto buf = makeV4l2Buffer(V4L2_MEMORY_USERPTR, index);
72 static_assert(
sizeof(
decltype(buf.m.userptr)) ==
sizeof(size_t),
"Not compatible sizes");
74 m_byteArrays[index] = QByteArray(
static_cast<
int>(m_imageSize), Qt::Uninitialized);
76 buf.m.userptr = (
decltype(buf.m.userptr))m_byteArrays[index].data();
77 buf.length = m_byteArrays[index].size();
80 qWarning() <<
"Couldn't add V4L2 buffer" << errno << qt_error_string(errno) << index;
87 quint32 buffersCount()
const override {
return static_cast<quint32>(m_byteArrays.size()); }
93 m_imageSize(imageSize),
94 m_byteArrays(buffersCount)
100 std::vector<QByteArray> m_byteArrays;
108 void *data =
nullptr;
110 bool inQueue =
false;
115 quint32 buffersCount = 2;
116 if (!fileDescriptor->requestBuffers(V4L2_MEMORY_MMAP, buffersCount)) {
117 qCWarning(qLcV4L2MemoryTransfer) <<
"Cannot request V4L2_MEMORY_MMAP buffers";
121 std::unique_ptr<MMapMemoryTransfer> result(
122 new MMapMemoryTransfer(
std::move(fileDescriptor)));
124 return result->init(buffersCount) ?
std::move(result) :
nullptr;
127 bool init(quint32 buffersCount)
129 for (quint32 index = 0; index < buffersCount; ++index) {
130 auto buf = makeV4l2Buffer(V4L2_MEMORY_MMAP, index);
133 qWarning() <<
"Can't map buffer" << index;
137 auto mappedData = mmap(
nullptr, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
138 fileDescriptor().get(), buf.m.offset);
141 qWarning() <<
"mmap failed" << index << buf.length << buf.m.offset;
145 m_spans.push_back(MemorySpan{ mappedData, buf.length,
false });
148 m_spans.shrink_to_fit();
153 ~MMapMemoryTransfer()
override
155 for (
const auto &span : m_spans)
156 munmap(span.data, span.size);
159 std::optional<
Buffer> dequeueBuffer() override
161 auto v4l2Buffer = makeV4l2Buffer(V4L2_MEMORY_MMAP);
165 const auto index = v4l2Buffer.index;
167 Q_ASSERT(index < m_spans.size());
169 auto &span = m_spans[index];
171 Q_ASSERT(span.inQueue);
172 span.inQueue =
false;
174 Q_ASSERT(v4l2Buffer.bytesused <= span.size);
177 QByteArray byteArray(
reinterpret_cast<
const char *>(span.data), v4l2Buffer.bytesused);
179 return Buffer{ v4l2Buffer,
std::move(byteArray) };
182 bool enqueueBuffer(quint32 index)
override
184 Q_ASSERT(index < m_spans.size());
185 Q_ASSERT(!m_spans[index].inQueue);
187 auto buf = makeV4l2Buffer(V4L2_MEMORY_MMAP, index);
191 m_spans[index].inQueue =
true;
195 quint32 buffersCount()
const override {
return static_cast<quint32>(m_spans.size()); }
201 std::vector<MemorySpan> m_spans;
208 Q_ASSERT(m_fileDescriptor);
209 Q_ASSERT(!m_fileDescriptor->streamStarted());
214 Q_ASSERT(!m_fileDescriptor->streamStarted());
219 for (quint32 i = 0; i < buffersCount(); ++i)
220 if (!enqueueBuffer(i))
229 return UserPtrMemoryTransfer::create(
std::move(fileDescriptor), imageSize);
234 return MMapMemoryTransfer::create(
std::move(fileDescriptor));
QV4L2MemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor)
const QV4L2FileDescriptor & fileDescriptor() const
virtual ~QV4L2MemoryTransfer()
QV4L2MemoryTransferUPtr makeMMapMemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor)
Q_STATIC_LOGGING_CATEGORY(qLcV4L2Camera, "qt.multimedia.v4l2.camera")
QV4L2MemoryTransferUPtr makeUserPtrMemoryTransfer(QV4L2FileDescriptorPtr fileDescriptor, quint32 imageSize)
std::shared_ptr< QV4L2FileDescriptor > QV4L2FileDescriptorPtr