mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge pull request #2867
Sean (5): generic pixel format selection Merge branch 'master' of https://github.com/seanlaguna/qTox into pixfmt Merge branch 'pixfmt' of https://github.com/seanlaguna/qTox into pixfmt tabs to spaces camera res option reduction Sean Laguna (1): whoops, forgot an else in an else if
This commit is contained in:
commit
3f89cd95d5
|
@ -28,6 +28,7 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Most of this file is adapted from libavdevice's v4l2.c,
|
* Most of this file is adapted from libavdevice's v4l2.c,
|
||||||
|
@ -35,6 +36,26 @@
|
||||||
* stdout and is not part of the public API for some reason.
|
* stdout and is not part of the public API for some reason.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static std::map<uint32_t,uint8_t> createPixFmtToQuality()
|
||||||
|
{
|
||||||
|
std::map<uint32_t,uint8_t> m;
|
||||||
|
m[V4L2_PIX_FMT_H264] = 3;
|
||||||
|
m[V4L2_PIX_FMT_MJPEG] = 2;
|
||||||
|
m[V4L2_PIX_FMT_YUYV] = 1;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
const std::map<uint32_t,uint8_t> pixFmtToQuality = createPixFmtToQuality();
|
||||||
|
|
||||||
|
static std::map<uint32_t,QString> createPixFmtToName()
|
||||||
|
{
|
||||||
|
std::map<uint32_t,QString> m;
|
||||||
|
m[V4L2_PIX_FMT_H264] = QString("h264");
|
||||||
|
m[V4L2_PIX_FMT_MJPEG] = QString("mjpeg");
|
||||||
|
m[V4L2_PIX_FMT_YUYV] = QString("yuyv422");
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
const std::map<uint32_t,QString> pixFmtToName = createPixFmtToName();
|
||||||
|
|
||||||
static int deviceOpen(QString devName)
|
static int deviceOpen(QString devName)
|
||||||
{
|
{
|
||||||
struct v4l2_capability cap;
|
struct v4l2_capability cap;
|
||||||
|
@ -113,6 +134,7 @@ QVector<VideoMode> v4l2::getDeviceModes(QString devName)
|
||||||
|
|
||||||
while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
|
while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) {
|
||||||
VideoMode mode;
|
VideoMode mode;
|
||||||
|
mode.pixel_format = vfse.pixel_format;
|
||||||
switch (vfse.type) {
|
switch (vfse.type) {
|
||||||
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
case V4L2_FRMSIZE_TYPE_DISCRETE:
|
||||||
mode.width = vfse.discrete.width;
|
mode.width = vfse.discrete.width;
|
||||||
|
@ -169,3 +191,27 @@ QVector<QPair<QString, QString>> v4l2::getDeviceList()
|
||||||
}
|
}
|
||||||
return devices;
|
return devices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString v4l2::getPixelFormatString(uint32_t pixel_format)
|
||||||
|
{
|
||||||
|
if (pixFmtToName.find(pixel_format) == pixFmtToName.end())
|
||||||
|
{
|
||||||
|
printf("BAD!\n");
|
||||||
|
return QString("unknown");
|
||||||
|
}
|
||||||
|
return pixFmtToName.at(pixel_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool v4l2::betterPixelFormat(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
if (pixFmtToQuality.find(a) == pixFmtToQuality.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (pixFmtToQuality.find(b) == pixFmtToQuality.end())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return pixFmtToQuality.at(a) > pixFmtToQuality.at(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ namespace v4l2
|
||||||
{
|
{
|
||||||
QVector<VideoMode> getDeviceModes(QString devName);
|
QVector<VideoMode> getDeviceModes(QString devName);
|
||||||
QVector<QPair<QString, QString>> getDeviceList();
|
QVector<QPair<QString, QString>> getDeviceList();
|
||||||
|
QString getPixelFormatString(uint32_t pixel_format);
|
||||||
|
bool betterPixelFormat(uint32_t a, uint32_t b);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // V4L2_H
|
#endif // V4L2_H
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
|
@ -105,7 +104,7 @@ out:
|
||||||
|
|
||||||
CameraDevice* CameraDevice::open(QString devName)
|
CameraDevice* CameraDevice::open(QString devName)
|
||||||
{
|
{
|
||||||
VideoMode mode{0,0,0};
|
VideoMode mode{0,0,0,0};
|
||||||
return open(devName, mode);
|
return open(devName, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +163,11 @@ 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, "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);
|
av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0);
|
||||||
av_dict_set(&options, "pixel_format", "mjpeg", 0);
|
const char *pixel_format = v4l2::getPixelFormatString(mode.pixel_format).toStdString().c_str();
|
||||||
|
if (strncmp(pixel_format, "unknown", 7) != 0)
|
||||||
|
{
|
||||||
|
av_dict_set(&options, "pixel_format", pixel_format, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef Q_OS_OSX
|
#ifdef Q_OS_OSX
|
||||||
|
@ -360,6 +363,24 @@ QVector<VideoMode> CameraDevice::getVideoModes(QString devName)
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString CameraDevice::getPixelFormatString(uint32_t pixel_format)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
return v4l2::getPixelFormatString(pixel_format);
|
||||||
|
#else
|
||||||
|
return QString("unknown");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CameraDevice::betterPixelFormat(uint32_t a, uint32_t b)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
return v4l2::betterPixelFormat(a, b);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool CameraDevice::getDefaultInputFormat()
|
bool CameraDevice::getDefaultInputFormat()
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&iformatLock);
|
QMutexLocker locker(&iformatLock);
|
||||||
|
|
|
@ -59,6 +59,10 @@ public:
|
||||||
|
|
||||||
/// Get the list of video modes for a device
|
/// Get the list of video modes for a device
|
||||||
static QVector<VideoMode> getVideoModes(QString devName);
|
static QVector<VideoMode> getVideoModes(QString devName);
|
||||||
|
/// Get the name of the pixel format of a video mode
|
||||||
|
static QString getPixelFormatString(uint32_t pixel_format);
|
||||||
|
/// Returns true if we prefer format a to b, false otherwise (such as if there's no preference)
|
||||||
|
static bool betterPixelFormat(uint32_t a, uint32_t b);
|
||||||
|
|
||||||
/// Returns the short name of the default defice
|
/// Returns the short name of the default defice
|
||||||
/// This is either the device in the settings
|
/// This is either the device in the settings
|
||||||
|
|
|
@ -35,7 +35,7 @@ extern "C" {
|
||||||
CameraSource* CameraSource::instance{nullptr};
|
CameraSource* CameraSource::instance{nullptr};
|
||||||
|
|
||||||
CameraSource::CameraSource()
|
CameraSource::CameraSource()
|
||||||
: deviceName{"none"}, device{nullptr}, mode(VideoMode{0,0,0}),
|
: deviceName{"none"}, device{nullptr}, mode(VideoMode{0,0,0,0}),
|
||||||
cctx{nullptr}, cctxOrig{nullptr}, videoStreamIndex{-1},
|
cctx{nullptr}, cctxOrig{nullptr}, videoStreamIndex{-1},
|
||||||
_isOpen{false}, streamBlocker{false}, subscriptions{0}
|
_isOpen{false}, streamBlocker{false}, subscriptions{0}
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ void CameraSource::open()
|
||||||
|
|
||||||
void CameraSource::open(const QString deviceName)
|
void CameraSource::open(const QString deviceName)
|
||||||
{
|
{
|
||||||
open(deviceName, VideoMode{0,0,0});
|
open(deviceName, VideoMode{0,0,0,0});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraSource::open(const QString DeviceName, VideoMode Mode)
|
void CameraSource::open(const QString DeviceName, VideoMode Mode)
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <QMutexLocker>
|
#include <QMutexLocker>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <vpx/vpx_image.h>
|
#include <vpx/vpx_image.h>
|
||||||
|
@ -48,12 +50,13 @@ VideoFrame::VideoFrame(AVFrame* frame, int w, int h, int fmt, std::function<void
|
||||||
else
|
else
|
||||||
frame->color_range = AVCOL_RANGE_UNSPECIFIED;
|
frame->color_range = AVCOL_RANGE_UNSPECIFIED;
|
||||||
|
|
||||||
if (pixFmt == AV_PIX_FMT_YUV420P)
|
if (pixFmt == AV_PIX_FMT_YUV420P) {
|
||||||
frameYUV420 = frame;
|
frameYUV420 = frame;
|
||||||
else if (pixFmt == AV_PIX_FMT_RGB24)
|
} else if (pixFmt == AV_PIX_FMT_RGB24) {
|
||||||
frameRGB24 = frame;
|
frameRGB24 = frame;
|
||||||
else
|
} else {
|
||||||
frameOther = frame;
|
frameOther = frame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoFrame::VideoFrame(AVFrame* frame, std::function<void()> freelistCallback)
|
VideoFrame::VideoFrame(AVFrame* frame, std::function<void()> freelistCallback)
|
||||||
|
@ -126,6 +129,7 @@ bool VideoFrame::convertToRGB24(QSize size)
|
||||||
qWarning() << "None of the frames are valid! Did someone release us?";
|
qWarning() << "None of the frames are valid! Did someone release us?";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//std::cout << "converting to RGB24" << std::endl;
|
||||||
|
|
||||||
if (size.isEmpty())
|
if (size.isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -198,6 +202,7 @@ bool VideoFrame::convertToYUV420()
|
||||||
qCritical() << "None of the frames are valid! Did someone release us?";
|
qCritical() << "None of the frames are valid! Did someone release us?";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
//std::cout << "converting to YUV420" << std::endl;
|
||||||
|
|
||||||
frameYUV420=av_frame_alloc();
|
frameYUV420=av_frame_alloc();
|
||||||
if (!frameYUV420)
|
if (!frameYUV420)
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct VideoMode
|
||||||
{
|
{
|
||||||
unsigned short width, height; ///< Displayed video resolution (NOT frame resolution)
|
unsigned short width, height; ///< Displayed video resolution (NOT frame resolution)
|
||||||
float FPS; ///< Max frames per second supported by the device at this resolution
|
float FPS; ///< Max frames per second supported by the device at this resolution
|
||||||
|
uint32_t pixel_format;
|
||||||
|
|
||||||
/// All zeros means a default/unspecified mode
|
/// All zeros means a default/unspecified mode
|
||||||
operator bool() const
|
operator bool() const
|
||||||
|
@ -37,7 +38,13 @@ struct VideoMode
|
||||||
{
|
{
|
||||||
return width == other.width
|
return width == other.width
|
||||||
&& height == other.height
|
&& height == other.height
|
||||||
&& FPS == other.FPS;
|
&& FPS == other.FPS
|
||||||
|
&& pixel_format == other.pixel_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t norm(const VideoMode& other) const
|
||||||
|
{
|
||||||
|
return std::abs(this->width-other.width) + std::abs(this->height-other.height);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
#ifndef ALC_ALL_DEVICES_SPECIFIER
|
||||||
#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER
|
#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER
|
||||||
|
@ -159,21 +160,65 @@ void AVForm::updateVideoModes(int curIndex)
|
||||||
a.FPS>b.FPS;});
|
a.FPS>b.FPS;});
|
||||||
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
||||||
bodyUI->videoModescomboBox->clear();
|
bodyUI->videoModescomboBox->clear();
|
||||||
|
|
||||||
|
// Identify the best resolutions available for the supposed XXXXp resolutions.
|
||||||
|
std::map<int, VideoMode> idealModes;
|
||||||
|
idealModes[240] = {460,240,0,0}; idealModes[360] = {640,360,0,0};
|
||||||
|
idealModes[480] = {854,480,0,0}; idealModes[720] = {1280,720,0,0};
|
||||||
|
idealModes[1080] = {1920,1080,0,0};
|
||||||
|
std::map<int, int> bestModeInds;
|
||||||
|
for (int i=0; i<videoModes.size(); ++i)
|
||||||
|
{
|
||||||
|
VideoMode mode = videoModes[i];
|
||||||
|
printf("width: %d, height: %d, FPS: %f, pixel format: %s\n", mode.width, mode.height, mode.FPS, CameraDevice::getPixelFormatString(mode.pixel_format).toStdString().c_str());
|
||||||
|
for(auto iter = idealModes.begin(); iter != idealModes.end(); ++iter)
|
||||||
|
{
|
||||||
|
int res = iter->first;
|
||||||
|
VideoMode idealMode = iter->second;
|
||||||
|
// don't take approximately correct resolutions unless they really
|
||||||
|
// are close
|
||||||
|
if (mode.norm(idealMode) > 300) continue;
|
||||||
|
if (bestModeInds.find(res) == bestModeInds.end())
|
||||||
|
{
|
||||||
|
bestModeInds[res] = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int ind = bestModeInds[res];
|
||||||
|
if (mode.norm(idealMode) < videoModes[ind].norm(idealMode))
|
||||||
|
{
|
||||||
|
bestModeInds[res] = i;
|
||||||
|
}
|
||||||
|
else if (mode.norm(idealMode) == videoModes[ind].norm(idealMode))
|
||||||
|
{
|
||||||
|
// prefer higher FPS and "better" pixel formats
|
||||||
|
if (mode.FPS > videoModes[ind].FPS) {
|
||||||
|
bestModeInds[res] = i;
|
||||||
|
}
|
||||||
|
else if (mode.FPS == videoModes[ind].FPS &&
|
||||||
|
CameraDevice::betterPixelFormat(mode.pixel_format, videoModes[ind].pixel_format))
|
||||||
|
{
|
||||||
|
bestModeInds[res] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("=====\n");
|
||||||
int prefResIndex = -1;
|
int prefResIndex = -1;
|
||||||
QSize prefRes = Settings::getInstance().getCamVideoRes();
|
QSize prefRes = Settings::getInstance().getCamVideoRes();
|
||||||
unsigned short prefFPS = Settings::getInstance().getCamVideoFPS();
|
unsigned short prefFPS = Settings::getInstance().getCamVideoFPS();
|
||||||
for (int i=0; i<videoModes.size(); ++i)
|
// Iterate backwards to show higest resolution first.
|
||||||
|
for(auto iter = bestModeInds.rbegin(); iter != bestModeInds.rend(); ++iter)
|
||||||
{
|
{
|
||||||
|
int i = iter->second;
|
||||||
VideoMode mode = videoModes[i];
|
VideoMode mode = videoModes[i];
|
||||||
if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1)
|
if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1)
|
||||||
prefResIndex = i;
|
prefResIndex = i;
|
||||||
QString str;
|
QString str;
|
||||||
|
printf("width: %d, height: %d, FPS: %f, pixel format: %s\n", mode.width, mode.height, mode.FPS, CameraDevice::getPixelFormatString(mode.pixel_format).toStdString().c_str());
|
||||||
if (mode.height && mode.width)
|
if (mode.height && mode.width)
|
||||||
str += tr("%1x%2").arg(mode.width).arg(mode.height);
|
str += tr("%1p").arg(iter->first);
|
||||||
else
|
else
|
||||||
str += tr("Default resolution");
|
str += tr("Default resolution");
|
||||||
if (mode.FPS)
|
|
||||||
str += tr(" at %1 FPS").arg(mode.FPS);
|
|
||||||
bodyUI->videoModescomboBox->addItem(str);
|
bodyUI->videoModescomboBox->addItem(str);
|
||||||
}
|
}
|
||||||
if (videoModes.isEmpty())
|
if (videoModes.isEmpty())
|
||||||
|
|
Loading…
Reference in New Issue
Block a user