mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Video modesetting for v4l2
This commit is contained in:
parent
0f7015941c
commit
fe4838bb83
6
qtox.pro
6
qtox.pro
@ -459,7 +459,8 @@ SOURCES += \
|
||||
src/video/cameradevice.cpp \
|
||||
src/video/camerasource.cpp \
|
||||
src/video/corevideosource.cpp \
|
||||
src/core/toxid.cpp
|
||||
src/core/toxid.cpp \
|
||||
src/platform/camera/v4l2.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
@ -493,4 +494,5 @@ HEADERS += \
|
||||
src/video/camerasource.h \
|
||||
src/video/corevideosource.h \
|
||||
src/video/videomode.h \
|
||||
src/core/toxid.h
|
||||
src/core/toxid.h \
|
||||
src/platform/camera/v4l2.h
|
||||
|
109
src/platform/camera/v4l2.cpp
Normal file
109
src/platform/camera/v4l2.cpp
Normal file
@ -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;
|
||||
}
|
19
src/platform/camera/v4l2.h
Normal file
19
src/platform/camera/v4l2.h
Normal file
@ -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
|
||||
|
@ -9,6 +9,9 @@ extern "C" {
|
||||
#ifdef Q_OS_WIN
|
||||
#include "src/platform/camera/directshow.h"
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
#include "src/platform/camera/v4l2.h"
|
||||
#endif
|
||||
|
||||
QHash<QString, CameraDevice*> CameraDevice::openDevices;
|
||||
QMutex CameraDevice::openDeviceLock, CameraDevice::iformatLock;
|
||||
@ -62,6 +65,13 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode)
|
||||
av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0);
|
||||
av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
else if (iformat->name == QString("video4linux2,v4l2"))
|
||||
{
|
||||
av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0);
|
||||
av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
@ -196,6 +206,10 @@ QVector<VideoMode> CameraDevice::getVideoModes(QString devName)
|
||||
#ifdef Q_OS_WIN
|
||||
else if (iformat->name == QString("dshow"))
|
||||
return DirectShow::getDeviceModes(devName);
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
else if (iformat->name == QString("video4linux2,v4l2"))
|
||||
return v4l2::getDeviceModes(devName);
|
||||
#endif
|
||||
else
|
||||
qWarning() << "Video mode listing not implemented for input "<<iformat->name;
|
||||
|
@ -4,8 +4,8 @@
|
||||
/// Describes a video mode supported by a device
|
||||
struct VideoMode
|
||||
{
|
||||
short width, height; ///< Displayed video resolution (NOT frame resolution)
|
||||
short FPS; ///< Max frames per second supported by the device at this resolution
|
||||
unsigned short width, height; ///< Displayed video resolution (NOT frame resolution)
|
||||
unsigned short FPS; ///< Max frames per second supported by the device at this resolution
|
||||
|
||||
/// All zeros means a default/unspecified mode
|
||||
operator bool()
|
||||
|
Loading…
x
Reference in New Issue
Block a user