mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge pull request #3392
Diadlo (12): refactor(avform): Extracted functions with best mode search and combo box filling refactor(avform): Replace `bestModeInds` on videoMode index and video height as quality name refactor(avform): Separeted search of preferred index in function fix(avform): Took default resolution from middle of list feat(videomode): Added possible video shift feat(cameradevice, avform): Added ability of screen selection feat(avform, screenshotgrabber): Added custom screen region selection style(corevideosource): Small style fixes fix(videoframe): Added correct image copy fix(avform): Added restoring selected region feat(camerasource): Change default video mode to preferred fix(directshow): Fixed problem with crosses initialization
This commit is contained in:
commit
e97a870c0f
|
@ -295,7 +295,7 @@ void CoreAV::sendCallVideo(uint32_t callId, shared_ptr<VideoFrame> vframe)
|
||||||
if (frame->fmt == VPX_IMG_FMT_NONE)
|
if (frame->fmt == VPX_IMG_FMT_NONE)
|
||||||
{
|
{
|
||||||
qWarning() << "Invalid frame";
|
qWarning() << "Invalid frame";
|
||||||
delete frame;
|
vpx_img_free(frame);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,7 +321,7 @@ void CoreAV::sendCallVideo(uint32_t callId, shared_ptr<VideoFrame> vframe)
|
||||||
if (err == TOXAV_ERR_SEND_FRAME_SYNC)
|
if (err == TOXAV_ERR_SEND_FRAME_SYNC)
|
||||||
qDebug() << "toxav_video_send_frame error: Lock busy, dropping frame";
|
qDebug() << "toxav_video_send_frame error: Lock busy, dropping frame";
|
||||||
|
|
||||||
delete frame;
|
vpx_img_free(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreAV::micMuteToggle(uint32_t callId)
|
void CoreAV::micMuteToggle(uint32_t callId)
|
||||||
|
|
|
@ -102,6 +102,7 @@ ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
|
||||||
{
|
{
|
||||||
videoSource = new CoreVideoSource;
|
videoSource = new CoreVideoSource;
|
||||||
CameraSource& source = CameraSource::getInstance();
|
CameraSource& source = CameraSource::getInstance();
|
||||||
|
|
||||||
if (!source.isOpen())
|
if (!source.isOpen())
|
||||||
source.open();
|
source.open();
|
||||||
source.subscribe();
|
source.subscribe();
|
||||||
|
|
|
@ -251,7 +251,9 @@ void Settings::loadGlobal()
|
||||||
|
|
||||||
s.beginGroup("Video");
|
s.beginGroup("Video");
|
||||||
videoDev = s.value("videoDev", "").toString();
|
videoDev = s.value("videoDev", "").toString();
|
||||||
camVideoRes = s.value("camVideoRes",QSize()).toSize();
|
camVideoRes = s.value("camVideoRes", QRect()).toRect();
|
||||||
|
screenRegion = s.value("screenRegion", QRect()).toRect();
|
||||||
|
screenGrabbed = s.value("screenGrabbed", false).toBool();
|
||||||
camVideoFPS = s.value("camVideoFPS", 0).toUInt();
|
camVideoFPS = s.value("camVideoFPS", 0).toUInt();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
|
@ -489,8 +491,10 @@ void Settings::saveGlobal()
|
||||||
|
|
||||||
s.beginGroup("Video");
|
s.beginGroup("Video");
|
||||||
s.setValue("videoDev", videoDev);
|
s.setValue("videoDev", videoDev);
|
||||||
s.setValue("camVideoRes",camVideoRes);
|
s.setValue("camVideoRes", camVideoRes);
|
||||||
s.setValue("camVideoFPS",camVideoFPS);
|
s.setValue("camVideoFPS", camVideoFPS);
|
||||||
|
s.setValue("screenRegion", screenRegion);
|
||||||
|
s.setValue("screenGrabbed", screenGrabbed);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1465,13 +1469,35 @@ void Settings::setOutVolume(int volume)
|
||||||
outVolume = volume;
|
outVolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize Settings::getCamVideoRes() const
|
QRect Settings::getScreenRegion() const
|
||||||
|
{
|
||||||
|
return screenRegion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setScreenRegion(const QRect &value)
|
||||||
|
{
|
||||||
|
QMutexLocker locker{&bigLock};
|
||||||
|
screenRegion = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Settings::getScreenGrabbed() const
|
||||||
|
{
|
||||||
|
return screenGrabbed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setScreenGrabbed(bool value)
|
||||||
|
{
|
||||||
|
QMutexLocker locker{&bigLock};
|
||||||
|
screenGrabbed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect Settings::getCamVideoRes() const
|
||||||
{
|
{
|
||||||
QMutexLocker locker{&bigLock};
|
QMutexLocker locker{&bigLock};
|
||||||
return camVideoRes;
|
return camVideoRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::setCamVideoRes(QSize newValue)
|
void Settings::setCamVideoRes(QRect newValue)
|
||||||
{
|
{
|
||||||
QMutexLocker locker{&bigLock};
|
QMutexLocker locker{&bigLock};
|
||||||
camVideoRes = newValue;
|
camVideoRes = newValue;
|
||||||
|
|
|
@ -197,8 +197,14 @@ public:
|
||||||
QString getVideoDev() const;
|
QString getVideoDev() const;
|
||||||
void setVideoDev(const QString& deviceSpecifier);
|
void setVideoDev(const QString& deviceSpecifier);
|
||||||
|
|
||||||
QSize getCamVideoRes() const;
|
QRect getScreenRegion() const;
|
||||||
void setCamVideoRes(QSize newValue);
|
void setScreenRegion(const QRect &value);
|
||||||
|
|
||||||
|
bool getScreenGrabbed() const;
|
||||||
|
void setScreenGrabbed(bool value);
|
||||||
|
|
||||||
|
QRect getCamVideoRes() const;
|
||||||
|
void setCamVideoRes(QRect newValue);
|
||||||
|
|
||||||
unsigned short getCamVideoFPS() const;
|
unsigned short getCamVideoFPS() const;
|
||||||
void setCamVideoFPS(unsigned short newValue);
|
void setCamVideoFPS(unsigned short newValue);
|
||||||
|
@ -447,7 +453,9 @@ private:
|
||||||
|
|
||||||
// Video
|
// Video
|
||||||
QString videoDev;
|
QString videoDev;
|
||||||
QSize camVideoRes;
|
QRect camVideoRes;
|
||||||
|
QRect screenRegion;
|
||||||
|
bool screenGrabbed;
|
||||||
unsigned short camVideoFPS;
|
unsigned short camVideoFPS;
|
||||||
|
|
||||||
struct friendProp
|
struct friendProp
|
||||||
|
|
|
@ -187,6 +187,7 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
|
||||||
IPin *pin;
|
IPin *pin;
|
||||||
if (devFilter->EnumPins(&pins) != S_OK)
|
if (devFilter->EnumPins(&pins) != S_OK)
|
||||||
return modes;
|
return modes;
|
||||||
|
|
||||||
while (pins->Next(1, &pin, nullptr) == S_OK)
|
while (pins->Next(1, &pin, nullptr) == S_OK)
|
||||||
{
|
{
|
||||||
IKsPropertySet *p = nullptr;
|
IKsPropertySet *p = nullptr;
|
||||||
|
@ -214,12 +215,14 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
|
||||||
goto next;
|
goto next;
|
||||||
if (config->GetNumberOfCapabilities(&n, &size) != S_OK)
|
if (config->GetNumberOfCapabilities(&n, &size) != S_OK)
|
||||||
goto pinend;
|
goto pinend;
|
||||||
|
|
||||||
assert(size == sizeof(VIDEO_STREAM_CONFIG_CAPS));
|
assert(size == sizeof(VIDEO_STREAM_CONFIG_CAPS));
|
||||||
vcaps = new VIDEO_STREAM_CONFIG_CAPS;
|
vcaps = new VIDEO_STREAM_CONFIG_CAPS;
|
||||||
|
|
||||||
for (int i=0; i<n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
AM_MEDIA_TYPE* type = nullptr;
|
AM_MEDIA_TYPE* type = nullptr;
|
||||||
|
VideoMode mode;
|
||||||
if (config->GetStreamCaps(i, &type, (BYTE*)vcaps) != S_OK)
|
if (config->GetStreamCaps(i, &type, (BYTE*)vcaps) != S_OK)
|
||||||
goto nextformat;
|
goto nextformat;
|
||||||
|
|
||||||
|
@ -227,7 +230,6 @@ QVector<VideoMode> DirectShow::getDeviceModes(QString devName)
|
||||||
&& !IsEqualGUID(type->formattype, FORMAT_VideoInfo2))
|
&& !IsEqualGUID(type->formattype, FORMAT_VideoInfo2))
|
||||||
goto nextformat;
|
goto nextformat;
|
||||||
|
|
||||||
VideoMode mode;
|
|
||||||
mode.width = vcaps->MaxOutputSize.cx;
|
mode.width = vcaps->MaxOutputSize.cx;
|
||||||
mode.height = vcaps->MaxOutputSize.cy;
|
mode.height = vcaps->MaxOutputSize.cy;
|
||||||
mode.FPS = 1e7 / vcaps->MinFrameInterval;
|
mode.FPS = 1e7 / vcaps->MinFrameInterval;
|
||||||
|
|
|
@ -73,7 +73,7 @@ CameraDevice* CameraDevice::open(QString devName, AVDictionary** options)
|
||||||
format = iformat;
|
format = iformat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avformat_open_input(&fctx, devName.toStdString().c_str(), format, options)<0)
|
if (avformat_open_input(&fctx, devName.toStdString().c_str(), format, options) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
// Fix avformat_find_stream_info hanging on garbage input
|
// Fix avformat_find_stream_info hanging on garbage input
|
||||||
|
@ -103,12 +103,6 @@ out:
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
CameraDevice* CameraDevice::open(QString devName)
|
|
||||||
{
|
|
||||||
VideoMode mode{0,0,0,0};
|
|
||||||
return open(devName, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
CameraDevice* CameraDevice::open(QString devName, VideoMode mode)
|
CameraDevice* CameraDevice::open(QString devName, VideoMode mode)
|
||||||
{
|
{
|
||||||
if (!getDefaultInputFormat())
|
if (!getDefaultInputFormat())
|
||||||
|
@ -149,26 +143,14 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode)
|
||||||
screen.setHeight((screen.height() * pixRatio)-2);
|
screen.setHeight((screen.height() * pixRatio)-2);
|
||||||
}
|
}
|
||||||
av_dict_set(&options, "video_size", QString("%1x%2").arg(screen.width()).arg(screen.height()).toStdString().c_str(), 0);
|
av_dict_set(&options, "video_size", QString("%1x%2").arg(screen.width()).arg(screen.height()).toStdString().c_str(), 0);
|
||||||
|
devName += QString("+%1,%2").arg(QString().setNum(mode.x), QString().setNum(mode.y));
|
||||||
|
|
||||||
|
int FPS = 5;
|
||||||
if (mode.FPS)
|
if (mode.FPS)
|
||||||
av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0);
|
FPS = mode.FPS;
|
||||||
else
|
|
||||||
av_dict_set(&options, "framerate", QString().setNum(5).toStdString().c_str(), 0);
|
av_dict_set(&options, "framerate", QString().setNum(FPS).toStdString().c_str(), 0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
else if (devName.startsWith("gdigrab#"))
|
|
||||||
{
|
|
||||||
av_dict_set(&options, "framerate", QString().setNum(5).toStdString().c_str(), 0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
else if (iformat->name == QString("dshow") && 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") && mode)
|
else if (iformat->name == QString("video4linux2,v4l2") && 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);
|
||||||
|
@ -180,6 +162,20 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
else if (devName.startsWith("gdigrab#"))
|
||||||
|
{
|
||||||
|
av_dict_set(&options, "framerate", QString().setNum(5).toStdString().c_str(), 0);
|
||||||
|
av_dict_set(&options, "offset_x", QString().setNum(mode.x).toStdString().c_str(), 0);
|
||||||
|
av_dict_set(&options, "offset_y", QString().setNum(mode.y).toStdString().c_str(), 0);
|
||||||
|
av_dict_set(&options, "video_size", QString("%1x%2").arg(mode.width).arg(mode.height).toStdString().c_str(), 0);
|
||||||
|
}
|
||||||
|
else if (iformat->name == QString("dshow") && 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_OSX
|
#ifdef Q_OS_OSX
|
||||||
else if (iformat->name == QString("avfoundation"))
|
else if (iformat->name == QString("avfoundation"))
|
||||||
{
|
{
|
||||||
|
@ -215,19 +211,15 @@ void CameraDevice::open()
|
||||||
|
|
||||||
bool CameraDevice::close()
|
bool CameraDevice::close()
|
||||||
{
|
{
|
||||||
if (--refcount <= 0)
|
if (--refcount > 0)
|
||||||
{
|
|
||||||
openDeviceLock.lock();
|
|
||||||
openDevices.remove(devName);
|
|
||||||
openDeviceLock.unlock();
|
|
||||||
avformat_close_input(&context);
|
|
||||||
delete this;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
openDeviceLock.lock();
|
||||||
|
openDevices.remove(devName);
|
||||||
|
openDeviceLock.unlock();
|
||||||
|
avformat_close_input(&context);
|
||||||
|
delete this;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QPair<QString, QString>> CameraDevice::getRawDeviceListGeneric()
|
QVector<QPair<QString, QString>> CameraDevice::getRawDeviceListGeneric()
|
||||||
|
@ -351,9 +343,33 @@ QString CameraDevice::getDefaultDeviceName()
|
||||||
return devlist[0].first;
|
return devlist[0].first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CameraDevice::isScreen(const QString &devName)
|
||||||
|
{
|
||||||
|
return devName.startsWith("x11grab") || devName.startsWith("gdigrab");
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<VideoMode> CameraDevice::getScreenModes()
|
||||||
|
{
|
||||||
|
QList<QScreen*> screens = QApplication::screens();
|
||||||
|
QVector<VideoMode> result;
|
||||||
|
|
||||||
|
std::for_each(screens.begin(), screens.end(), [&result](QScreen *s)
|
||||||
|
{
|
||||||
|
QRect rect = s->geometry();
|
||||||
|
QPoint p = rect.topLeft();
|
||||||
|
|
||||||
|
VideoMode mode(rect.width(), rect.height(), p.x(), p.y());
|
||||||
|
result.push_back(mode);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
QVector<VideoMode> CameraDevice::getVideoModes(QString devName)
|
QVector<VideoMode> CameraDevice::getVideoModes(QString devName)
|
||||||
{
|
{
|
||||||
if (!iformat);
|
if (!iformat);
|
||||||
|
else if (isScreen(devName))
|
||||||
|
return getScreenModes();
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
else if (iformat->name == QString("dshow"))
|
else if (iformat->name == QString("dshow"))
|
||||||
return DirectShow::getDeviceModes(devName);
|
return DirectShow::getDeviceModes(devName);
|
||||||
|
@ -417,6 +433,7 @@ bool CameraDevice::getDefaultInputFormat()
|
||||||
if ((iformat = av_find_input_format("dshow")))
|
if ((iformat = av_find_input_format("dshow")))
|
||||||
return true;
|
return true;
|
||||||
if ((iformat = av_find_input_format("vfwcap")))
|
if ((iformat = av_find_input_format("vfwcap")))
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Q_OS_OSX
|
#ifdef Q_OS_OSX
|
||||||
|
|
|
@ -41,15 +41,12 @@ struct AVDictionary;
|
||||||
class CameraDevice
|
class CameraDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Opens a device, creating a new one if needed
|
|
||||||
/// Returns a nullptr if the device couldn't be opened
|
|
||||||
static CameraDevice* open(QString devName);
|
|
||||||
/// Opens a device, creating a new one if needed
|
/// Opens a device, creating a new one if needed
|
||||||
/// If the device is alreay open in another mode, the mode
|
/// If the device is alreay open in another mode, the mode
|
||||||
/// will be ignored and the existing device is used
|
/// will be ignored and the existing device is used
|
||||||
/// If the mode does not exist, a new device can't be opened
|
/// If the mode does not exist, a new device can't be opened
|
||||||
/// Returns a nullptr if the device couldn't be opened
|
/// Returns a nullptr if the device couldn't be opened
|
||||||
static CameraDevice* open(QString devName, VideoMode mode);
|
static CameraDevice* open(QString devName, VideoMode mode = VideoMode());
|
||||||
void open(); ///< Opens the device again. Never fails
|
void open(); ///< Opens the device again. Never fails
|
||||||
bool close(); ///< Closes the device. Never fails. If returns true, "this" becomes invalid
|
bool close(); ///< Closes the device. Never fails. If returns true, "this" becomes invalid
|
||||||
|
|
||||||
|
@ -69,11 +66,15 @@ public:
|
||||||
/// or the system default.
|
/// or the system default.
|
||||||
static QString getDefaultDeviceName();
|
static QString getDefaultDeviceName();
|
||||||
|
|
||||||
|
/// Checks if a device name specifies a display
|
||||||
|
static bool isScreen(const QString &devName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CameraDevice(const QString &devName, AVFormatContext *context);
|
CameraDevice(const QString &devName, AVFormatContext *context);
|
||||||
static CameraDevice* open(QString devName, AVDictionary** options);
|
static CameraDevice* open(QString devName, AVDictionary** options);
|
||||||
static bool getDefaultInputFormat(); ///< Sets CameraDevice::iformat, returns success/failure
|
static bool getDefaultInputFormat(); ///< Sets CameraDevice::iformat, returns success/failure
|
||||||
static QVector<QPair<QString, QString> > getRawDeviceListGeneric(); ///< Uses avdevice_list_devices
|
static QVector<QPair<QString, QString> > getRawDeviceListGeneric(); ///< Uses avdevice_list_devices
|
||||||
|
static QVector<VideoMode> getScreenModes(); ///< Returns avaliable screen modes with offset
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const QString devName; ///< Short name of the device
|
const QString devName; ///< Short name of the device
|
||||||
|
|
|
@ -28,6 +28,7 @@ extern "C" {
|
||||||
#include <QtConcurrent/QtConcurrentRun>
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include "src/persistence/settings.h"
|
||||||
#include "camerasource.h"
|
#include "camerasource.h"
|
||||||
#include "cameradevice.h"
|
#include "cameradevice.h"
|
||||||
#include "videoframe.h"
|
#include "videoframe.h"
|
||||||
|
@ -35,7 +36,7 @@ extern "C" {
|
||||||
CameraSource* CameraSource::instance{nullptr};
|
CameraSource* CameraSource::instance{nullptr};
|
||||||
|
|
||||||
CameraSource::CameraSource()
|
CameraSource::CameraSource()
|
||||||
: deviceName{"none"}, device{nullptr}, mode(VideoMode{0,0,0,0}),
|
: deviceName{"none"}, device{nullptr}, mode(VideoMode()),
|
||||||
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 +68,15 @@ void CameraSource::open()
|
||||||
|
|
||||||
void CameraSource::open(const QString& deviceName)
|
void CameraSource::open(const QString& deviceName)
|
||||||
{
|
{
|
||||||
open(deviceName, VideoMode{0,0,0,0});
|
bool isScreen = CameraDevice::isScreen(deviceName);
|
||||||
|
VideoMode mode = VideoMode(Settings::getInstance().getScreenRegion());
|
||||||
|
if (!isScreen)
|
||||||
|
{
|
||||||
|
mode = VideoMode(Settings::getInstance().getCamVideoRes());
|
||||||
|
mode.FPS = Settings::getInstance().getCamVideoFPS();
|
||||||
|
}
|
||||||
|
|
||||||
|
open(deviceName, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CameraSource::open(const QString& DeviceName, VideoMode Mode)
|
void CameraSource::open(const QString& DeviceName, VideoMode Mode)
|
||||||
|
@ -206,7 +215,7 @@ void CameraSource::unsubscribe()
|
||||||
|
|
||||||
bool CameraSource::openDevice()
|
bool CameraSource::openDevice()
|
||||||
{
|
{
|
||||||
qDebug() << "Opening device "<<deviceName;
|
qDebug() << "Opening device " << deviceName;
|
||||||
|
|
||||||
if (device)
|
if (device)
|
||||||
{
|
{
|
||||||
|
@ -216,10 +225,8 @@ bool CameraSource::openDevice()
|
||||||
|
|
||||||
// We need to create a new CameraDevice
|
// We need to create a new CameraDevice
|
||||||
AVCodec* codec;
|
AVCodec* codec;
|
||||||
if (mode)
|
device = CameraDevice::open(deviceName, mode);
|
||||||
device = CameraDevice::open(deviceName, mode);
|
|
||||||
else
|
|
||||||
device = CameraDevice::open(deviceName);
|
|
||||||
if (!device)
|
if (!device)
|
||||||
{
|
{
|
||||||
qWarning() << "Failed to open device!";
|
qWarning() << "Failed to open device!";
|
||||||
|
@ -240,25 +247,36 @@ bool CameraSource::openDevice()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoStreamIndex == -1)
|
if (videoStreamIndex == -1)
|
||||||
|
{
|
||||||
|
qWarning() << "Video stream not found";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Get a pointer to the codec context for the video stream
|
// Get a pointer to the codec context for the video stream
|
||||||
cctxOrig = device->context->streams[videoStreamIndex]->codec;
|
cctxOrig = device->context->streams[videoStreamIndex]->codec;
|
||||||
codec = avcodec_find_decoder(cctxOrig->codec_id);
|
codec = avcodec_find_decoder(cctxOrig->codec_id);
|
||||||
if(!codec)
|
if(!codec)
|
||||||
|
{
|
||||||
|
qWarning() << "Codec not found";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy context, since we apparently aren't allowed to use the original
|
// Copy context, since we apparently aren't allowed to use the original
|
||||||
cctx = avcodec_alloc_context3(codec);
|
cctx = avcodec_alloc_context3(codec);
|
||||||
if(avcodec_copy_context(cctx, cctxOrig) != 0)
|
if(avcodec_copy_context(cctx, cctxOrig) != 0)
|
||||||
|
{
|
||||||
|
qWarning() << "Can't copy context";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
cctx->refcounted_frames = 1;
|
cctx->refcounted_frames = 1;
|
||||||
|
|
||||||
// Open codec
|
// Open codec
|
||||||
if(avcodec_open2(cctx, codec, nullptr)<0)
|
if(avcodec_open2(cctx, codec, nullptr)<0)
|
||||||
{
|
{
|
||||||
|
qWarning() << "Can't open codec";
|
||||||
avcodec_free_context(&cctx);
|
avcodec_free_context(&cctx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -288,6 +306,7 @@ void CameraSource::closeDevice()
|
||||||
std::shared_ptr<VideoFrame> vframe = freelist[i].lock();
|
std::shared_ptr<VideoFrame> vframe = freelist[i].lock();
|
||||||
if (!vframe)
|
if (!vframe)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
vframe->releaseFrame();
|
vframe->releaseFrame();
|
||||||
}
|
}
|
||||||
freelist.clear();
|
freelist.clear();
|
||||||
|
@ -311,14 +330,15 @@ void CameraSource::stream()
|
||||||
AVFrame* frame = av_frame_alloc();
|
AVFrame* frame = av_frame_alloc();
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
frame->opaque = nullptr;
|
frame->opaque = nullptr;
|
||||||
|
|
||||||
AVPacket packet;
|
AVPacket packet;
|
||||||
if (av_read_frame(device->context, &packet)<0)
|
if (av_read_frame(device->context, &packet) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only keep packets from the right stream;
|
// Only keep packets from the right stream;
|
||||||
if (packet.stream_index==videoStreamIndex)
|
if (packet.stream_index == videoStreamIndex)
|
||||||
{
|
{
|
||||||
// Decode video frame
|
// Decode video frame
|
||||||
int frameFinished;
|
int frameFinished;
|
||||||
|
@ -340,7 +360,8 @@ void CameraSource::stream()
|
||||||
av_packet_unref(&packet);
|
av_packet_unref(&packet);
|
||||||
};
|
};
|
||||||
|
|
||||||
forever {
|
forever
|
||||||
|
{
|
||||||
biglock.lock();
|
biglock.lock();
|
||||||
|
|
||||||
// When a thread makes device null, it releases it, so we acquire here
|
// When a thread makes device null, it releases it, so we acquire here
|
||||||
|
@ -357,6 +378,7 @@ void CameraSource::stream()
|
||||||
biglock.unlock();
|
biglock.unlock();
|
||||||
while (streamBlocker)
|
while (streamBlocker)
|
||||||
QThread::yieldCurrentThread();
|
QThread::yieldCurrentThread();
|
||||||
|
|
||||||
QThread::yieldCurrentThread();
|
QThread::yieldCurrentThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
along with qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavcodec/avcodec.h>
|
#include <libavcodec/avcodec.h>
|
||||||
#include <libavutil/imgutils.h>
|
#include <libavutil/imgutils.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "corevideosource.h"
|
#include "corevideosource.h"
|
||||||
#include "videoframe.h"
|
#include "videoframe.h"
|
||||||
|
|
||||||
|
@ -39,15 +39,13 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
|
||||||
QMutexLocker locker(&biglock);
|
QMutexLocker locker(&biglock);
|
||||||
|
|
||||||
std::shared_ptr<VideoFrame> vframe;
|
std::shared_ptr<VideoFrame> vframe;
|
||||||
AVFrame* avframe;
|
int width = vpxframe->d_w;
|
||||||
uint8_t* buf;
|
int height = vpxframe->d_h;
|
||||||
int width = vpxframe->d_w, height = vpxframe->d_h;
|
|
||||||
int dstStride, srcStride, minStride;
|
|
||||||
|
|
||||||
if (subscribers <= 0)
|
if (subscribers <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
avframe = av_frame_alloc();
|
AVFrame* avframe = av_frame_alloc();
|
||||||
if (!avframe)
|
if (!avframe)
|
||||||
return;
|
return;
|
||||||
avframe->width = width;
|
avframe->width = width;
|
||||||
|
@ -55,29 +53,35 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe)
|
||||||
avframe->format = AV_PIX_FMT_YUV420P;
|
avframe->format = AV_PIX_FMT_YUV420P;
|
||||||
|
|
||||||
int imgBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
|
int imgBufferSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1);
|
||||||
buf = (uint8_t*)av_malloc(imgBufferSize);
|
uint8_t* buf = (uint8_t*)av_malloc(imgBufferSize);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
{
|
{
|
||||||
av_frame_free(&avframe);
|
av_frame_free(&avframe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
avframe->opaque = buf;
|
|
||||||
|
|
||||||
uint8_t** data = avframe->data;
|
uint8_t** data = avframe->data;
|
||||||
int* linesize = avframe->linesize;
|
int* linesize = avframe->linesize;
|
||||||
av_image_fill_arrays(data, linesize, buf, AV_PIX_FMT_YUV420P, width, height, 1);
|
av_image_fill_arrays(data, linesize, buf, AV_PIX_FMT_YUV420P, width, height, 1);
|
||||||
|
|
||||||
dstStride=avframe->linesize[0], srcStride=vpxframe->stride[0], minStride=std::min(dstStride, srcStride);
|
for (int i = 0; i < 3; i++)
|
||||||
for (int i=0; i<height; i++)
|
{
|
||||||
memcpy(avframe->data[0]+dstStride*i, vpxframe->planes[0]+srcStride*i, minStride);
|
int dstStride = avframe->linesize[i];
|
||||||
dstStride=avframe->linesize[1], srcStride=vpxframe->stride[1], minStride=std::min(dstStride, srcStride);
|
int srcStride = vpxframe->stride[i];
|
||||||
for (int i=0; i<height/2; i++)
|
int minStride = std::min(dstStride, srcStride);
|
||||||
memcpy(avframe->data[1]+dstStride*i, vpxframe->planes[1]+srcStride*i, minStride);
|
int size = (i == 0) ? height : height / 2;
|
||||||
dstStride=avframe->linesize[2], srcStride=vpxframe->stride[2], minStride=std::min(dstStride, srcStride);
|
|
||||||
for (int i=0; i<height/2; i++)
|
for (int j = 0; j < size; j++)
|
||||||
memcpy(avframe->data[2]+dstStride*i, vpxframe->planes[2]+srcStride*i, minStride);
|
{
|
||||||
|
uint8_t *dst = avframe->data[i] + dstStride * j;
|
||||||
|
uint8_t *src = vpxframe->planes[i] + srcStride * j;
|
||||||
|
memcpy(dst, src, minStride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vframe = std::make_shared<VideoFrame>(avframe);
|
vframe = std::make_shared<VideoFrame>(avframe);
|
||||||
|
|
||||||
|
av_free(buf);
|
||||||
emit frameAvailable(vframe);
|
emit frameAvailable(vframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,12 +84,8 @@ NetCamView::NetCamView(int friendId, QWidget* parent)
|
||||||
videoSurface->setAvatar(pixmap);
|
videoSurface->setAvatar(pixmap);
|
||||||
});
|
});
|
||||||
|
|
||||||
VideoMode videoMode;
|
QRect videoSize = Settings::getInstance().getCamVideoRes();
|
||||||
QSize videoSize = Settings::getInstance().getCamVideoRes();
|
|
||||||
videoMode.width = videoSize.width();
|
|
||||||
videoMode.height = videoSize.height();
|
|
||||||
qDebug() << "SIZER" << videoSize;
|
qDebug() << "SIZER" << videoSize;
|
||||||
videoMode.FPS = Settings::getInstance().getCamVideoFPS();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetCamView::~NetCamView()
|
NetCamView::~NetCamView()
|
||||||
|
|
|
@ -90,25 +90,25 @@ QImage VideoFrame::toQImage(QSize size)
|
||||||
|
|
||||||
vpx_image *VideoFrame::toVpxImage()
|
vpx_image *VideoFrame::toVpxImage()
|
||||||
{
|
{
|
||||||
// libvpx doesn't provide a clean way to reuse an existing external buffer
|
vpx_image* img = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, width, height, 0);
|
||||||
// so we'll manually fill-in the vpx_image fields and hope for the best.
|
|
||||||
vpx_image* img = new vpx_image;
|
|
||||||
memset(img, 0, sizeof(vpx_image));
|
|
||||||
|
|
||||||
if (!convertToYUV420())
|
if (!convertToYUV420())
|
||||||
return img;
|
return img;
|
||||||
|
|
||||||
img->w = img->d_w = width;
|
for (int i = 0; i < 3; i++)
|
||||||
img->h = img->d_h = height;
|
{
|
||||||
img->fmt = VPX_IMG_FMT_I420;
|
int dstStride = img->stride[i];
|
||||||
img->planes[0] = frameYUV420->data[0];
|
int srcStride = frameYUV420->linesize[i];
|
||||||
img->planes[1] = frameYUV420->data[1];
|
int minStride = std::min(dstStride, srcStride);
|
||||||
img->planes[2] = frameYUV420->data[2];
|
int size = (i == 0) ? img->d_h : img->d_h / 2;
|
||||||
img->planes[3] = nullptr;
|
|
||||||
img->stride[0] = frameYUV420->linesize[0];
|
for (int j = 0; j < size; j++)
|
||||||
img->stride[1] = frameYUV420->linesize[1];
|
{
|
||||||
img->stride[2] = frameYUV420->linesize[2];
|
uint8_t *dst = img->planes[i] + dstStride * j;
|
||||||
img->stride[3] = frameYUV420->linesize[3];
|
uint8_t *src = frameYUV420->data[i] + srcStride * j;
|
||||||
|
memcpy(dst, src, minStride);
|
||||||
|
}
|
||||||
|
}
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,36 @@
|
||||||
#ifndef VIDEOMODE_H
|
#ifndef VIDEOMODE_H
|
||||||
#define VIDEOMODE_H
|
#define VIDEOMODE_H
|
||||||
|
|
||||||
|
#include <QRect>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
/// Describes a video mode supported by a device
|
/// Describes a video mode supported by a device
|
||||||
struct VideoMode
|
struct VideoMode
|
||||||
{
|
{
|
||||||
unsigned short width, height; ///< Displayed video resolution (NOT frame resolution)
|
unsigned short width, height; ///< Displayed video resolution (NOT frame resolution)
|
||||||
|
unsigned short x, y; ///< Coordinates of upper-left corner
|
||||||
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;
|
uint32_t pixel_format;
|
||||||
|
|
||||||
|
VideoMode(int width = 0, int height = 0, int x = 0, int y = 0,
|
||||||
|
int FPS = 0, int format = 0) :
|
||||||
|
width(width), height(height), x(x), y(y),
|
||||||
|
FPS(FPS), pixel_format(format)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoMode(QRect rect) :
|
||||||
|
width(rect.width()), height(rect.height()),
|
||||||
|
x(rect.x()), y(rect.y()),
|
||||||
|
FPS(0), pixel_format(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QRect toRect() const
|
||||||
|
{
|
||||||
|
return QRect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
/// All zeros means a default/unspecified mode
|
/// All zeros means a default/unspecified mode
|
||||||
operator bool() const
|
operator bool() const
|
||||||
{
|
{
|
||||||
|
@ -38,6 +61,8 @@ struct VideoMode
|
||||||
{
|
{
|
||||||
return width == other.width
|
return width == other.width
|
||||||
&& height == other.height
|
&& height == other.height
|
||||||
|
&& x == other.x
|
||||||
|
&& y == other.y
|
||||||
&& FPS == other.FPS
|
&& FPS == other.FPS
|
||||||
&& pixel_format == other.pixel_format;
|
&& pixel_format == other.pixel_format;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "src/video/cameradevice.h"
|
#include "src/video/cameradevice.h"
|
||||||
#include "src/video/videosurface.h"
|
#include "src/video/videosurface.h"
|
||||||
#include "src/widget/translator.h"
|
#include "src/widget/translator.h"
|
||||||
|
#include "src/widget/tool/screenshotgrabber.h"
|
||||||
#include "src/core/core.h"
|
#include "src/core/core.h"
|
||||||
#include "src/core/coreav.h"
|
#include "src/core/coreav.h"
|
||||||
|
|
||||||
|
@ -32,14 +33,15 @@
|
||||||
#include <QShowEvent>
|
#include <QShowEvent>
|
||||||
#include <map>
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AVForm::AVForm() :
|
AVForm::AVForm() :
|
||||||
GenericForm(QPixmap(":/img/settings/av.png"))
|
GenericForm(QPixmap(":/img/settings/av.png"))
|
||||||
, subscribedToAudioIn{false}
|
, subscribedToAudioIn(false)
|
||||||
, camVideoSurface{nullptr}
|
, camVideoSurface(nullptr)
|
||||||
, camera(CameraSource::getInstance())
|
, camera(CameraSource::getInstance())
|
||||||
{
|
{
|
||||||
bodyUI = new Ui::AVSettings;
|
bodyUI = new Ui::AVSettings;
|
||||||
|
@ -134,58 +136,80 @@ void AVForm::showEvent(QShowEvent* event)
|
||||||
GenericForm::showEvent(event);
|
GenericForm::showEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AVForm::open(const QString &devName, const VideoMode &mode)
|
||||||
|
{
|
||||||
|
QRect rect = mode.toRect();
|
||||||
|
Settings::getInstance().setCamVideoRes(rect);
|
||||||
|
Settings::getInstance().setCamVideoFPS(mode.FPS);
|
||||||
|
camera.open(devName, mode);
|
||||||
|
}
|
||||||
|
|
||||||
void AVForm::onVideoModesIndexChanged(int index)
|
void AVForm::onVideoModesIndexChanged(int index)
|
||||||
{
|
{
|
||||||
if (index<0 || index>=videoModes.size())
|
if (index < 0 || index >= videoModes.size())
|
||||||
{
|
{
|
||||||
qWarning() << "Invalid mode index";
|
qWarning() << "Invalid mode index";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int devIndex = bodyUI->videoDevCombobox->currentIndex();
|
int devIndex = bodyUI->videoDevCombobox->currentIndex();
|
||||||
if (devIndex<0 || devIndex>=videoModes.size())
|
if (devIndex < 0 || devIndex >= videoDeviceList.size())
|
||||||
{
|
{
|
||||||
qWarning() << "Invalid device index";
|
qWarning() << "Invalid device index";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString devName = videoDeviceList[devIndex].first;
|
QString devName = videoDeviceList[devIndex].first;
|
||||||
VideoMode mode = videoModes[index];
|
VideoMode mode = videoModes[index];
|
||||||
Settings::getInstance().setCamVideoRes(QSize(mode.width, mode.height));
|
|
||||||
Settings::getInstance().setCamVideoFPS(mode.FPS);
|
|
||||||
camera.open(devName, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AVForm::updateVideoModes(int curIndex)
|
if (CameraDevice::isScreen(devName) && mode == VideoMode())
|
||||||
{
|
|
||||||
if (curIndex<0 || curIndex>=videoDeviceList.size())
|
|
||||||
{
|
{
|
||||||
qWarning() << "Invalid index";
|
if (Settings::getInstance().getScreenGrabbed())
|
||||||
|
{
|
||||||
|
VideoMode mode(Settings::getInstance().getScreenRegion());
|
||||||
|
open(devName, mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreenshotGrabber* screenshotGrabber = new ScreenshotGrabber(this);
|
||||||
|
|
||||||
|
auto onGrabbed = [screenshotGrabber, devName, this] (QRect region)
|
||||||
|
{
|
||||||
|
VideoMode mode(region);
|
||||||
|
mode.width = mode.width / 2 * 2;
|
||||||
|
mode.height = mode.height / 2 * 2;
|
||||||
|
|
||||||
|
Settings::getInstance().setScreenRegion(mode.toRect());
|
||||||
|
Settings::getInstance().setScreenGrabbed(true);
|
||||||
|
|
||||||
|
open(devName, mode);
|
||||||
|
delete screenshotGrabber;
|
||||||
|
};
|
||||||
|
|
||||||
|
connect(screenshotGrabber, &ScreenshotGrabber::regionChosen, this, onGrabbed, Qt::QueuedConnection);
|
||||||
|
screenshotGrabber->showGrabber();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString devName = videoDeviceList[curIndex].first;
|
|
||||||
QVector<VideoMode> allVideoModes = CameraDevice::getVideoModes(devName);
|
|
||||||
std::sort(allVideoModes.begin(), allVideoModes.end(),
|
|
||||||
[](const VideoMode& a, const VideoMode& b)
|
|
||||||
{return a.width!=b.width ? a.width>b.width :
|
|
||||||
a.height!=b.height ? a.height>b.height :
|
|
||||||
a.FPS>b.FPS;});
|
|
||||||
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
|
||||||
bodyUI->videoModescomboBox->clear();
|
|
||||||
|
|
||||||
|
Settings::getInstance().setScreenGrabbed(false);
|
||||||
|
open(devName, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVForm::selectBestModes(QVector<VideoMode> &allVideoModes)
|
||||||
|
{
|
||||||
// Identify the best resolutions available for the supposed XXXXp resolutions.
|
// Identify the best resolutions available for the supposed XXXXp resolutions.
|
||||||
std::map<int, VideoMode> idealModes;
|
std::map<int, VideoMode> idealModes;
|
||||||
idealModes[120] = {160,120,0,0};
|
idealModes[120] = VideoMode(160, 120);
|
||||||
idealModes[240] = {460,240,0,0};
|
idealModes[240] = VideoMode(460, 240);
|
||||||
idealModes[360] = {640,360,0,0};
|
idealModes[360] = VideoMode(640, 360);
|
||||||
idealModes[480] = {854,480,0,0};
|
idealModes[480] = VideoMode(854, 480);
|
||||||
idealModes[720] = {1280,720,0,0};
|
idealModes[720] = VideoMode(1280, 720);
|
||||||
idealModes[1080] = {1920,1080,0,0};
|
idealModes[1080] = VideoMode(1920, 1080);
|
||||||
std::map<int, int> bestModeInds;
|
|
||||||
|
|
||||||
qDebug("available Modes:");
|
std::map<int, int> bestModeInds;
|
||||||
for (int i=0; i<allVideoModes.size(); ++i)
|
for (int i = 0; i < allVideoModes.size(); ++i)
|
||||||
{
|
{
|
||||||
VideoMode mode = allVideoModes[i];
|
VideoMode mode = allVideoModes[i];
|
||||||
qDebug("width: %d, height: %d, FPS: %f, pixel format: %s", mode.width, mode.height, mode.FPS, CameraDevice::getPixelFormatString(mode.pixel_format).toStdString().c_str());
|
QString pixelFormat = CameraDevice::getPixelFormatString(mode.pixel_format);
|
||||||
|
qDebug("width: %d, height: %d, FPS: %f, pixel format: %s", mode.width, mode.height, mode.FPS, pixelFormat.toStdString().c_str());
|
||||||
|
|
||||||
// PS3-Cam protection, everything above 60fps makes no sense
|
// PS3-Cam protection, everything above 60fps makes no sense
|
||||||
if(mode.FPS > 60)
|
if(mode.FPS > 60)
|
||||||
|
@ -205,120 +229,188 @@ void AVForm::updateVideoModes(int curIndex)
|
||||||
bestModeInds[res] = i;
|
bestModeInds[res] = i;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int ind = bestModeInds[res];
|
|
||||||
if (mode.norm(idealMode) < allVideoModes[ind].norm(idealMode))
|
int index = bestModeInds[res];
|
||||||
|
VideoMode best = allVideoModes[index];
|
||||||
|
if (mode.norm(idealMode) < best.norm(idealMode))
|
||||||
{
|
{
|
||||||
bestModeInds[res] = i;
|
bestModeInds[res] = i;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (mode.norm(idealMode) == allVideoModes[ind].norm(idealMode))
|
|
||||||
|
if (mode.norm(idealMode) == best.norm(idealMode))
|
||||||
{
|
{
|
||||||
// prefer higher FPS and "better" pixel formats
|
// prefer higher FPS and "better" pixel formats
|
||||||
if (mode.FPS > allVideoModes[ind].FPS)
|
if (mode.FPS > best.FPS)
|
||||||
{
|
{
|
||||||
bestModeInds[res] = i;
|
bestModeInds[res] = i;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (mode.FPS == allVideoModes[ind].FPS &&
|
|
||||||
CameraDevice::betterPixelFormat(mode.pixel_format, allVideoModes[ind].pixel_format))
|
bool better = CameraDevice::betterPixelFormat(mode.pixel_format, best.pixel_format);
|
||||||
{
|
if (mode.FPS == best.FPS && better)
|
||||||
bestModeInds[res] = i;
|
bestModeInds[res] = i;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug("selected Modes:");
|
|
||||||
int prefResIndex = -1;
|
QVector<VideoMode> newVideoModes;
|
||||||
QSize prefRes = Settings::getInstance().getCamVideoRes();
|
for (auto it = bestModeInds.rbegin(); it != bestModeInds.rend(); ++it)
|
||||||
unsigned short prefFPS = Settings::getInstance().getCamVideoFPS();
|
|
||||||
// Iterate backwards to show higest resolution first.
|
|
||||||
videoModes.clear();
|
|
||||||
for(auto iter = bestModeInds.rbegin(); iter != bestModeInds.rend(); ++iter)
|
|
||||||
{
|
{
|
||||||
int i = iter->second;
|
VideoMode mode = allVideoModes[it->second];
|
||||||
VideoMode mode = allVideoModes[i];
|
auto result = std::find(newVideoModes.begin(), newVideoModes.end(), mode);
|
||||||
|
if (result == newVideoModes.end())
|
||||||
|
newVideoModes.push_back(mode);
|
||||||
|
}
|
||||||
|
allVideoModes = newVideoModes;
|
||||||
|
}
|
||||||
|
|
||||||
if (videoModes.contains(mode))
|
void AVForm::fillCameraModesComboBox()
|
||||||
continue;
|
{
|
||||||
|
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
||||||
|
bodyUI->videoModescomboBox->clear();
|
||||||
|
|
||||||
|
for(int i = 0; i < videoModes.size(); i++)
|
||||||
|
{
|
||||||
|
VideoMode mode = videoModes[i];
|
||||||
|
|
||||||
videoModes.append(mode);
|
|
||||||
if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1)
|
|
||||||
prefResIndex = videoModes.size() - 1;
|
|
||||||
QString str;
|
QString str;
|
||||||
qDebug("width: %d, height: %d, FPS: %f, pixel format: %s\n", mode.width, mode.height, mode.FPS, CameraDevice::getPixelFormatString(mode.pixel_format).toStdString().c_str());
|
QString pixelFormat = CameraDevice::getPixelFormatString(mode.pixel_format);
|
||||||
|
qDebug("width: %d, height: %d, FPS: %f, pixel format: %s\n", mode.width, mode.height, mode.FPS, pixelFormat.toStdString().c_str());
|
||||||
|
|
||||||
if (mode.height && mode.width)
|
if (mode.height && mode.width)
|
||||||
str += tr("%1p").arg(iter->first);
|
str += QString("%1p").arg(mode.height);
|
||||||
else
|
else
|
||||||
str += tr("Default resolution");
|
str += tr("Default resolution");
|
||||||
|
|
||||||
bodyUI->videoModescomboBox->addItem(str);
|
bodyUI->videoModescomboBox->addItem(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoModes.isEmpty())
|
if (videoModes.isEmpty())
|
||||||
bodyUI->videoModescomboBox->addItem(tr("Default resolution"));
|
bodyUI->videoModescomboBox->addItem(tr("Default resolution"));
|
||||||
|
|
||||||
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
||||||
if (prefResIndex != -1)
|
}
|
||||||
|
|
||||||
|
int AVForm::searchPreferredIndex()
|
||||||
|
{
|
||||||
|
QRect prefRes = Settings::getInstance().getCamVideoRes();
|
||||||
|
unsigned short prefFPS = Settings::getInstance().getCamVideoFPS();
|
||||||
|
|
||||||
|
for (int i = 0; i < videoModes.size(); i++)
|
||||||
{
|
{
|
||||||
bodyUI->videoModescomboBox->setCurrentIndex(prefResIndex);
|
VideoMode mode = videoModes[i];
|
||||||
|
if (mode.width == prefRes.width()
|
||||||
|
&& mode.height == prefRes.height()
|
||||||
|
&& mode.FPS == prefFPS)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVForm::fillScreenModesComboBox()
|
||||||
|
{
|
||||||
|
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
||||||
|
bodyUI->videoModescomboBox->clear();
|
||||||
|
|
||||||
|
for(int i = 0; i < videoModes.size(); i++)
|
||||||
|
{
|
||||||
|
VideoMode mode = videoModes[i];
|
||||||
|
QString pixelFormat = CameraDevice::getPixelFormatString(mode.pixel_format);
|
||||||
|
qDebug("%dx%d+%d,%d FPS: %f, pixel format: %s\n", mode.width, mode.height, mode.x, mode.y, mode.FPS, pixelFormat.toStdString().c_str());
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
if (mode.width && mode.height)
|
||||||
|
name = QString("Screen %1").arg(i + 1);
|
||||||
|
else
|
||||||
|
name = tr("Select region");
|
||||||
|
|
||||||
|
bodyUI->videoModescomboBox->addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AVForm::updateVideoModes(int curIndex)
|
||||||
|
{
|
||||||
|
if (curIndex < 0 || curIndex >= videoDeviceList.size())
|
||||||
|
{
|
||||||
|
qWarning() << "Invalid index";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString devName = videoDeviceList[curIndex].first;
|
||||||
|
QVector<VideoMode> allVideoModes = CameraDevice::getVideoModes(devName);
|
||||||
|
|
||||||
|
qDebug("available Modes:");
|
||||||
|
bool isScreen = CameraDevice::isScreen(devName);
|
||||||
|
if (isScreen)
|
||||||
|
{
|
||||||
|
// Add extra video mode to region selection
|
||||||
|
allVideoModes.push_back(VideoMode());
|
||||||
|
videoModes = allVideoModes;
|
||||||
|
fillScreenModesComboBox();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// If the user hasn't set a preffered resolution yet,
|
selectBestModes(allVideoModes);
|
||||||
// we'll pick the resolution in the middle of the list,
|
videoModes = allVideoModes;
|
||||||
// and the best FPS for that resolution.
|
|
||||||
// If we picked the lowest resolution, the quality would be awful
|
|
||||||
// but if we picked the largest, FPS would be bad and thus quality bad too.
|
|
||||||
int numRes=0;
|
|
||||||
QSize lastSize;
|
|
||||||
for (int i=0; i<videoModes.size(); i++)
|
|
||||||
{
|
|
||||||
if (lastSize != QSize{videoModes[i].width, videoModes[i].height})
|
|
||||||
{
|
|
||||||
numRes++;
|
|
||||||
lastSize = {videoModes[i].width, videoModes[i].height};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int target = numRes/2;
|
|
||||||
numRes=0;
|
|
||||||
for (int i=0; i<videoModes.size(); i++)
|
|
||||||
{
|
|
||||||
if (lastSize != QSize{videoModes[i].width, videoModes[i].height})
|
|
||||||
{
|
|
||||||
numRes++;
|
|
||||||
lastSize = {videoModes[i].width, videoModes[i].height};
|
|
||||||
}
|
|
||||||
if (numRes==target)
|
|
||||||
{
|
|
||||||
bodyUI->videoModescomboBox->setCurrentIndex(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoModes.size())
|
qDebug("selected Modes:");
|
||||||
{
|
fillCameraModesComboBox();
|
||||||
bodyUI->videoModescomboBox->setUpdatesEnabled(false);
|
|
||||||
bodyUI->videoModescomboBox->setCurrentIndex(-1);
|
|
||||||
bodyUI->videoModescomboBox->setUpdatesEnabled(true);
|
|
||||||
bodyUI->videoModescomboBox->setCurrentIndex(0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We don't have any video modes, open it with the default mode
|
|
||||||
camera.open(devName);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int preferedIndex = searchPreferredIndex();
|
||||||
|
if (preferedIndex != -1)
|
||||||
|
{
|
||||||
|
bodyUI->videoModescomboBox->setCurrentIndex(preferedIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isScreen)
|
||||||
|
{
|
||||||
|
QRect rect = Settings::getInstance().getScreenRegion();
|
||||||
|
VideoMode mode(rect);
|
||||||
|
|
||||||
|
Settings::getInstance().setScreenGrabbed(true);
|
||||||
|
bodyUI->videoModescomboBox->setCurrentIndex(videoModes.size() - 1);
|
||||||
|
open(devName, mode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user hasn't set a preferred resolution yet,
|
||||||
|
// we'll pick the resolution in the middle of the list,
|
||||||
|
// and the best FPS for that resolution.
|
||||||
|
// If we picked the lowest resolution, the quality would be awful
|
||||||
|
// but if we picked the largest, FPS would be bad and thus quality bad too.
|
||||||
|
int mid = (videoModes.size() - 1) / 2;
|
||||||
|
bodyUI->videoModescomboBox->setCurrentIndex(mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AVForm::onVideoDevChanged(int index)
|
void AVForm::onVideoDevChanged(int index)
|
||||||
{
|
{
|
||||||
if (index<0 || index>=videoDeviceList.size())
|
if (index < 0 || index >= videoDeviceList.size())
|
||||||
{
|
{
|
||||||
qWarning() << "Invalid index";
|
qWarning() << "Invalid index";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings::getInstance().setScreenGrabbed(false);
|
||||||
QString dev = videoDeviceList[index].first;
|
QString dev = videoDeviceList[index].first;
|
||||||
Settings::getInstance().setVideoDev(dev);
|
Settings::getInstance().setVideoDev(dev);
|
||||||
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true);
|
||||||
updateVideoModes(index);
|
updateVideoModes(index);
|
||||||
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
bodyUI->videoModescomboBox->blockSignals(previouslyBlocked);
|
||||||
camera.open(dev);
|
|
||||||
|
if (Settings::getInstance().getScreenGrabbed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int modeIndex = bodyUI->videoModescomboBox->currentIndex();
|
||||||
|
VideoMode mode = VideoMode();
|
||||||
|
if (0 < modeIndex && modeIndex < videoModes.size())
|
||||||
|
mode = videoModes[modeIndex];
|
||||||
|
|
||||||
|
camera.open(dev, mode);
|
||||||
if (dev == "none")
|
if (dev == "none")
|
||||||
Core::getInstance()->getAv()->sendNoVideo();
|
Core::getInstance()->getAv()->sendNoVideo();
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,11 @@ private:
|
||||||
void getAudioOutDevices();
|
void getAudioOutDevices();
|
||||||
void getVideoDevices();
|
void getVideoDevices();
|
||||||
|
|
||||||
|
void selectBestModes(QVector<VideoMode> &allVideoModes);
|
||||||
|
void fillCameraModesComboBox();
|
||||||
|
void fillScreenModesComboBox();
|
||||||
|
int searchPreferredIndex();
|
||||||
|
|
||||||
void createVideoSurface();
|
void createVideoSurface();
|
||||||
void killVideoSurface();
|
void killVideoSurface();
|
||||||
|
|
||||||
|
@ -70,9 +75,9 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool eventFilter(QObject *o, QEvent *e) final override;
|
bool eventFilter(QObject *o, QEvent *e) final override;
|
||||||
|
|
||||||
void hideEvent(QHideEvent* event) final override;
|
void hideEvent(QHideEvent* event) final override;
|
||||||
void showEvent(QShowEvent*event) final override;
|
void showEvent(QShowEvent*event) final override;
|
||||||
|
void open(const QString &devName, const VideoMode &mode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::AVSettings *bodyUI;
|
Ui::AVSettings *bodyUI;
|
||||||
|
|
|
@ -131,6 +131,7 @@ void ScreenshotGrabber::acceptRegion()
|
||||||
if (rect.width() < 1 || rect.height() < 1)
|
if (rect.width() < 1 || rect.height() < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
emit regionChosen(rect);
|
||||||
qDebug() << "Screenshot accepted, chosen region" << rect;
|
qDebug() << "Screenshot accepted, chosen region" << rect;
|
||||||
QPixmap pixmap = this->screenGrab.copy(rect);
|
QPixmap pixmap = this->screenGrab.copy(rect);
|
||||||
this->window->close();
|
this->window->close();
|
||||||
|
|
|
@ -52,6 +52,7 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void screenshotTaken(const QPixmap &pixmap);
|
void screenshotTaken(const QPixmap &pixmap);
|
||||||
|
void regionChosen(QRect region);
|
||||||
void rejected();
|
void rejected();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user