1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

camera res option reduction

This commit is contained in:
Sean 2016-03-21 21:17:21 -05:00
parent ffa312b91b
commit f595f4f817
7 changed files with 111 additions and 21 deletions

View File

@ -28,6 +28,7 @@
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#include <dirent.h>
#include <map>
/**
* 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.
*/
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)
{
struct v4l2_capability cap;
@ -173,20 +194,24 @@ QVector<QPair<QString, QString>> v4l2::getDeviceList()
QString v4l2::getPixelFormatString(uint32_t pixel_format)
{
if (pixel_format == V4L2_PIX_FMT_H264)
if (pixFmtToName.find(pixel_format) == pixFmtToName.end())
{
return QString("h264");
}
else if (pixel_format == V4L2_PIX_FMT_MJPEG)
{
return QString("mjpeg");
}
else if (pixel_format == V4L2_PIX_FMT_YUYV)
{
return QString("yuyv422");
}
else {
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);
}

View File

@ -33,6 +33,7 @@ namespace v4l2
QVector<VideoMode> getDeviceModes(QString devName);
QVector<QPair<QString, QString>> getDeviceList();
QString getPixelFormatString(uint32_t pixel_format);
bool betterPixelFormat(uint32_t a, uint32_t b);
}
#endif // V4L2_H

View File

@ -372,6 +372,15 @@ QString CameraDevice::getPixelFormatString(uint32_t pixel_format)
#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()
{
QMutexLocker locker(&iformatLock);

View File

@ -61,6 +61,8 @@ public:
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
/// This is either the device in the settings

View File

@ -17,6 +17,8 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <QMutexLocker>
#include <QDebug>
#include <vpx/vpx_image.h>
@ -48,12 +50,13 @@ VideoFrame::VideoFrame(AVFrame* frame, int w, int h, int fmt, std::function<void
else
frame->color_range = AVCOL_RANGE_UNSPECIFIED;
if (pixFmt == AV_PIX_FMT_YUV420P)
if (pixFmt == AV_PIX_FMT_YUV420P) {
frameYUV420 = frame;
else if (pixFmt == AV_PIX_FMT_RGB24)
} else if (pixFmt == AV_PIX_FMT_RGB24) {
frameRGB24 = frame;
else
} else {
frameOther = frame;
}
}
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?";
return false;
}
//std::cout << "converting to RGB24" << std::endl;
if (size.isEmpty())
{
@ -198,6 +202,7 @@ bool VideoFrame::convertToYUV420()
qCritical() << "None of the frames are valid! Did someone release us?";
return false;
}
//std::cout << "converting to YUV420" << std::endl;
frameYUV420=av_frame_alloc();
if (!frameYUV420)

View File

@ -41,6 +41,11 @@ struct VideoMode
&& 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);
}
};
#endif // VIDEOMODE_H

View File

@ -30,6 +30,7 @@
#include <QDebug>
#include <QShowEvent>
#include <map>
#ifndef ALC_ALL_DEVICES_SPECIFIER
#define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER
@ -172,23 +173,65 @@ void AVForm::updateVideoModes(int curIndex)
a.FPS>b.FPS;});
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
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;
QSize prefRes = Settings::getInstance().getCamVideoRes();
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];
if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1)
prefResIndex = i;
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)
str += tr("%1x%2").arg(mode.width).arg(mode.height);
str += tr("%1p").arg(iter->first);
else
str += tr("Default resolution");
if (mode.FPS)
str += tr(" at %1 FPS").arg(mode.FPS);
if (mode.pixel_format)
str += tr(" using %1").arg(CameraDevice::getPixelFormatString(mode.pixel_format));
bodyUI->videoModescomboBox->addItem(str);
}
if (videoModes.isEmpty())