1
0
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:
tux3 2015-06-01 16:37:31 +02:00
parent 0f7015941c
commit fe4838bb83
5 changed files with 148 additions and 4 deletions

View File

@ -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

View 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;
}

View 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

View File

@ -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;

View File

@ -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()