mirror of https://github.com/qTox/qTox.git
5 changed files with 148 additions and 4 deletions
@ -0,0 +1,109 @@
@@ -0,0 +1,109 @@
|
||||
#include "v4l2.h" |
||||
|
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#include <sys/ioctl.h> |
||||
#include <linux/videodev2.h> |
||||
|
||||
/**
|
||||
* Most of this file is adapted from libavdevice's v4l2.c, |
||||
* which retrieves useful information but only exposes it to |
||||
* stdout and is not part of the public API for some reason. |
||||
*/ |
||||
|
||||
static int deviceOpen(QString devName) |
||||
{ |
||||
struct v4l2_capability cap; |
||||
int fd; |
||||
int err; |
||||
|
||||
fd = open(devName.toStdString().c_str(), O_RDWR, 0); |
||||
if (fd < 0) |
||||
return errno; |
||||
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { |
||||
err = errno; |
||||
goto fail; |
||||
} |
||||
|
||||
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { |
||||
err = ENODEV; |
||||
goto fail; |
||||
} |
||||
|
||||
if (!(cap.capabilities & V4L2_CAP_STREAMING)) { |
||||
err = ENOSYS; |
||||
goto fail; |
||||
} |
||||
|
||||
return fd; |
||||
|
||||
fail: |
||||
close(fd); |
||||
return err; |
||||
} |
||||
|
||||
static QVector<unsigned short> getDeviceModeFramerates(int fd, unsigned w, unsigned h, uint32_t pixelFormat) |
||||
{ |
||||
QVector<unsigned short> rates; |
||||
v4l2_frmivalenum vfve = { .pixel_format = pixelFormat, .height = h, .width = w }; |
||||
|
||||
while(!ioctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &vfve)) { |
||||
int rate; |
||||
switch (vfve.type) { |
||||
case V4L2_FRMSIZE_TYPE_DISCRETE: |
||||
rate = vfve.discrete.denominator / vfve.discrete.numerator; |
||||
if (!rates.contains(rate)) |
||||
rates.append(rate); |
||||
break; |
||||
case V4L2_FRMSIZE_TYPE_CONTINUOUS: |
||||
case V4L2_FRMSIZE_TYPE_STEPWISE: |
||||
rate = vfve.stepwise.min.denominator / vfve.stepwise.min.numerator; |
||||
if (!rates.contains(rate)) |
||||
rates.append(rate); |
||||
} |
||||
vfve.index++; |
||||
} |
||||
|
||||
return rates; |
||||
} |
||||
|
||||
QVector<VideoMode> v4l2::getDeviceModes(QString devName) |
||||
{ |
||||
QVector<VideoMode> modes; |
||||
|
||||
int fd = deviceOpen(devName); |
||||
if (fd < 0) |
||||
return modes; |
||||
v4l2_fmtdesc vfd = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE }; |
||||
|
||||
while(!ioctl(fd, VIDIOC_ENUM_FMT, &vfd)) { |
||||
vfd.index++; |
||||
|
||||
v4l2_frmsizeenum vfse = { .pixel_format = vfd.pixelformat }; |
||||
|
||||
while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) { |
||||
VideoMode mode; |
||||
switch (vfse.type) { |
||||
case V4L2_FRMSIZE_TYPE_DISCRETE: |
||||
mode.width = vfse.discrete.width; |
||||
mode.height = vfse.discrete.height; |
||||
break; |
||||
case V4L2_FRMSIZE_TYPE_CONTINUOUS: |
||||
case V4L2_FRMSIZE_TYPE_STEPWISE: |
||||
mode.width = vfse.stepwise.max_width; |
||||
mode.height = vfse.stepwise.max_height; |
||||
} |
||||
QVector<unsigned short> rates = getDeviceModeFramerates(fd, mode.width, mode.height, vfd.pixelformat); |
||||
for (unsigned short rate : rates) |
||||
{ |
||||
mode.FPS = rate; |
||||
if (!modes.contains(mode)) |
||||
modes.append(std::move(mode)); |
||||
} |
||||
vfse.index++; |
||||
} |
||||
} |
||||
|
||||
return modes; |
||||
} |
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
#ifndef V4L2_H |
||||
#define V4L2_H |
||||
|
||||
#include <QString> |
||||
#include <QVector> |
||||
#include <QPair> |
||||
#include "src/video/videomode.h" |
||||
|
||||
#ifndef Q_OS_LINUX |
||||
#error "This file is only meant to be compiled for Linux targets" |
||||
#endif |
||||
|
||||
namespace v4l2 |
||||
{ |
||||
QVector<VideoMode> getDeviceModes(QString devName); |
||||
} |
||||
|
||||
#endif // V4L2_H
|
||||
|
Loading…
Reference in new issue