From 6f3ef0cf59a9c6fc5da2c995a9a570b449691779 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Mon, 13 Jun 2016 19:15:35 +0300 Subject: [PATCH 01/12] refactor(avform): Extracted functions with best mode search and combo box filling --- src/widget/form/settings/avform.cpp | 187 +++++++++++++++++----------- src/widget/form/settings/avform.h | 4 +- 2 files changed, 118 insertions(+), 73 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 88f10277c..2667a1203 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -154,23 +154,8 @@ void AVForm::onVideoModesIndexChanged(int index) camera.open(devName, mode); } -void AVForm::updateVideoModes(int curIndex) +std::map AVForm::getBestModeInds(QVector &allVideoModes) { - if (curIndex<0 || curIndex>=videoDeviceList.size()) - { - qWarning() << "Invalid index"; - return; - } - QString devName = videoDeviceList[curIndex].first; - QVector 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(); - // Identify the best resolutions available for the supposed XXXXp resolutions. std::map idealModes; idealModes[120] = {160,120,0,0}; @@ -179,10 +164,9 @@ void AVForm::updateVideoModes(int curIndex) idealModes[480] = {854,480,0,0}; idealModes[720] = {1280,720,0,0}; idealModes[1080] = {1920,1080,0,0}; - std::map bestModeInds; - qDebug("available Modes:"); - for (int i=0; i bestModeInds; + for (int i = 0; i < allVideoModes.size(); ++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()); @@ -225,83 +209,142 @@ void AVForm::updateVideoModes(int curIndex) } } } - qDebug("selected Modes:"); + + QVector newVideoModes; + int index = 0; + for (auto it = bestModeInds.rbegin(); it != bestModeInds.rend(); ++it) + { + int i = it->second; + VideoMode mode = videoModes[i]; + auto result = std::find(newVideoModes.begin(), newVideoModes.end(), mode); + if (result == newVideoModes.end()) + newVideoModes.push_back(mode); + it->second = index++; + } + videoModes = newVideoModes; + + return bestModeInds; +} + +int AVForm::fillModesComboBox(std::map bestModeInds) +{ + bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); + bodyUI->videoModescomboBox->clear(); + int prefResIndex = -1; QSize prefRes = Settings::getInstance().getCamVideoRes(); 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[i]; + int index = iter->second; + VideoMode mode = videoModes[index]; - if (videoModes.contains(mode)) - continue; + if (mode.width == prefRes.width() + && mode.height == prefRes.height() + && mode.FPS == prefFPS + && prefResIndex == -1) + prefResIndex = index; - videoModes.append(mode); - if (mode.width==prefRes.width() && mode.height==prefRes.height() && mode.FPS == prefFPS && prefResIndex==-1) - prefResIndex = videoModes.size() - 1; 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) - str += tr("%1p").arg(iter->first); + str += QString("%1p").arg(iter->first); else str += tr("Default resolution"); + bodyUI->videoModescomboBox->addItem(str); } + if (videoModes.isEmpty()) bodyUI->videoModescomboBox->addItem(tr("Default resolution")); + bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); + return prefResIndex; +} + +void AVForm::updateVideoModes(int curIndex) +{ + if (curIndex<0 || curIndex>=videoDeviceList.size()) + { + qWarning() << "Invalid index"; + return; + } + QString devName = videoDeviceList[curIndex].first; + QVector 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;}); + + qDebug("available Modes:"); + std::map bestModeInds = getBestModeInds(allVideoModes); + videoModes = allVideoModes; + + qDebug("selected Modes:"); + int prefResIndex = fillModesComboBox(bestModeInds); if (prefResIndex != -1) { bodyUI->videoModescomboBox->setCurrentIndex(prefResIndex); + return; + } + + if (videoModes.size() == 0) + { + // We don't have any video modes, open it with the default mode + camera.open(devName); + 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 numRes=0; + QSize lastSize; + for (int i=0; ivideoModescomboBox->setCurrentIndex(i); + break; + } + } + + if (videoModes.size()) + { + bodyUI->videoModescomboBox->setUpdatesEnabled(false); + bodyUI->videoModescomboBox->setCurrentIndex(-1); + bodyUI->videoModescomboBox->setUpdatesEnabled(true); + bodyUI->videoModescomboBox->setCurrentIndex(0); } else { - // If the user hasn't set a preffered 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 numRes=0; - QSize lastSize; - for (int i=0; ivideoModescomboBox->setCurrentIndex(i); - break; - } - } - - if (videoModes.size()) - { - 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); - } + // We don't have any video modes, open it with the default mode + camera.open(devName); } } diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index e58d95812..22fcb1509 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -46,6 +46,9 @@ private: void getAudioOutDevices(); void getVideoDevices(); + std::map getBestModeInds(QVector &allVideoModes); + int fillModesComboBox(std::map bestModeInds); + void createVideoSurface(); void killVideoSurface(); @@ -70,7 +73,6 @@ protected: private: bool eventFilter(QObject *o, QEvent *e) final override; - void hideEvent(QHideEvent* event) final override; void showEvent(QShowEvent*event) final override; From 3f82396173a25bfdc25c81063a1a9f9e191248b1 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Mon, 13 Jun 2016 20:19:32 +0300 Subject: [PATCH 02/12] refactor(avform): Replace `bestModeInds` on videoMode index and video height as quality name --- src/widget/form/settings/avform.cpp | 60 ++++++++++++----------------- src/widget/form/settings/avform.h | 4 +- 2 files changed, 27 insertions(+), 37 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 2667a1203..58ce937fd 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -154,7 +154,7 @@ void AVForm::onVideoModesIndexChanged(int index) camera.open(devName, mode); } -std::map AVForm::getBestModeInds(QVector &allVideoModes) +void AVForm::selectBestModes(QVector &allVideoModes) { // Identify the best resolutions available for the supposed XXXXp resolutions. std::map idealModes; @@ -169,7 +169,8 @@ std::map AVForm::getBestModeInds(QVector &allVideoModes) for (int i = 0; i < allVideoModes.size(); ++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 if(mode.FPS > 60) @@ -189,44 +190,43 @@ std::map AVForm::getBestModeInds(QVector &allVideoModes) bestModeInds[res] = i; 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; + continue; } - else if (mode.norm(idealMode) == allVideoModes[ind].norm(idealMode)) + + if (mode.norm(idealMode) == best.norm(idealMode)) { // prefer higher FPS and "better" pixel formats - if (mode.FPS > allVideoModes[ind].FPS) + if (mode.FPS > best.FPS) { 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; - } } } } QVector newVideoModes; - int index = 0; for (auto it = bestModeInds.rbegin(); it != bestModeInds.rend(); ++it) { - int i = it->second; - VideoMode mode = videoModes[i]; + VideoMode mode = allVideoModes[it->second]; auto result = std::find(newVideoModes.begin(), newVideoModes.end(), mode); if (result == newVideoModes.end()) newVideoModes.push_back(mode); - it->second = index++; } - videoModes = newVideoModes; - - return bestModeInds; + allVideoModes = newVideoModes; } -int AVForm::fillModesComboBox(std::map bestModeInds) +int AVForm::fillModesComboBox() { bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); bodyUI->videoModescomboBox->clear(); @@ -235,25 +235,22 @@ int AVForm::fillModesComboBox(std::map bestModeInds) QSize prefRes = Settings::getInstance().getCamVideoRes(); unsigned short prefFPS = Settings::getInstance().getCamVideoFPS(); - // Iterate backwards to show higest resolution first. - videoModes.clear(); - for(auto iter = bestModeInds.rbegin(); iter != bestModeInds.rend(); ++iter) + for(int i = 0; i < videoModes.size(); i++) { - int index = iter->second; - VideoMode mode = videoModes[index]; + VideoMode mode = videoModes[i]; if (mode.width == prefRes.width() && mode.height == prefRes.height() && mode.FPS == prefFPS && prefResIndex == -1) - prefResIndex = index; + prefResIndex = i; QString 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) - str += QString("%1p").arg(iter->first); + str += QString("%1p").arg(mode.height); else str += tr("Default resolution"); @@ -269,7 +266,7 @@ int AVForm::fillModesComboBox(std::map bestModeInds) void AVForm::updateVideoModes(int curIndex) { - if (curIndex<0 || curIndex>=videoDeviceList.size()) + if (curIndex < 0 || curIndex >= videoDeviceList.size()) { qWarning() << "Invalid index"; return; @@ -277,18 +274,12 @@ void AVForm::updateVideoModes(int curIndex) QString devName = videoDeviceList[curIndex].first; QVector 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;}); - qDebug("available Modes:"); - std::map bestModeInds = getBestModeInds(allVideoModes); + selectBestModes(allVideoModes); videoModes = allVideoModes; qDebug("selected Modes:"); - int prefResIndex = fillModesComboBox(bestModeInds); + int prefResIndex = fillModesComboBox(); if (prefResIndex != -1) { bodyUI->videoModescomboBox->setCurrentIndex(prefResIndex); @@ -302,7 +293,6 @@ void AVForm::updateVideoModes(int curIndex) 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. diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 22fcb1509..fde7f9ee2 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -46,8 +46,8 @@ private: void getAudioOutDevices(); void getVideoDevices(); - std::map getBestModeInds(QVector &allVideoModes); - int fillModesComboBox(std::map bestModeInds); + void selectBestModes(QVector &allVideoModes); + int fillModesComboBox(); void createVideoSurface(); void killVideoSurface(); From 33729dcf4a523cb6f6eb3f551ec7e5c1f31e6033 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Mon, 13 Jun 2016 23:22:36 +0300 Subject: [PATCH 03/12] refactor(avform): Separeted search of preferred index in function --- src/widget/form/settings/avform.cpp | 45 +++++++++++++++-------------- src/widget/form/settings/avform.h | 3 +- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 58ce937fd..d1e310e37 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -226,25 +226,15 @@ void AVForm::selectBestModes(QVector &allVideoModes) allVideoModes = newVideoModes; } -int AVForm::fillModesComboBox() +void AVForm::fillModesComboBox() { bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); bodyUI->videoModescomboBox->clear(); - int prefResIndex = -1; - QSize prefRes = Settings::getInstance().getCamVideoRes(); - unsigned short prefFPS = Settings::getInstance().getCamVideoFPS(); - for(int i = 0; i < videoModes.size(); i++) { VideoMode mode = videoModes[i]; - if (mode.width == prefRes.width() - && mode.height == prefRes.height() - && mode.FPS == prefFPS - && prefResIndex == -1) - prefResIndex = i; - QString 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()); @@ -261,7 +251,23 @@ int AVForm::fillModesComboBox() bodyUI->videoModescomboBox->addItem(tr("Default resolution")); bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); - return prefResIndex; +} + +int AVForm::searchPreferredIndex() +{ + QSize prefRes = Settings::getInstance().getCamVideoRes(); + unsigned short prefFPS = Settings::getInstance().getCamVideoFPS(); + + for (int i = 0; i < videoModes.size(); i++) + { + VideoMode mode = videoModes[i]; + if (mode.width == prefRes.width() + && mode.height == prefRes.height() + && mode.FPS == prefFPS) + return i; + } + + return -1; } void AVForm::updateVideoModes(int curIndex) @@ -279,17 +285,12 @@ void AVForm::updateVideoModes(int curIndex) videoModes = allVideoModes; qDebug("selected Modes:"); - int prefResIndex = fillModesComboBox(); - if (prefResIndex != -1) - { - bodyUI->videoModescomboBox->setCurrentIndex(prefResIndex); - return; - } + fillModesComboBox(); - if (videoModes.size() == 0) + int preferedIndex = searchPreferredIndex(); + if (preferedIndex!= -1) { - // We don't have any video modes, open it with the default mode - camera.open(devName); + bodyUI->videoModescomboBox->setCurrentIndex(preferedIndex); return; } @@ -300,7 +301,7 @@ void AVForm::updateVideoModes(int curIndex) // 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 &allVideoModes); - int fillModesComboBox(); + void fillModesComboBox(); + int searchPreferredIndex(); void createVideoSurface(); void killVideoSurface(); From 2d861ee25b2f6ac5607005ea89f6866d7321e66d Mon Sep 17 00:00:00 2001 From: Diadlo Date: Tue, 14 Jun 2016 00:04:30 +0300 Subject: [PATCH 04/12] fix(avform): Took default resolution from middle of list --- src/widget/form/settings/avform.cpp | 48 ++++++----------------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index d1e310e37..10f954717 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -299,44 +299,8 @@ void AVForm::updateVideoModes(int curIndex) // 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; ivideoModescomboBox->setCurrentIndex(i); - break; - } - } - - if (videoModes.size()) - { - 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 mid = videoModes.size() / 2; + bodyUI->videoModescomboBox->setCurrentIndex(mid); } void AVForm::onVideoDevChanged(int index) @@ -352,7 +316,13 @@ void AVForm::onVideoDevChanged(int index) bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); updateVideoModes(index); bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); - camera.open(dev); + + int modeIndex = bodyUI->videoModescomboBox->currentIndex(); + VideoMode mode = VideoMode(); + if (0 < modeIndex || modeIndex < videoModes.size()) + mode = videoModes[modeIndex]; + + camera.open(dev, mode); if (dev == "none") Core::getInstance()->getAv()->sendNoVideo(); } From fd701df1012763cba98bbfbbf7bf9ccd898f1c03 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Sat, 18 Jun 2016 22:44:31 +0300 Subject: [PATCH 05/12] feat(videomode): Added possible video shift --- src/persistence/settings.cpp | 6 +++--- src/persistence/settings.h | 6 +++--- src/video/cameradevice.cpp | 4 ++-- src/video/camerasource.cpp | 33 ++++++++++++++++++++--------- src/video/netcamview.cpp | 6 +----- src/video/videomode.h | 25 ++++++++++++++++++++++ src/widget/form/settings/avform.cpp | 18 +++++++++------- 7 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 594fadc8a..437e83084 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -242,7 +242,7 @@ void Settings::loadGlobal() s.beginGroup("Video"); videoDev = s.value("videoDev", "").toString(); - camVideoRes = s.value("camVideoRes",QSize()).toSize(); + camVideoRes = s.value("camVideoRes", QRect()).toRect(); camVideoFPS = s.value("camVideoFPS", 0).toUInt(); s.endGroup(); @@ -1412,13 +1412,13 @@ void Settings::setOutVolume(int volume) outVolume = volume; } -QSize Settings::getCamVideoRes() const +QRect Settings::getCamVideoRes() const { QMutexLocker locker{&bigLock}; return camVideoRes; } -void Settings::setCamVideoRes(QSize newValue) +void Settings::setCamVideoRes(QRect newValue) { QMutexLocker locker{&bigLock}; camVideoRes = newValue; diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 15af3ae08..a96290ee8 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -190,8 +190,8 @@ public: QString getVideoDev() const; void setVideoDev(const QString& deviceSpecifier); - QSize getCamVideoRes() const; - void setCamVideoRes(QSize newValue); + QRect getCamVideoRes() const; + void setCamVideoRes(QRect newValue); unsigned short getCamVideoFPS() const; void setCamVideoFPS(unsigned short newValue); @@ -434,7 +434,7 @@ private: // Video QString videoDev; - QSize camVideoRes; + QRect camVideoRes; unsigned short camVideoFPS; struct friendProp diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index ba0a7adc4..1076d4b20 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -73,7 +73,7 @@ CameraDevice* CameraDevice::open(QString devName, AVDictionary** options) 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; // Fix avformat_find_stream_info hanging on garbage input @@ -105,7 +105,7 @@ out: CameraDevice* CameraDevice::open(QString devName) { - VideoMode mode{0,0,0,0}; + VideoMode mode = VideoMode(); return open(devName, mode); } diff --git a/src/video/camerasource.cpp b/src/video/camerasource.cpp index bfb9646c1..7400234e3 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,0}), + : deviceName{"none"}, device{nullptr}, mode(VideoMode()), 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,0}); + open(deviceName, VideoMode()); } void CameraSource::open(const QString& DeviceName, VideoMode Mode) @@ -206,7 +206,7 @@ void CameraSource::unsubscribe() bool CameraSource::openDevice() { - qDebug() << "Opening device "<context->streams[videoStreamIndex]->codec; codec = avcodec_find_decoder(cctxOrig->codec_id); if(!codec) + { + qWarning() << "Codec not found"; return false; + } // Copy context, since we apparently aren't allowed to use the original cctx = avcodec_alloc_context3(codec); if(avcodec_copy_context(cctx, cctxOrig) != 0) + { + qWarning() << "Can't copy context"; return false; + } cctx->refcounted_frames = 1; // Open codec if(avcodec_open2(cctx, codec, nullptr)<0) { + qWarning() << "Can't open codec"; avcodec_free_context(&cctx); return false; } @@ -288,6 +297,7 @@ void CameraSource::closeDevice() std::shared_ptr vframe = freelist[i].lock(); if (!vframe) continue; + vframe->releaseFrame(); } freelist.clear(); @@ -311,14 +321,15 @@ void CameraSource::stream() AVFrame* frame = av_frame_alloc(); if (!frame) return; + frame->opaque = nullptr; AVPacket packet; - if (av_read_frame(device->context, &packet)<0) + if (av_read_frame(device->context, &packet) < 0) return; // Only keep packets from the right stream; - if (packet.stream_index==videoStreamIndex) + if (packet.stream_index == videoStreamIndex) { // Decode video frame int frameFinished; @@ -340,7 +351,8 @@ void CameraSource::stream() av_packet_unref(&packet); }; - forever { + forever + { biglock.lock(); // When a thread makes device null, it releases it, so we acquire here @@ -357,6 +369,7 @@ void CameraSource::stream() biglock.unlock(); while (streamBlocker) QThread::yieldCurrentThread(); + QThread::yieldCurrentThread(); } } diff --git a/src/video/netcamview.cpp b/src/video/netcamview.cpp index 997bbfe0a..74dd0bde1 100644 --- a/src/video/netcamview.cpp +++ b/src/video/netcamview.cpp @@ -84,12 +84,8 @@ NetCamView::NetCamView(int friendId, QWidget* parent) videoSurface->setAvatar(pixmap); }); - VideoMode videoMode; - QSize videoSize = Settings::getInstance().getCamVideoRes(); - videoMode.width = videoSize.width(); - videoMode.height = videoSize.height(); + QRect videoSize = Settings::getInstance().getCamVideoRes(); qDebug() << "SIZER" << videoSize; - videoMode.FPS = Settings::getInstance().getCamVideoFPS(); } NetCamView::~NetCamView() diff --git a/src/video/videomode.h b/src/video/videomode.h index 134650af5..0fc4fb05d 100644 --- a/src/video/videomode.h +++ b/src/video/videomode.h @@ -21,13 +21,36 @@ #ifndef VIDEOMODE_H #define VIDEOMODE_H +#include +#include + /// Describes a video mode supported by a device struct VideoMode { 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 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 operator bool() const { @@ -38,6 +61,8 @@ struct VideoMode { return width == other.width && height == other.height + && x == other.x + && y == other.y && 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 10f954717..1ff82de6d 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -149,7 +149,9 @@ void AVForm::onVideoModesIndexChanged(int index) } QString devName = videoDeviceList[devIndex].first; VideoMode mode = videoModes[index]; - Settings::getInstance().setCamVideoRes(QSize(mode.width, mode.height)); + + QRect rect(mode.x, mode.y, mode.width, mode.height); + Settings::getInstance().setCamVideoRes(rect); Settings::getInstance().setCamVideoFPS(mode.FPS); camera.open(devName, mode); } @@ -158,12 +160,12 @@ void AVForm::selectBestModes(QVector &allVideoModes) { // Identify the best resolutions available for the supposed XXXXp resolutions. std::map idealModes; - idealModes[120] = {160,120,0,0}; - 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}; + idealModes[120] = VideoMode(160, 120); + idealModes[240] = VideoMode(460, 240); + idealModes[360] = VideoMode(640, 360); + idealModes[480] = VideoMode(854, 480); + idealModes[720] = VideoMode(1280, 720); + idealModes[1080] = VideoMode(1920, 1080); std::map bestModeInds; for (int i = 0; i < allVideoModes.size(); ++i) @@ -255,7 +257,7 @@ void AVForm::fillModesComboBox() int AVForm::searchPreferredIndex() { - QSize prefRes = Settings::getInstance().getCamVideoRes(); + QRect prefRes = Settings::getInstance().getCamVideoRes(); unsigned short prefFPS = Settings::getInstance().getCamVideoFPS(); for (int i = 0; i < videoModes.size(); i++) From d781a4f762a75a5766d9ca534ef0f034bf332ea0 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Wed, 15 Jun 2016 02:04:39 +0300 Subject: [PATCH 06/12] feat(cameradevice, avform): Added ability of screen selection --- src/video/cameradevice.cpp | 89 +++++++++++++++++------------ src/video/cameradevice.h | 9 +-- src/widget/form/settings/avform.cpp | 46 +++++++++++---- src/widget/form/settings/avform.h | 3 +- 4 files changed, 96 insertions(+), 51 deletions(-) diff --git a/src/video/cameradevice.cpp b/src/video/cameradevice.cpp index 1076d4b20..6a9c2c92c 100644 --- a/src/video/cameradevice.cpp +++ b/src/video/cameradevice.cpp @@ -103,12 +103,6 @@ out: return dev; } -CameraDevice* CameraDevice::open(QString devName) -{ - VideoMode mode = VideoMode(); - return open(devName, mode); -} - CameraDevice* CameraDevice::open(QString devName, VideoMode mode) { if (!getDefaultInputFormat()) @@ -149,26 +143,14 @@ CameraDevice* CameraDevice::open(QString devName, VideoMode mode) 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); + devName += QString("+%1,%2").arg(QString().setNum(mode.x), QString().setNum(mode.y)); + + int FPS = 5; if (mode.FPS) - av_dict_set(&options, "framerate", QString().setNum(mode.FPS).toStdString().c_str(), 0); - else - av_dict_set(&options, "framerate", QString().setNum(5).toStdString().c_str(), 0); + FPS = mode.FPS; + + 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) { 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 +#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 else if (iformat->name == QString("avfoundation")) { @@ -215,19 +211,15 @@ void CameraDevice::open() bool CameraDevice::close() { - if (--refcount <= 0) - { - openDeviceLock.lock(); - openDevices.remove(devName); - openDeviceLock.unlock(); - avformat_close_input(&context); - delete this; - return true; - } - else - { + if (--refcount > 0) return false; - } + + openDeviceLock.lock(); + openDevices.remove(devName); + openDeviceLock.unlock(); + avformat_close_input(&context); + delete this; + return true; } QVector> CameraDevice::getRawDeviceListGeneric() @@ -351,9 +343,33 @@ QString CameraDevice::getDefaultDeviceName() return devlist[0].first; } +bool CameraDevice::isScreen(const QString &devName) +{ + return devName.startsWith("x11grab") || devName.startsWith("gdigrab"); +} + +QVector CameraDevice::getScreenModes() +{ + QList screens = QApplication::screens(); + QVector 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 CameraDevice::getVideoModes(QString devName) { if (!iformat); + else if (isScreen(devName)) + return getScreenModes(); #ifdef Q_OS_WIN else if (iformat->name == QString("dshow")) return DirectShow::getDeviceModes(devName); @@ -417,6 +433,7 @@ bool CameraDevice::getDefaultInputFormat() if ((iformat = av_find_input_format("dshow"))) return true; if ((iformat = av_find_input_format("vfwcap"))) + return true; #endif #ifdef Q_OS_OSX diff --git a/src/video/cameradevice.h b/src/video/cameradevice.h index e6f304e35..48981858d 100644 --- a/src/video/cameradevice.h +++ b/src/video/cameradevice.h @@ -41,15 +41,12 @@ struct AVDictionary; class CameraDevice { 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 /// If the device is alreay open in another mode, the mode /// will be ignored and the existing device is used /// If the mode does not exist, a new device can'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 bool close(); ///< Closes the device. Never fails. If returns true, "this" becomes invalid @@ -69,11 +66,15 @@ public: /// or the system default. static QString getDefaultDeviceName(); + /// Checks if a device name specifies a display + static bool isScreen(const QString &devName); + private: CameraDevice(const QString &devName, AVFormatContext *context); static CameraDevice* open(QString devName, AVDictionary** options); static bool getDefaultInputFormat(); ///< Sets CameraDevice::iformat, returns success/failure static QVector > getRawDeviceListGeneric(); ///< Uses avdevice_list_devices + static QVector getScreenModes(); ///< Returns avaliable screen modes with offset public: const QString devName; ///< Short name of the device diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 1ff82de6d..f47e8a8bd 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -136,13 +136,13 @@ void AVForm::showEvent(QShowEvent* event) void AVForm::onVideoModesIndexChanged(int index) { - if (index<0 || index>=videoModes.size()) + if (index < 0 || index >= videoModes.size()) { qWarning() << "Invalid mode index"; return; } int devIndex = bodyUI->videoDevCombobox->currentIndex(); - if (devIndex<0 || devIndex>=videoModes.size()) + if (devIndex < 0 || devIndex >= videoDeviceList.size()) { qWarning() << "Invalid device index"; return; @@ -150,8 +150,7 @@ void AVForm::onVideoModesIndexChanged(int index) QString devName = videoDeviceList[devIndex].first; VideoMode mode = videoModes[index]; - QRect rect(mode.x, mode.y, mode.width, mode.height); - Settings::getInstance().setCamVideoRes(rect); + Settings::getInstance().setCamVideoRes(mode.toRect()); Settings::getInstance().setCamVideoFPS(mode.FPS); camera.open(devName, mode); } @@ -228,7 +227,7 @@ void AVForm::selectBestModes(QVector &allVideoModes) allVideoModes = newVideoModes; } -void AVForm::fillModesComboBox() +void AVForm::fillCameraModesComboBox() { bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); bodyUI->videoModescomboBox->clear(); @@ -272,6 +271,25 @@ int AVForm::searchPreferredIndex() 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 = QString("Screen %1").arg(i + 1); + bodyUI->videoModescomboBox->addItem(name); + } + + bodyUI->videoModescomboBox->addItem(tr("Select region")); + bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); +} + void AVForm::updateVideoModes(int curIndex) { if (curIndex < 0 || curIndex >= videoDeviceList.size()) @@ -283,11 +301,19 @@ void AVForm::updateVideoModes(int curIndex) QVector allVideoModes = CameraDevice::getVideoModes(devName); qDebug("available Modes:"); - selectBestModes(allVideoModes); - videoModes = allVideoModes; + if (CameraDevice::isScreen(devName)) + { + videoModes = allVideoModes; + fillScreenModesComboBox(); + } + else + { + selectBestModes(allVideoModes); + videoModes = allVideoModes; - qDebug("selected Modes:"); - fillModesComboBox(); + qDebug("selected Modes:"); + fillCameraModesComboBox(); + } int preferedIndex = searchPreferredIndex(); if (preferedIndex!= -1) @@ -307,7 +333,7 @@ void AVForm::updateVideoModes(int curIndex) void AVForm::onVideoDevChanged(int index) { - if (index<0 || index>=videoDeviceList.size()) + if (index < 0 || index >= videoDeviceList.size()) { qWarning() << "Invalid index"; return; diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index cb9cd7f92..1c9869308 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -47,7 +47,8 @@ private: void getVideoDevices(); void selectBestModes(QVector &allVideoModes); - void fillModesComboBox(); + void fillCameraModesComboBox(); + void fillScreenModesComboBox(); int searchPreferredIndex(); void createVideoSurface(); From 9cfd678c262b223413dab30d656aff50ae7ce470 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Wed, 15 Jun 2016 03:11:02 +0300 Subject: [PATCH 07/12] feat(avform, screenshotgrabber): Added custom screen region selection --- src/widget/form/settings/avform.cpp | 31 +++++++++++++++++++++++++-- src/widget/tool/screenshotgrabber.cpp | 1 + src/widget/tool/screenshotgrabber.h | 1 + 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index f47e8a8bd..3f9422d8f 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -25,6 +25,7 @@ #include "src/video/cameradevice.h" #include "src/video/videosurface.h" #include "src/widget/translator.h" +#include "src/widget/tool/screenshotgrabber.h" #include "src/core/core.h" #include "src/core/coreav.h" @@ -32,6 +33,7 @@ #include #include + #ifndef ALC_ALL_DEVICES_SPECIFIER #define ALC_ALL_DEVICES_SPECIFIER ALC_DEVICE_SPECIFIER #endif @@ -150,6 +152,25 @@ void AVForm::onVideoModesIndexChanged(int index) QString devName = videoDeviceList[devIndex].first; VideoMode mode = videoModes[index]; + if (CameraDevice::isScreen(devName) && !mode.height && !mode.width) + { + 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; + camera.open(devName, mode); + delete screenshotGrabber; + }; + + connect(screenshotGrabber, &ScreenshotGrabber::regionChosen, this, onGrabbed, Qt::QueuedConnection); + + screenshotGrabber->showGrabber(); + return; + } + Settings::getInstance().setCamVideoRes(mode.toRect()); Settings::getInstance().setCamVideoFPS(mode.FPS); camera.open(devName, mode); @@ -282,11 +303,15 @@ void AVForm::fillScreenModesComboBox() 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 = QString("Screen %1").arg(i + 1); + 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->addItem(tr("Select region")); bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); } @@ -303,6 +328,8 @@ void AVForm::updateVideoModes(int curIndex) qDebug("available Modes:"); if (CameraDevice::isScreen(devName)) { + // Add extra video mode to region selection + allVideoModes.push_back(VideoMode()); videoModes = allVideoModes; fillScreenModesComboBox(); } diff --git a/src/widget/tool/screenshotgrabber.cpp b/src/widget/tool/screenshotgrabber.cpp index 22b26329a..56e16901f 100644 --- a/src/widget/tool/screenshotgrabber.cpp +++ b/src/widget/tool/screenshotgrabber.cpp @@ -131,6 +131,7 @@ void ScreenshotGrabber::acceptRegion() if (rect.width() < 1 || rect.height() < 1) return; + emit regionChosen(rect); qDebug() << "Screenshot accepted, chosen region" << rect; emit screenshotTaken(this->screenGrab.copy(rect)); this->window->close(); diff --git a/src/widget/tool/screenshotgrabber.h b/src/widget/tool/screenshotgrabber.h index 0a0a36b62..e983aba13 100644 --- a/src/widget/tool/screenshotgrabber.h +++ b/src/widget/tool/screenshotgrabber.h @@ -52,6 +52,7 @@ public slots: signals: void screenshotTaken(const QPixmap &pixmap); + void regionChosen(QRect region); void rejected(); private: From ef641ce6d3398792c10b30bf24a81c5a6005fe06 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Thu, 16 Jun 2016 12:23:01 +0300 Subject: [PATCH 08/12] style(corevideosource): Small style fixes --- src/video/corevideosource.cpp | 38 +++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/video/corevideosource.cpp b/src/video/corevideosource.cpp index 0e76df947..cac6ce382 100644 --- a/src/video/corevideosource.cpp +++ b/src/video/corevideosource.cpp @@ -17,11 +17,11 @@ along with qTox. If not, see . */ - extern "C" { #include #include } + #include "corevideosource.h" #include "videoframe.h" @@ -39,15 +39,13 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe) QMutexLocker locker(&biglock); std::shared_ptr vframe; - AVFrame* avframe; - uint8_t* buf; - int width = vpxframe->d_w, height = vpxframe->d_h; - int dstStride, srcStride, minStride; + int width = vpxframe->d_w; + int height = vpxframe->d_h; if (subscribers <= 0) return; - avframe = av_frame_alloc(); + AVFrame* avframe = av_frame_alloc(); if (!avframe) return; avframe->width = width; @@ -55,29 +53,35 @@ void CoreVideoSource::pushFrame(const vpx_image_t* vpxframe) avframe->format = AV_PIX_FMT_YUV420P; 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) { av_frame_free(&avframe); return; } - avframe->opaque = buf; uint8_t** data = avframe->data; int* linesize = avframe->linesize; 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; idata[0]+dstStride*i, vpxframe->planes[0]+srcStride*i, minStride); - dstStride=avframe->linesize[1], srcStride=vpxframe->stride[1], minStride=std::min(dstStride, srcStride); - for (int i=0; idata[1]+dstStride*i, vpxframe->planes[1]+srcStride*i, minStride); - dstStride=avframe->linesize[2], srcStride=vpxframe->stride[2], minStride=std::min(dstStride, srcStride); - for (int i=0; idata[2]+dstStride*i, vpxframe->planes[2]+srcStride*i, minStride); + for (int i = 0; i < 3; i++) + { + int dstStride = avframe->linesize[i]; + int srcStride = vpxframe->stride[i]; + int minStride = std::min(dstStride, srcStride); + int size = (i == 0) ? height : height / 2; + + for (int j = 0; j < size; j++) + { + uint8_t *dst = avframe->data[i] + dstStride * j; + uint8_t *src = vpxframe->planes[i] + srcStride * j; + memcpy(dst, src, minStride); + } + } vframe = std::make_shared(avframe); + + av_free(buf); emit frameAvailable(vframe); } From 1ddc1371a0ea12de9621bd387b633ee8cdd575b3 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Thu, 16 Jun 2016 12:25:11 +0300 Subject: [PATCH 09/12] fix(videoframe): Added correct image copy --- src/core/coreav.cpp | 4 ++-- src/video/videoframe.cpp | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/coreav.cpp b/src/core/coreav.cpp index 691c58796..529174f8b 100644 --- a/src/core/coreav.cpp +++ b/src/core/coreav.cpp @@ -295,7 +295,7 @@ void CoreAV::sendCallVideo(uint32_t callId, shared_ptr vframe) if (frame->fmt == VPX_IMG_FMT_NONE) { qWarning() << "Invalid frame"; - delete frame; + vpx_img_free(frame); return; } @@ -321,7 +321,7 @@ void CoreAV::sendCallVideo(uint32_t callId, shared_ptr vframe) if (err == TOXAV_ERR_SEND_FRAME_SYNC) qDebug() << "toxav_video_send_frame error: Lock busy, dropping frame"; - delete frame; + vpx_img_free(frame); } void CoreAV::micMuteToggle(uint32_t callId) diff --git a/src/video/videoframe.cpp b/src/video/videoframe.cpp index 72ef4f5b4..4845a5264 100644 --- a/src/video/videoframe.cpp +++ b/src/video/videoframe.cpp @@ -90,25 +90,25 @@ QImage VideoFrame::toQImage(QSize size) vpx_image *VideoFrame::toVpxImage() { - // libvpx doesn't provide a clean way to reuse an existing external buffer - // 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)); + vpx_image* img = vpx_img_alloc(nullptr, VPX_IMG_FMT_I420, width, height, 0); if (!convertToYUV420()) return img; - img->w = img->d_w = width; - img->h = img->d_h = height; - img->fmt = VPX_IMG_FMT_I420; - img->planes[0] = frameYUV420->data[0]; - img->planes[1] = frameYUV420->data[1]; - img->planes[2] = frameYUV420->data[2]; - img->planes[3] = nullptr; - img->stride[0] = frameYUV420->linesize[0]; - img->stride[1] = frameYUV420->linesize[1]; - img->stride[2] = frameYUV420->linesize[2]; - img->stride[3] = frameYUV420->linesize[3]; + for (int i = 0; i < 3; i++) + { + int dstStride = img->stride[i]; + int srcStride = frameYUV420->linesize[i]; + int minStride = std::min(dstStride, srcStride); + int size = (i == 0) ? img->d_h : img->d_h / 2; + + for (int j = 0; j < size; j++) + { + uint8_t *dst = img->planes[i] + dstStride * j; + uint8_t *src = frameYUV420->data[i] + srcStride * j; + memcpy(dst, src, minStride); + } + } return img; } From 1c5158213dd6f38acdcf202e660b6e383764c436 Mon Sep 17 00:00:00 2001 From: Diadlo Date: Mon, 20 Jun 2016 02:06:55 +0300 Subject: [PATCH 10/12] fix(avform): Added restoring selected region --- src/persistence/settings.cpp | 30 ++++++++++++++- src/persistence/settings.h | 8 ++++ src/widget/form/settings/avform.cpp | 57 +++++++++++++++++++++++------ src/widget/form/settings/avform.h | 1 + 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index 437e83084..7f8b24a8c 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -243,6 +243,8 @@ void Settings::loadGlobal() s.beginGroup("Video"); videoDev = s.value("videoDev", "").toString(); camVideoRes = s.value("camVideoRes", QRect()).toRect(); + screenRegion = s.value("screenRegion", QRect()).toRect(); + screenGrabbed = s.value("screenGrabbed", false).toBool(); camVideoFPS = s.value("camVideoFPS", 0).toUInt(); s.endGroup(); @@ -472,8 +474,10 @@ void Settings::saveGlobal() s.beginGroup("Video"); s.setValue("videoDev", videoDev); - s.setValue("camVideoRes",camVideoRes); - s.setValue("camVideoFPS",camVideoFPS); + s.setValue("camVideoRes", camVideoRes); + s.setValue("camVideoFPS", camVideoFPS); + s.setValue("screenRegion", screenRegion); + s.setValue("screenGrabbed", screenGrabbed); s.endGroup(); } @@ -1412,6 +1416,28 @@ void Settings::setOutVolume(int volume) outVolume = volume; } +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}; diff --git a/src/persistence/settings.h b/src/persistence/settings.h index a96290ee8..23a7a18e9 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -190,6 +190,12 @@ public: QString getVideoDev() const; void setVideoDev(const QString& deviceSpecifier); + QRect getScreenRegion() const; + void setScreenRegion(const QRect &value); + + bool getScreenGrabbed() const; + void setScreenGrabbed(bool value); + QRect getCamVideoRes() const; void setCamVideoRes(QRect newValue); @@ -435,6 +441,8 @@ private: // Video QString videoDev; QRect camVideoRes; + QRect screenRegion; + bool screenGrabbed; unsigned short camVideoFPS; struct friendProp diff --git a/src/widget/form/settings/avform.cpp b/src/widget/form/settings/avform.cpp index 3f9422d8f..889256634 100644 --- a/src/widget/form/settings/avform.cpp +++ b/src/widget/form/settings/avform.cpp @@ -40,8 +40,8 @@ AVForm::AVForm() : GenericForm(QPixmap(":/img/settings/av.png")) - , subscribedToAudioIn{false} - , camVideoSurface{nullptr} + , subscribedToAudioIn(false) + , camVideoSurface(nullptr) , camera(CameraSource::getInstance()) { bodyUI = new Ui::AVSettings; @@ -136,6 +136,14 @@ void AVForm::showEvent(QShowEvent* 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) { if (index < 0 || index >= videoModes.size()) @@ -152,8 +160,15 @@ void AVForm::onVideoModesIndexChanged(int index) QString devName = videoDeviceList[devIndex].first; VideoMode mode = videoModes[index]; - if (CameraDevice::isScreen(devName) && !mode.height && !mode.width) + if (CameraDevice::isScreen(devName) && mode == VideoMode()) { + 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) @@ -161,19 +176,21 @@ void AVForm::onVideoModesIndexChanged(int index) VideoMode mode(region); mode.width = mode.width / 2 * 2; mode.height = mode.height / 2 * 2; - camera.open(devName, mode); + + 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; } - Settings::getInstance().setCamVideoRes(mode.toRect()); - Settings::getInstance().setCamVideoFPS(mode.FPS); - camera.open(devName, mode); + Settings::getInstance().setScreenGrabbed(false); + open(devName, mode); } void AVForm::selectBestModes(QVector &allVideoModes) @@ -326,7 +343,8 @@ void AVForm::updateVideoModes(int curIndex) QVector allVideoModes = CameraDevice::getVideoModes(devName); qDebug("available Modes:"); - if (CameraDevice::isScreen(devName)) + bool isScreen = CameraDevice::isScreen(devName); + if (isScreen) { // Add extra video mode to region selection allVideoModes.push_back(VideoMode()); @@ -343,18 +361,29 @@ void AVForm::updateVideoModes(int curIndex) } int preferedIndex = searchPreferredIndex(); - if (preferedIndex!= -1) + 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() / 2; + int mid = (videoModes.size() - 1) / 2; bodyUI->videoModescomboBox->setCurrentIndex(mid); } @@ -366,15 +395,19 @@ void AVForm::onVideoDevChanged(int index) return; } + Settings::getInstance().setScreenGrabbed(false); QString dev = videoDeviceList[index].first; Settings::getInstance().setVideoDev(dev); bool previouslyBlocked = bodyUI->videoModescomboBox->blockSignals(true); updateVideoModes(index); bodyUI->videoModescomboBox->blockSignals(previouslyBlocked); + if (Settings::getInstance().getScreenGrabbed()) + return; + int modeIndex = bodyUI->videoModescomboBox->currentIndex(); VideoMode mode = VideoMode(); - if (0 < modeIndex || modeIndex < videoModes.size()) + if (0 < modeIndex && modeIndex < videoModes.size()) mode = videoModes[modeIndex]; camera.open(dev, mode); diff --git a/src/widget/form/settings/avform.h b/src/widget/form/settings/avform.h index 1c9869308..ed812305f 100644 --- a/src/widget/form/settings/avform.h +++ b/src/widget/form/settings/avform.h @@ -77,6 +77,7 @@ private: bool eventFilter(QObject *o, QEvent *e) final override; void hideEvent(QHideEvent* event) final override; void showEvent(QShowEvent*event) final override; + void open(const QString &devName, const VideoMode &mode); private: Ui::AVSettings *bodyUI; From c3de6238ca5efa9e42b484a755934c986d0d4b6e Mon Sep 17 00:00:00 2001 From: Diadlo Date: Thu, 23 Jun 2016 02:11:02 +0300 Subject: [PATCH 11/12] feat(camerasource): Change default video mode to preferred --- src/core/toxcall.cpp | 1 + src/video/camerasource.cpp | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/toxcall.cpp b/src/core/toxcall.cpp index 390957f2b..8ed8d14a1 100644 --- a/src/core/toxcall.cpp +++ b/src/core/toxcall.cpp @@ -102,6 +102,7 @@ ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av) { videoSource = new CoreVideoSource; CameraSource& source = CameraSource::getInstance(); + if (!source.isOpen()) source.open(); source.subscribe(); diff --git a/src/video/camerasource.cpp b/src/video/camerasource.cpp index 7400234e3..1bcbcc296 100644 --- a/src/video/camerasource.cpp +++ b/src/video/camerasource.cpp @@ -28,6 +28,7 @@ extern "C" { #include #include #include +#include "src/persistence/settings.h" #include "camerasource.h" #include "cameradevice.h" #include "videoframe.h" @@ -67,7 +68,15 @@ void CameraSource::open() void CameraSource::open(const QString& deviceName) { - open(deviceName, VideoMode()); + 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) From 504ad534e0e9d27077a49222f2c7f9e0d568b22d Mon Sep 17 00:00:00 2001 From: Diadlo Date: Sat, 25 Jun 2016 11:46:59 +0300 Subject: [PATCH 12/12] fix(directshow): Fixed problem with crosses initialization --- src/platform/camera/directshow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/platform/camera/directshow.cpp b/src/platform/camera/directshow.cpp index f0d8208f8..38287464c 100644 --- a/src/platform/camera/directshow.cpp +++ b/src/platform/camera/directshow.cpp @@ -187,6 +187,7 @@ QVector DirectShow::getDeviceModes(QString devName) IPin *pin; if (devFilter->EnumPins(&pins) != S_OK) return modes; + while (pins->Next(1, &pin, nullptr) == S_OK) { IKsPropertySet *p = nullptr; @@ -214,12 +215,14 @@ QVector DirectShow::getDeviceModes(QString devName) goto next; if (config->GetNumberOfCapabilities(&n, &size) != S_OK) goto pinend; + assert(size == sizeof(VIDEO_STREAM_CONFIG_CAPS)); vcaps = new VIDEO_STREAM_CONFIG_CAPS; - for (int i=0; iGetStreamCaps(i, &type, (BYTE*)vcaps) != S_OK) goto nextformat; @@ -227,7 +230,6 @@ QVector DirectShow::getDeviceModes(QString devName) && !IsEqualGUID(type->formattype, FORMAT_VideoInfo2)) goto nextformat; - VideoMode mode; mode.width = vcaps->MaxOutputSize.cx; mode.height = vcaps->MaxOutputSize.cy; mode.FPS = 1e7 / vcaps->MinFrameInterval;