29 #include <linux/videodev2.h>
31 #include <sys/ioctl.h>
40 static std::map<uint32_t, uint8_t> createPixFmtToQuality()
42 std::map<uint32_t, uint8_t> m;
43 m[V4L2_PIX_FMT_H264] = 3;
44 m[V4L2_PIX_FMT_MJPEG] = 2;
45 m[V4L2_PIX_FMT_YUYV] = 1;
46 m[V4L2_PIX_FMT_UYVY] = 1;
51 static std::map<uint32_t, QString> createPixFmtToName()
53 std::map<uint32_t, QString> m;
54 m[V4L2_PIX_FMT_H264] = QString(
"h264");
55 m[V4L2_PIX_FMT_MJPEG] = QString(
"mjpeg");
56 m[V4L2_PIX_FMT_YUYV] = QString(
"yuyv422");
57 m[V4L2_PIX_FMT_UYVY] = QString(
"uyvy422");
60 const std::map<uint32_t, QString>
pixFmtToName = createPixFmtToName();
62 static int deviceOpen(QString devName,
int* error)
64 struct v4l2_capability cap;
67 const std::string devNameString = devName.toStdString();
68 fd = open(devNameString.c_str(), O_RDWR, 0);
74 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) {
79 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
84 if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
96 static QVector<float> getDeviceModeFramerates(
int fd,
unsigned w,
unsigned h,
100 v4l2_frmivalenum vfve{};
101 vfve.pixel_format = pixelFormat;
105 while (!ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &vfve)) {
108 case V4L2_FRMSIZE_TYPE_DISCRETE:
109 rate = vfve.discrete.denominator / vfve.discrete.numerator;
110 if (!rates.contains(rate))
113 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
114 case V4L2_FRMSIZE_TYPE_STEPWISE:
115 rate = vfve.stepwise.min.denominator / vfve.stepwise.min.numerator;
116 if (!rates.contains(rate))
127 QVector<VideoMode> modes;
130 int fd = deviceOpen(devName, &error);
131 if (fd < 0 || error != 0) {
136 vfd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
138 while (!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) {
141 v4l2_frmsizeenum vfse{};
142 vfse.pixel_format = vfd.pixelformat;
144 while (!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
148 case V4L2_FRMSIZE_TYPE_DISCRETE:
149 mode.
width = vfse.discrete.width;
150 mode.
height = vfse.discrete.height;
152 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
153 case V4L2_FRMSIZE_TYPE_STEPWISE:
154 mode.
width = vfse.stepwise.max_width;
155 mode.
height = vfse.stepwise.max_height;
161 QVector<float> rates =
162 getDeviceModeFramerates(fd, mode.
width, mode.
height, vfd.pixelformat);
166 if (rates.isEmpty()) {
170 for (
float rate : rates) {
172 if (!modes.contains(mode)) {
173 modes.append(std::move(mode));
186 QVector<QPair<QString, QString>> devices;
187 QStringList deviceFiles;
189 DIR* dir = opendir(
"/dev");
194 while ((e = readdir(dir)))
195 if (!strncmp(e->d_name,
"video", 5) || !strncmp(e->d_name,
"vbi", 3))
196 deviceFiles += QString(
"/dev/") + e->d_name;
199 for (QString
file : deviceFiles) {
200 const std::string filePath =
file.toStdString();
201 int fd = open(filePath.c_str(), O_RDWR);
206 v4l2_capability caps;
207 ioctl(fd, VIDIOC_QUERYCAP, &caps);
210 if (caps.device_caps & V4L2_CAP_VIDEO_CAPTURE)
211 devices += {
file,
reinterpret_cast<const char*
>(caps.card)};
219 qWarning() <<
"Pixel format not found";
220 return QString(
"invalid");