8#include <private/qcameradevice_p.h>
9#include <private/qcore_unix_p.h>
14#include <qloggingcategory.h>
16#include <linux/videodev2.h>
24 auto areCamerasDataEqual = [](
const QCameraDevice &a,
const QCameraDevice &b) {
25 Q_ASSERT(QCameraDevicePrivate::handle(a));
26 Q_ASSERT(QCameraDevicePrivate::handle(b));
27 return *QCameraDevicePrivate::handle(a) == *QCameraDevicePrivate::handle(b);
30 return std::equal(a.cbegin(), a.cend(), b.cbegin(), b.cend(), areCamerasDataEqual);
34 : QPlatformVideoDevices(integration)
36 m_deviceWatcher.addPath(QLatin1String(
"/dev"));
37 connect(&m_deviceWatcher, &QFileSystemWatcher::directoryChanged,
this,
38 &QV4L2CameraDevices::checkCameras);
50 onVideoInputsChanged();
55 QList<QCameraDevice> newCameras;
57 QDir dir(QLatin1String(
"/dev"));
58 const auto devices = dir.entryList(QDir::System);
62 for (
auto device : devices) {
64 if (!device.startsWith(QLatin1String(
"video")))
67 QByteArray file = QFile::encodeName(dir.filePath(device));
68 const int fd = open(file.constData(), O_RDONLY);
72 auto fileCloseGuard = qScopeGuard([fd]() { close(fd); });
74 v4l2_fmtdesc formatDesc = {};
76 struct v4l2_capability cap;
77 if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
80 if (cap.device_caps & V4L2_CAP_META_CAPTURE)
82 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
84 if (!(cap.capabilities & V4L2_CAP_STREAMING))
87 auto camera = std::make_unique<QCameraDevicePrivate>();
90 camera->description = QString::fromUtf8((
const char *)cap.card);
91 qCDebug(qLcV4L2CameraDevices) <<
"found camera" << camera->id << camera->description;
93 formatDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
95 while (!xioctl(fd, VIDIOC_ENUM_FMT, &formatDesc)) {
96 auto pixelFmt = formatForV4L2Format(formatDesc.pixelformat);
97 qCDebug(qLcV4L2CameraDevices) <<
" " << pixelFmt;
99 if (pixelFmt == QVideoFrameFormat::Format_Invalid) {
104 qCDebug(qLcV4L2CameraDevices) <<
"frame sizes:";
105 v4l2_frmsizeenum frameSize = {};
106 frameSize.pixel_format = formatDesc.pixelformat;
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));
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));
120 for (
auto resolution : resolutions) {
123 auto updateMaxMinFrameRate = [&max, &min](
auto discreteFrameRate) {
124 const float rate =
float(discreteFrameRate.denominator)
125 /
float(discreteFrameRate.numerator);
132 v4l2_frmivalenum frameInterval = {};
133 frameInterval.pixel_format = formatDesc.pixelformat;
134 frameInterval.width = resolution.width();
135 frameInterval.height = resolution.height();
137 while (!xioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frameInterval)) {
138 if (frameInterval.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
139 updateMaxMinFrameRate(frameInterval.discrete);
141 updateMaxMinFrameRate(frameInterval.stepwise.max);
142 updateMaxMinFrameRate(frameInterval.stepwise.min);
144 ++frameInterval.index;
147 qCDebug(qLcV4L2CameraDevices) <<
" " << resolution << 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);
164 if (camera->videoFormats.empty())
168 camera->isDefault = std::exchange(first,
false);
170 newCameras.append(camera.release()->create());
173 if (areCamerasEqual(m_cameras, newCameras))
176 m_cameras = std::move(newCameras);
182#include "moc_qv4l2cameradevices_p.cpp"
QList< QCameraDevice > findVideoInputs() const override
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
static bool areCamerasEqual(QList< QCameraDevice > a, QList< QCameraDevice > b)