Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4l2cameradevices.cpp
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6#include "qv4l2camera_p.h"
7
8#include <private/qcameradevice_p.h>
9#include <private/qcore_unix_p.h>
10
11#include <qdir.h>
12#include <qfile.h>
13#include <qdebug.h>
14#include <qloggingcategory.h>
15
16#include <linux/videodev2.h>
17
19
20static Q_LOGGING_CATEGORY(qLcV4L2CameraDevices, "qt.multimedia.ffmpeg.v4l2cameradevices");
21
22static bool areCamerasEqual(QList<QCameraDevice> a, QList<QCameraDevice> b)
23{
24 auto areCamerasDataEqual = [](const QCameraDevice &a, const QCameraDevice &b) {
28 };
29
30 return std::equal(a.cbegin(), a.cend(), b.cbegin(), b.cend(), areCamerasDataEqual);
31}
32
34 : QPlatformVideoDevices(integration)
35{
36 m_deviceWatcher.addPath(QLatin1String("/dev"));
37 connect(&m_deviceWatcher, &QFileSystemWatcher::directoryChanged, this,
39 doCheckCameras();
40}
41
42QList<QCameraDevice> QV4L2CameraDevices::videoDevices() const
43{
44 return m_cameras;
45}
46
48{
49 if (doCheckCameras())
51}
52
53bool QV4L2CameraDevices::doCheckCameras()
54{
55 QList<QCameraDevice> newCameras;
56
57 QDir dir(QLatin1String("/dev"));
58 const auto devices = dir.entryList(QDir::System);
59
60 bool first = true;
61
62 for (auto device : devices) {
63 // qCDebug(qLcV4L2Camera) << "device:" << device;
64 if (!device.startsWith(QLatin1String("video")))
65 continue;
66
68 const int fd = open(file.constData(), O_RDONLY);
69 if (fd < 0)
70 continue;
71
72 auto fileCloseGuard = qScopeGuard([fd]() { close(fd); });
73
74 v4l2_fmtdesc formatDesc = {};
75
76 struct v4l2_capability cap;
77 if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
78 continue;
79
80 if (cap.device_caps & V4L2_CAP_META_CAPTURE)
81 continue;
82 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
83 continue;
84 if (!(cap.capabilities & V4L2_CAP_STREAMING))
85 continue;
86
87 auto camera = std::make_unique<QCameraDevicePrivate>();
88
89 camera->id = file;
90 camera->description = QString::fromUtf8((const char *)cap.card);
91 qCDebug(qLcV4L2CameraDevices) << "found camera" << camera->id << camera->description;
92
93 formatDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
94
95 while (!xioctl(fd, VIDIOC_ENUM_FMT, &formatDesc)) {
96 auto pixelFmt = formatForV4L2Format(formatDesc.pixelformat);
97 qCDebug(qLcV4L2CameraDevices) << " " << pixelFmt;
98
99 if (pixelFmt == QVideoFrameFormat::Format_Invalid) {
100 ++formatDesc.index;
101 continue;
102 }
103
104 qCDebug(qLcV4L2CameraDevices) << "frame sizes:";
105 v4l2_frmsizeenum frameSize = {};
106 frameSize.pixel_format = formatDesc.pixelformat;
107
108 while (!xioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frameSize)) {
109 QList<QSize> resolutions;
110 if (frameSize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
111 resolutions.append(QSize(frameSize.discrete.width,
112 frameSize.discrete.height));
113 } else {
114 resolutions.append(QSize(frameSize.stepwise.max_width,
115 frameSize.stepwise.max_height));
116 resolutions.append(QSize(frameSize.stepwise.min_width,
117 frameSize.stepwise.min_height));
118 }
119
120 for (auto resolution : resolutions) {
121 float min = 1e10;
122 float max = 0;
123 auto updateMaxMinFrameRate = [&max, &min](auto discreteFrameRate) {
124 const float rate = float(discreteFrameRate.denominator)
125 / float(discreteFrameRate.numerator);
126 if (rate > max)
127 max = rate;
128 if (rate < min)
129 min = rate;
130 };
131
132 v4l2_frmivalenum frameInterval = {};
133 frameInterval.pixel_format = formatDesc.pixelformat;
134 frameInterval.width = resolution.width();
135 frameInterval.height = resolution.height();
136
137 while (!xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) {
138 if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
139 updateMaxMinFrameRate(frameInterval.discrete);
140 } else {
141 updateMaxMinFrameRate(frameInterval.stepwise.max);
142 updateMaxMinFrameRate(frameInterval.stepwise.min);
143 }
144 ++frameInterval.index;
145 }
146
147 qCDebug(qLcV4L2CameraDevices) << " " << resolution << min << max;
148
149 if (min <= max) {
150 auto fmt = std::make_unique<QCameraFormatPrivate>();
151 fmt->pixelFormat = pixelFmt;
152 fmt->resolution = resolution;
153 fmt->minFrameRate = min;
154 fmt->maxFrameRate = max;
155 camera->videoFormats.append(fmt.release()->create());
156 camera->photoResolutions.append(resolution);
157 }
158 }
159 ++frameSize.index;
160 }
161 ++formatDesc.index;
162 }
163
164 if (camera->videoFormats.empty())
165 continue;
166
167 // first camera is default
168 camera->isDefault = std::exchange(first, false);
169
170 newCameras.append(camera.release()->create());
171 }
172
173 if (areCamerasEqual(m_cameras, newCameras))
174 return false;
175
176 m_cameras = std::move(newCameras);
177 return true;
178}
179
181
182#include "moc_qv4l2cameradevices_p.cpp"
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
static const QCameraDevicePrivate * handle(const QCameraDevice &device)
The QCameraDevice class provides general information about camera devices.
\inmodule QtCore
Definition qdir.h:20
@ System
Definition qdir.h:36
void directoryChanged(const QString &path, QPrivateSignal)
This signal is emitted when the directory at a specified path is modified (e.g., when a file is added...
bool addPath(const QString &file)
Adds path to the file system watcher if path exists.
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
Definition qfile.h:158
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtCore
Definition qsize.h:25
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QList< QCameraDevice > videoDevices() const override
QV4L2CameraDevices(QPlatformMediaIntegration *integration)
QCamera * camera
Definition camera.cpp:19
Combined button and popup list for selecting options.
constexpr const T & min(const T &a, const T &b)
Definition qnumeric.h:366
EGLDeviceEXT * devices
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint64 GLenum GLint fd
GLint first
GLuint GLenum * rate
GLenum cap
static constexpr QSize frameSize(const T &frame)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define emit
QVideoFrameFormat::PixelFormat fmt
QVideoFrameFormat::PixelFormat formatForV4L2Format(uint32_t v4l2Format)
static bool areCamerasEqual(QList< QCameraDevice > a, QList< QCameraDevice > b)
QT_BEGIN_NAMESPACE int xioctl(int fd, int request, void *arg)
QFile file
[0]
file open(QIODevice::ReadOnly)
QString dir
[11]