From ded8d87ba811eac0cb45f6df0eb0d2c040a3b2e5 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 26 Jan 2016 13:14:58 -0600 Subject: [PATCH 1/4] generic pixel format selection --- src/platform/camera/v4l2.cpp | 21 +++++++++++++++++++++ src/platform/camera/v4l2.h | 1 + src/video/cameradevice.cpp | 18 +++++++++++++++--- src/video/cameradevice.h | 2 ++ src/video/camerasource.cpp | 4 ++-- src/video/videomode.h | 4 +++- src/widget/form/settings/avform.cpp | 2 ++ 7 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/platform/camera/v4l2.cpp b/src/platform/camera/v4l2.cpp index 172bd4695..392542dff 100644 --- a/src/platform/camera/v4l2.cpp +++ b/src/platform/camera/v4l2.cpp @@ -113,6 +113,7 @@ QVector v4l2::getDeviceModes(QString devName) while(!ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &vfse)) { VideoMode mode; + mode.pixel_format = vfse.pixel_format; switch (vfse.type) { case V4L2_FRMSIZE_TYPE_DISCRETE: mode.width = vfse.discrete.width; @@ -169,3 +170,23 @@ QVector> v4l2::getDeviceList() } return devices; } + +QString v4l2::getPixelFormatString(uint32_t pixel_format) +{ + if (pixel_format == V4L2_PIX_FMT_H264) + { + return QString("h264"); + } + if (pixel_format == V4L2_PIX_FMT_MJPEG) + { + return QString("mjpeg"); + } + else if (pixel_format == V4L2_PIX_FMT_YUYV) + { + return QString("yuyv422"); + } + else { + return QString("unknown"); + } +} + diff --git a/src/platform/camera/v4l2.h b/src/platform/camera/v4l2.h index a4a8292e3..8d82de9cd 100644 --- a/src/platform/camera/v4l2.h +++ b/src/platform/camera/v4l2.h @@ -32,6 +32,7 @@ namespace v4l2 { QVector getDeviceModes(QString devName); QVector> getDeviceList(); + QString getPixelFormatString(uint32_t pixel_format); } #endif // V4L2_H diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index f774bfb12..1d55da2ac 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -17,7 +17,6 @@ along with qTox. If not, see . */ - #include #include #include @@ -105,7 +104,7 @@ out: CameraDevice* CameraDevice::open(QString devName) { - VideoMode mode{0,0,0}; + VideoMode mode{0,0,0,0}; 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, "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 #ifdef Q_OS_OSX @@ -360,6 +363,15 @@ QVector CameraDevice::getVideoModes(QString devName) return {}; } +QString CameraDevice::getPixelFormatString(uint32_t pixel_format) +{ +#ifdef Q_OS_LINUX + return v4l2::getPixelFormatString(pixel_format); +#else + return QString("unknown"); +#endif +} + bool CameraDevice::getDefaultInputFormat() { QMutexLocker locker(&iformatLock); diff --git a/src/video/cameradevice.h b/src/video/cameradevice.h index 83209aeeb..ced3d4e14 100644 --- a/src/video/cameradevice.h +++ b/src/video/cameradevice.h @@ -59,6 +59,8 @@ public: /// Get the list of video modes for a device static QVector getVideoModes(QString devName); + /// Get the name of the pixel format of a video mode + static QString getPixelFormatString(uint32_t pixel_format); /// Returns the short name of the default defice /// This is either the device in the settings diff --git a/src/video/camerasource.cpp b/src/video/camerasource.cpp index 25fd5473c..dd1beb143 100644 --- a/src/video/camerasource.cpp +++ b/src/video/camerasource.cpp @@ -35,7 +35,7 @@ extern "C" { CameraSource* CameraSource::instance{nullptr}; 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}, _isOpen{false}, streamBlocker{false}, subscriptions{0} { @@ -67,7 +67,7 @@ void CameraSource::open() 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) diff --git a/src/video/videomode.h b/src/video/videomode.h index d3e17f98b..c1628f439 100644 --- a/src/video/videomode.h +++ b/src/video/videomode.h @@ -26,6 +26,7 @@ struct VideoMode { unsigned short width, height; ///< Displayed video resolution (NOT frame 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 operator bool() const @@ -37,7 +38,8 @@ struct VideoMode { return width == other.width && height == other.height - && FPS == other.FPS; + && FPS == other.FPS + && pixel_format == other.pixel_format; } }; diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 849eaa3f2..71534df05 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -187,6 +187,8 @@ void AVForm::updateVideoModes(int curIndex) 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()) From de4dcb5bd7035fe3a136ea746c8f9adcbc5c0f93 Mon Sep 17 00:00:00 2001 From: Sean Laguna Date: Tue, 26 Jan 2016 13:27:32 -0600 Subject: [PATCH 2/4] whoops, forgot an else in an else if --- src/platform/camera/v4l2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/camera/v4l2.cpp b/src/platform/camera/v4l2.cpp index 392542dff..28f0ee35d 100644 --- a/src/platform/camera/v4l2.cpp +++ b/src/platform/camera/v4l2.cpp @@ -177,7 +177,7 @@ QString v4l2::getPixelFormatString(uint32_t pixel_format) { return QString("h264"); } - if (pixel_format == V4L2_PIX_FMT_MJPEG) + else if (pixel_format == V4L2_PIX_FMT_MJPEG) { return QString("mjpeg"); } From ffa312b91b6548cf956307c8f7fcd6b80c46aa39 Mon Sep 17 00:00:00 2001 From: Sean Date: Tue, 26 Jan 2016 13:34:29 -0600 Subject: [PATCH 3/4] tabs to spaces --- src/video/cameradevice.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 1d55da2ac..398eaf9da 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -166,7 +166,7 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode) 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); + av_dict_set(&options, "pixel_format", pixel_format, 0); } } #endif From f595f4f81715bb305827c93e9a16c838558fda53 Mon Sep 17 00:00:00 2001 From: Sean Date: Mon, 21 Mar 2016 21:17:21 -0500 Subject: [PATCH 4/4] camera res option reduction --- src/platform/camera/v4l2.cpp | 49 ++++++++++++++++++------- src/platform/camera/v4l2.h | 1 + src/video/cameradevice.cpp | 9 +++++ src/video/cameradevice.h | 2 ++ src/video/videoframe.cpp | 11 ++++-- src/video/videomode.h | 5 +++ src/widget/form/settings/avform.cpp | 55 +++++++++++++++++++++++++---- 7 files changed, 111 insertions(+), 21 deletions(-) diff --git a/src/platform/camera/v4l2.cpp b/src/platform/camera/v4l2.cpp index 28f0ee35d..a442afad4 100644 --- a/src/platform/camera/v4l2.cpp +++ b/src/platform/camera/v4l2.cpp @@ -28,6 +28,7 @@ #include #include #include +#include /** * 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 createPixFmtToQuality() +{ + std::map m; + m[V4L2_PIX_FMT_H264] = 3; + m[V4L2_PIX_FMT_MJPEG] = 2; + m[V4L2_PIX_FMT_YUYV] = 1; + return m; +} +const std::map pixFmtToQuality = createPixFmtToQuality(); + +static std::map createPixFmtToName() +{ + std::map 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 pixFmtToName = createPixFmtToName(); + static int deviceOpen(QString devName) { struct v4l2_capability cap; @@ -173,20 +194,24 @@ QVector> 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); } diff --git a/src/platform/camera/v4l2.h b/src/platform/camera/v4l2.h index 8d82de9cd..c9556c84c 100644 --- a/src/platform/camera/v4l2.h +++ b/src/platform/camera/v4l2.h @@ -33,6 +33,7 @@ namespace v4l2 QVector getDeviceModes(QString devName); QVector> getDeviceList(); QString getPixelFormatString(uint32_t pixel_format); + bool betterPixelFormat(uint32_t a, uint32_t b); } #endif // V4L2_H diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 398eaf9da..113f26e96 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -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); diff --git a/src/video/cameradevice.h b/src/video/cameradevice.h index ced3d4e14..e6f304e35 100644 --- a/src/video/cameradevice.h +++ b/src/video/cameradevice.h @@ -61,6 +61,8 @@ public: static QVector 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 diff --git a/src/video/videoframe.cpp b/src/video/videoframe.cpp index 427cfa8c8..c686b5fde 100644 --- a/src/video/videoframe.cpp +++ b/src/video/videoframe.cpp @@ -17,6 +17,8 @@ along with qTox. If not, see . */ +#include + #include #include #include @@ -48,12 +50,13 @@ VideoFrame::VideoFrame(AVFrame* frame, int w, int h, int fmt, std::functioncolor_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 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) diff --git a/src/video/videomode.h b/src/video/videomode.h index c1628f439..b3560409c 100644 --- a/src/video/videomode.h +++ b/src/video/videomode.h @@ -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 diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 71534df05..3d1b55e36 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -30,6 +30,7 @@ #include #include +#include #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 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 bestModeInds; + for (int i=0; ifirst; + 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; isecond; 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())