From 3f130f2c3c765f2aa7825d14ddbc54a95135b7af Mon Sep 17 00:00:00 2001 From: Tomaz Canabrava Date: Sat, 7 Dec 2019 16:00:05 +0000 Subject: [PATCH 1/2] Move VideoManager class from FligthDisplay to VideoStreaming Makes more sense for it to be in VideoStreamer as it takes care of managing the video streams. --- qgroundcontrol.pro | 4 +- src/FlightDisplay/VideoManager.cc | 458 ------------------------------------- src/FlightDisplay/VideoManager.h | 125 ---------- src/VideoStreaming/VideoManager.cc | 458 +++++++++++++++++++++++++++++++++++++ src/VideoStreaming/VideoManager.h | 125 ++++++++++ 5 files changed, 585 insertions(+), 585 deletions(-) delete mode 100644 src/FlightDisplay/VideoManager.cc delete mode 100644 src/FlightDisplay/VideoManager.h create mode 100644 src/VideoStreaming/VideoManager.cc create mode 100644 src/VideoStreaming/VideoManager.h diff --git a/qgroundcontrol.pro b/qgroundcontrol.pro index 831a87f..0f799fc 100644 --- a/qgroundcontrol.pro +++ b/qgroundcontrol.pro @@ -564,7 +564,6 @@ HEADERS += \ src/Camera/QGCCameraManager.h \ src/CmdLineOptParser.h \ src/FirmwarePlugin/PX4/px4_custom_mode.h \ - src/FlightDisplay/VideoManager.h \ src/FlightMap/Widgets/ValuesWidgetController.h \ src/FollowMe/FollowMe.h \ src/Joystick/Joystick.h \ @@ -771,7 +770,6 @@ SOURCES += \ src/Camera/QGCCameraIO.cc \ src/Camera/QGCCameraManager.cc \ src/CmdLineOptParser.cc \ - src/FlightDisplay/VideoManager.cc \ src/FlightMap/Widgets/ValuesWidgetController.cc \ src/FollowMe/FollowMe.cc \ src/Joystick/Joystick.cc \ @@ -1303,11 +1301,13 @@ HEADERS += \ src/VideoStreaming/VideoReceiver.h \ src/VideoStreaming/VideoStreaming.h \ src/VideoStreaming/SubtitleWriter.h \ + src/VideoStreaming/VideoManager.h SOURCES += \ src/VideoStreaming/VideoReceiver.cc \ src/VideoStreaming/VideoStreaming.cc \ src/VideoStreaming/SubtitleWriter.cc \ + src/VideoStreaming/VideoManager.cc contains (CONFIG, DISABLE_VIDEOSTREAMING) { message("Skipping support for video streaming (manual override from command line)") diff --git a/src/FlightDisplay/VideoManager.cc b/src/FlightDisplay/VideoManager.cc deleted file mode 100644 index 7fd2ef1..0000000 --- a/src/FlightDisplay/VideoManager.cc +++ /dev/null @@ -1,458 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2020 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#include -#include -#include -#include -#include - -#ifndef QGC_DISABLE_UVC -#include -#endif - -#include "ScreenToolsController.h" -#include "VideoManager.h" -#include "QGCToolbox.h" -#include "QGCCorePlugin.h" -#include "QGCOptions.h" -#include "MultiVehicleManager.h" -#include "Settings/SettingsManager.h" -#include "Vehicle.h" -#include "QGCCameraManager.h" - -QGC_LOGGING_CATEGORY(VideoManagerLog, "VideoManagerLog") - -//----------------------------------------------------------------------------- -VideoManager::VideoManager(QGCApplication* app, QGCToolbox* toolbox) - : QGCTool(app, toolbox) -{ -} - -//----------------------------------------------------------------------------- -VideoManager::~VideoManager() -{ - delete _videoReceiver; - _videoReceiver = nullptr; - delete _thermalVideoReceiver; - _thermalVideoReceiver = nullptr; -} - -//----------------------------------------------------------------------------- -void -VideoManager::setToolbox(QGCToolbox *toolbox) -{ - QGCTool::setToolbox(toolbox); - QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); - qmlRegisterUncreatableType ("QGroundControl.VideoManager", 1, 0, "VideoManager", "Reference only"); - qmlRegisterUncreatableType("QGroundControl", 1, 0, "VideoReceiver","Reference only"); - _videoSettings = toolbox->settingsManager()->videoSettings(); - QString videoSource = _videoSettings->videoSource()->rawValue().toString(); - connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged); - connect(_videoSettings->udpPort(), &Fact::rawValueChanged, this, &VideoManager::_udpPortChanged); - connect(_videoSettings->rtspUrl(), &Fact::rawValueChanged, this, &VideoManager::_rtspUrlChanged); - connect(_videoSettings->tcpUrl(), &Fact::rawValueChanged, this, &VideoManager::_tcpUrlChanged); - connect(_videoSettings->aspectRatio(), &Fact::rawValueChanged, this, &VideoManager::_aspectRatioChanged); - MultiVehicleManager *pVehicleMgr = qgcApp()->toolbox()->multiVehicleManager(); - connect(pVehicleMgr, &MultiVehicleManager::activeVehicleChanged, this, &VideoManager::_setActiveVehicle); - -#if defined(QGC_GST_STREAMING) -#ifndef QGC_DISABLE_UVC - // If we are using a UVC camera setup the device name - _updateUVC(); -#endif - - emit isGStreamerChanged(); - qCDebug(VideoManagerLog) << "New Video Source:" << videoSource; - _videoReceiver = toolbox->corePlugin()->createVideoReceiver(this); - _thermalVideoReceiver = toolbox->corePlugin()->createVideoReceiver(this); - _updateSettings(); - if(isGStreamer()) { - startVideo(); - _subtitleWriter.setVideoReceiver(_videoReceiver); - } else { - stopVideo(); - } - -#endif -} - -//----------------------------------------------------------------------------- -void -VideoManager::startVideo() -{ - if(_videoReceiver) _videoReceiver->start(); - if(_thermalVideoReceiver) _thermalVideoReceiver->start(); -} - -//----------------------------------------------------------------------------- -void -VideoManager::stopVideo() -{ - if(_videoReceiver) _videoReceiver->stop(); - if(_thermalVideoReceiver) _thermalVideoReceiver->stop(); -} - -//----------------------------------------------------------------------------- -double VideoManager::aspectRatio() -{ - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); - if(pInfo) { - qCDebug(VideoManagerLog) << "Primary AR: " << pInfo->aspectRatio(); - return pInfo->aspectRatio(); - } - } - return _videoSettings->aspectRatio()->rawValue().toDouble(); -} - -//----------------------------------------------------------------------------- -double VideoManager::thermalAspectRatio() -{ - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); - if(pInfo) { - qCDebug(VideoManagerLog) << "Thermal AR: " << pInfo->aspectRatio(); - return pInfo->aspectRatio(); - } - } - return 1.0; -} - -//----------------------------------------------------------------------------- -double VideoManager::hfov() -{ - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); - if(pInfo) { - return pInfo->hfov(); - } - } - return 1.0; -} - -//----------------------------------------------------------------------------- -double VideoManager::thermalHfov() -{ - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); - if(pInfo) { - return pInfo->aspectRatio(); - } - } - return _videoSettings->aspectRatio()->rawValue().toDouble(); -} - -//----------------------------------------------------------------------------- -bool -VideoManager::hasThermal() -{ - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); - if(pInfo) { - return true; - } - } - return false; -} - -//----------------------------------------------------------------------------- -bool -VideoManager::autoStreamConfigured() -{ -#if defined(QGC_GST_STREAMING) - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); - if(pInfo) { - return !pInfo->uri().isEmpty(); - } - } -#endif - return false; -} - -//----------------------------------------------------------------------------- -void -VideoManager::_updateUVC() -{ -#ifndef QGC_DISABLE_UVC - QString videoSource = _videoSettings->videoSource()->rawValue().toString(); - QList cameras = QCameraInfo::availableCameras(); - for (const QCameraInfo &cameraInfo: cameras) { - if(cameraInfo.description() == videoSource) { - _videoSourceID = cameraInfo.deviceName(); - emit videoSourceIDChanged(); - qCDebug(VideoManagerLog) << "Found USB source:" << _videoSourceID << " Name:" << videoSource; - break; - } - } -#endif -} - -//----------------------------------------------------------------------------- -void -VideoManager::_videoSourceChanged() -{ - _updateUVC(); - emit hasVideoChanged(); - emit isGStreamerChanged(); - emit isAutoStreamChanged(); - restartVideo(); -} - -//----------------------------------------------------------------------------- -void -VideoManager::_udpPortChanged() -{ - restartVideo(); -} - -//----------------------------------------------------------------------------- -void -VideoManager::_rtspUrlChanged() -{ - restartVideo(); -} - -//----------------------------------------------------------------------------- -void -VideoManager::_tcpUrlChanged() -{ - restartVideo(); -} - -//----------------------------------------------------------------------------- -bool -VideoManager::hasVideo() -{ - if(autoStreamConfigured()) { - return true; - } - QString videoSource = _videoSettings->videoSource()->rawValue().toString(); - return !videoSource.isEmpty() && videoSource != VideoSettings::videoSourceNoVideo && videoSource != VideoSettings::videoDisabled; -} - -//----------------------------------------------------------------------------- -bool -VideoManager::isGStreamer() -{ -#if defined(QGC_GST_STREAMING) - QString videoSource = _videoSettings->videoSource()->rawValue().toString(); - return - videoSource == VideoSettings::videoSourceUDPH264 || - videoSource == VideoSettings::videoSourceUDPH265 || - videoSource == VideoSettings::videoSourceRTSP || - videoSource == VideoSettings::videoSourceTCP || - videoSource == VideoSettings::videoSourceMPEGTS || - autoStreamConfigured(); -#else - return false; -#endif -} - -//----------------------------------------------------------------------------- -#ifndef QGC_DISABLE_UVC -bool -VideoManager::uvcEnabled() -{ - return QCameraInfo::availableCameras().count() > 0; -} -#endif - -//----------------------------------------------------------------------------- -void -VideoManager::setfullScreen(bool f) -{ - if(f) { - //-- No can do if no vehicle or connection lost - if(!_activeVehicle || _activeVehicle->connectionLost()) { - f = false; - } - } - _fullScreen = f; - emit fullScreenChanged(); -} - -//----------------------------------------------------------------------------- -#if defined(QGC_GST_STREAMING) -GstElement* -VideoManager::_makeVideoSink(gpointer widget) -{ - GstElement* sink; - - if ((sink = gst_element_factory_make("qgcvideosinkbin", nullptr)) != nullptr) { - g_object_set(sink, "widget", widget, NULL); - } else { - qCritical() << "VideoManager::_makeVideoSink() failed. Error with gst_element_factory_make('qgcvideosinkbin')"; - } - - return sink; -} -#endif - -//----------------------------------------------------------------------------- -void -VideoManager::_initVideo() -{ -#if defined(QGC_GST_STREAMING) - QQuickItem* root = qgcApp()->mainRootWindow(); - - if (root == nullptr) { - qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. No root window"; - return; - } - - QQuickItem* widget = root->findChild("videoContent"); - - if (widget != nullptr) { - _videoReceiver->setVideoSink(_makeVideoSink(widget)); - } else { - qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. 'videoContent' widget not found"; - } - - widget = root->findChild("thermalVideo"); - - if (widget != nullptr) { - _thermalVideoReceiver->setVideoSink(_makeVideoSink(widget)); - } else { - qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. 'thermalVideo' widget not found"; - } -#endif -} - -//----------------------------------------------------------------------------- -void -VideoManager::_updateSettings() -{ - if(!_videoSettings || !_videoReceiver) - return; - //-- Auto discovery - if(_activeVehicle && _activeVehicle->dynamicCameras()) { - QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); - if(pInfo) { - qCDebug(VideoManagerLog) << "Configure primary stream: " << pInfo->uri(); - switch(pInfo->type()) { - case VIDEO_STREAM_TYPE_RTSP: - _videoReceiver->setUri(pInfo->uri()); - _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceRTSP); - break; - case VIDEO_STREAM_TYPE_TCP_MPEG: - _videoReceiver->setUri(pInfo->uri()); - _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceTCP); - break; - case VIDEO_STREAM_TYPE_RTPUDP: - _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(pInfo->uri())); - _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceUDPH264); - break; - case VIDEO_STREAM_TYPE_MPEG_TS_H264: - _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(pInfo->uri())); - _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceMPEGTS); - break; - default: - _videoReceiver->setUri(pInfo->uri()); - break; - } - //-- Thermal stream (if any) - QGCVideoStreamInfo* pTinfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); - if(pTinfo) { - qCDebug(VideoManagerLog) << "Configure secondary stream: " << pTinfo->uri(); - switch(pTinfo->type()) { - case VIDEO_STREAM_TYPE_RTSP: - case VIDEO_STREAM_TYPE_TCP_MPEG: - _thermalVideoReceiver->setUri(pTinfo->uri()); - break; - case VIDEO_STREAM_TYPE_RTPUDP: - _thermalVideoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(pTinfo->uri())); - break; - case VIDEO_STREAM_TYPE_MPEG_TS_H264: - _thermalVideoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(pTinfo->uri())); - break; - default: - _thermalVideoReceiver->setUri(pTinfo->uri()); - break; - } - } - return; - } - } - QString source = _videoSettings->videoSource()->rawValue().toString(); - if (source == VideoSettings::videoSourceUDPH264) - _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); - else if (source == VideoSettings::videoSourceUDPH265) - _videoReceiver->setUri(QStringLiteral("udp265://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); - else if (source == VideoSettings::videoSourceMPEGTS) - _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); - else if (source == VideoSettings::videoSourceRTSP) - _videoReceiver->setUri(_videoSettings->rtspUrl()->rawValue().toString()); - else if (source == VideoSettings::videoSourceTCP) - _videoReceiver->setUri(QStringLiteral("tcp://%1").arg(_videoSettings->tcpUrl()->rawValue().toString())); -} - -//----------------------------------------------------------------------------- -void -VideoManager::restartVideo() -{ -#if defined(QGC_GST_STREAMING) - qCDebug(VideoManagerLog) << "Restart video streaming"; - stopVideo(); - _updateSettings(); - startVideo(); - emit aspectRatioChanged(); -#endif -} - -//---------------------------------------------------------------------------------------- -void -VideoManager::_setActiveVehicle(Vehicle* vehicle) -{ - if(_activeVehicle) { - disconnect(_activeVehicle, &Vehicle::connectionLostChanged, this, &VideoManager::_connectionLostChanged); - if(_activeVehicle->dynamicCameras()) { - QGCCameraControl* pCamera = _activeVehicle->dynamicCameras()->currentCameraInstance(); - if(pCamera) { - pCamera->stopStream(); - } - disconnect(_activeVehicle->dynamicCameras(), &QGCCameraManager::streamChanged, this, &VideoManager::restartVideo); - } - } - _activeVehicle = vehicle; - if(_activeVehicle) { - connect(_activeVehicle, &Vehicle::connectionLostChanged, this, &VideoManager::_connectionLostChanged); - if(_activeVehicle->dynamicCameras()) { - connect(_activeVehicle->dynamicCameras(), &QGCCameraManager::streamChanged, this, &VideoManager::restartVideo); - QGCCameraControl* pCamera = _activeVehicle->dynamicCameras()->currentCameraInstance(); - if(pCamera) { - pCamera->resumeStream(); - } - } - } else { - //-- Disable full screen video if vehicle is gone - setfullScreen(false); - } - emit autoStreamConfiguredChanged(); - restartVideo(); -} - -//---------------------------------------------------------------------------------------- -void -VideoManager::_connectionLostChanged(bool connectionLost) -{ - if(connectionLost) { - //-- Disable full screen video if connection is lost - setfullScreen(false); - } -} - -//---------------------------------------------------------------------------------------- -void -VideoManager::_aspectRatioChanged() -{ - emit aspectRatioChanged(); -} diff --git a/src/FlightDisplay/VideoManager.h b/src/FlightDisplay/VideoManager.h deleted file mode 100644 index f53f282..0000000 --- a/src/FlightDisplay/VideoManager.h +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** - * - * (c) 2009-2020 QGROUNDCONTROL PROJECT - * - * QGroundControl is licensed according to the terms in the file - * COPYING.md in the root of the source code directory. - * - ****************************************************************************/ - - -#ifndef VideoManager_H -#define VideoManager_H - -#include -#include -#include -#include - -#include "QGCMAVLink.h" -#include "QGCLoggingCategory.h" -#include "VideoReceiver.h" -#include "QGCToolbox.h" -#include "SubtitleWriter.h" - -Q_DECLARE_LOGGING_CATEGORY(VideoManagerLog) - -class VideoSettings; -class Vehicle; -class Joystick; - -class VideoManager : public QGCTool -{ - Q_OBJECT - -public: - VideoManager (QGCApplication* app, QGCToolbox* toolbox); - virtual ~VideoManager (); - - Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) - Q_PROPERTY(bool isGStreamer READ isGStreamer NOTIFY isGStreamerChanged) - Q_PROPERTY(bool isTaisync READ isTaisync WRITE setIsTaisync NOTIFY isTaisyncChanged) - Q_PROPERTY(QString videoSourceID READ videoSourceID NOTIFY videoSourceIDChanged) - Q_PROPERTY(bool uvcEnabled READ uvcEnabled CONSTANT) - Q_PROPERTY(bool fullScreen READ fullScreen WRITE setfullScreen NOTIFY fullScreenChanged) - Q_PROPERTY(VideoReceiver* videoReceiver READ videoReceiver CONSTANT) - Q_PROPERTY(VideoReceiver* thermalVideoReceiver READ thermalVideoReceiver CONSTANT) - Q_PROPERTY(double aspectRatio READ aspectRatio NOTIFY aspectRatioChanged) - Q_PROPERTY(double thermalAspectRatio READ thermalAspectRatio NOTIFY aspectRatioChanged) - Q_PROPERTY(double hfov READ hfov NOTIFY aspectRatioChanged) - Q_PROPERTY(double thermalHfov READ thermalHfov NOTIFY aspectRatioChanged) - Q_PROPERTY(bool autoStreamConfigured READ autoStreamConfigured NOTIFY autoStreamConfiguredChanged) - Q_PROPERTY(bool hasThermal READ hasThermal NOTIFY aspectRatioChanged) - - virtual bool hasVideo (); - virtual bool isGStreamer (); - virtual bool isTaisync () { return _isTaisync; } - virtual bool fullScreen () { return _fullScreen; } - virtual QString videoSourceID () { return _videoSourceID; } - virtual double aspectRatio (); - virtual double thermalAspectRatio (); - virtual double hfov (); - virtual double thermalHfov (); - virtual bool autoStreamConfigured(); - virtual bool hasThermal (); - virtual void restartVideo (); - - virtual VideoReceiver* videoReceiver () { return _videoReceiver; } - virtual VideoReceiver* thermalVideoReceiver () { return _thermalVideoReceiver; } - -#if defined(QGC_DISABLE_UVC) - virtual bool uvcEnabled () { return false; } -#else - virtual bool uvcEnabled (); -#endif - - virtual void setfullScreen (bool f); - virtual void setIsTaisync (bool t) { _isTaisync = t; emit isTaisyncChanged(); } - - // Override from QGCTool - virtual void setToolbox (QGCToolbox *toolbox); - - Q_INVOKABLE void startVideo (); - Q_INVOKABLE void stopVideo (); - -signals: - void hasVideoChanged (); - void isGStreamerChanged (); - void videoSourceIDChanged (); - void fullScreenChanged (); - void isAutoStreamChanged (); - void isTaisyncChanged (); - void aspectRatioChanged (); - void autoStreamConfiguredChanged(); - -protected slots: - void _videoSourceChanged (); - void _udpPortChanged (); - void _rtspUrlChanged (); - void _tcpUrlChanged (); - void _updateUVC (); - void _setActiveVehicle (Vehicle* vehicle); - void _aspectRatioChanged (); - void _connectionLostChanged (bool connectionLost); - -protected: - friend class FinishVideoInitialization; -#if defined(QGC_GST_STREAMING) - static gboolean _videoSinkQuery (GstPad* pad, GstObject* parent, GstQuery* query); - GstElement* _makeVideoSink (gpointer widget); -#endif - void _initVideo (); - void _updateSettings (); - -protected: - SubtitleWriter _subtitleWriter; - bool _isTaisync = false; - VideoReceiver* _videoReceiver = nullptr; - VideoReceiver* _thermalVideoReceiver = nullptr; - VideoSettings* _videoSettings = nullptr; - QString _videoSourceID; - bool _fullScreen = false; - Vehicle* _activeVehicle = nullptr; -}; - -#endif diff --git a/src/VideoStreaming/VideoManager.cc b/src/VideoStreaming/VideoManager.cc new file mode 100644 index 0000000..7fd2ef1 --- /dev/null +++ b/src/VideoStreaming/VideoManager.cc @@ -0,0 +1,458 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +#include +#include +#include +#include +#include + +#ifndef QGC_DISABLE_UVC +#include +#endif + +#include "ScreenToolsController.h" +#include "VideoManager.h" +#include "QGCToolbox.h" +#include "QGCCorePlugin.h" +#include "QGCOptions.h" +#include "MultiVehicleManager.h" +#include "Settings/SettingsManager.h" +#include "Vehicle.h" +#include "QGCCameraManager.h" + +QGC_LOGGING_CATEGORY(VideoManagerLog, "VideoManagerLog") + +//----------------------------------------------------------------------------- +VideoManager::VideoManager(QGCApplication* app, QGCToolbox* toolbox) + : QGCTool(app, toolbox) +{ +} + +//----------------------------------------------------------------------------- +VideoManager::~VideoManager() +{ + delete _videoReceiver; + _videoReceiver = nullptr; + delete _thermalVideoReceiver; + _thermalVideoReceiver = nullptr; +} + +//----------------------------------------------------------------------------- +void +VideoManager::setToolbox(QGCToolbox *toolbox) +{ + QGCTool::setToolbox(toolbox); + QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); + qmlRegisterUncreatableType ("QGroundControl.VideoManager", 1, 0, "VideoManager", "Reference only"); + qmlRegisterUncreatableType("QGroundControl", 1, 0, "VideoReceiver","Reference only"); + _videoSettings = toolbox->settingsManager()->videoSettings(); + QString videoSource = _videoSettings->videoSource()->rawValue().toString(); + connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged); + connect(_videoSettings->udpPort(), &Fact::rawValueChanged, this, &VideoManager::_udpPortChanged); + connect(_videoSettings->rtspUrl(), &Fact::rawValueChanged, this, &VideoManager::_rtspUrlChanged); + connect(_videoSettings->tcpUrl(), &Fact::rawValueChanged, this, &VideoManager::_tcpUrlChanged); + connect(_videoSettings->aspectRatio(), &Fact::rawValueChanged, this, &VideoManager::_aspectRatioChanged); + MultiVehicleManager *pVehicleMgr = qgcApp()->toolbox()->multiVehicleManager(); + connect(pVehicleMgr, &MultiVehicleManager::activeVehicleChanged, this, &VideoManager::_setActiveVehicle); + +#if defined(QGC_GST_STREAMING) +#ifndef QGC_DISABLE_UVC + // If we are using a UVC camera setup the device name + _updateUVC(); +#endif + + emit isGStreamerChanged(); + qCDebug(VideoManagerLog) << "New Video Source:" << videoSource; + _videoReceiver = toolbox->corePlugin()->createVideoReceiver(this); + _thermalVideoReceiver = toolbox->corePlugin()->createVideoReceiver(this); + _updateSettings(); + if(isGStreamer()) { + startVideo(); + _subtitleWriter.setVideoReceiver(_videoReceiver); + } else { + stopVideo(); + } + +#endif +} + +//----------------------------------------------------------------------------- +void +VideoManager::startVideo() +{ + if(_videoReceiver) _videoReceiver->start(); + if(_thermalVideoReceiver) _thermalVideoReceiver->start(); +} + +//----------------------------------------------------------------------------- +void +VideoManager::stopVideo() +{ + if(_videoReceiver) _videoReceiver->stop(); + if(_thermalVideoReceiver) _thermalVideoReceiver->stop(); +} + +//----------------------------------------------------------------------------- +double VideoManager::aspectRatio() +{ + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); + if(pInfo) { + qCDebug(VideoManagerLog) << "Primary AR: " << pInfo->aspectRatio(); + return pInfo->aspectRatio(); + } + } + return _videoSettings->aspectRatio()->rawValue().toDouble(); +} + +//----------------------------------------------------------------------------- +double VideoManager::thermalAspectRatio() +{ + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); + if(pInfo) { + qCDebug(VideoManagerLog) << "Thermal AR: " << pInfo->aspectRatio(); + return pInfo->aspectRatio(); + } + } + return 1.0; +} + +//----------------------------------------------------------------------------- +double VideoManager::hfov() +{ + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); + if(pInfo) { + return pInfo->hfov(); + } + } + return 1.0; +} + +//----------------------------------------------------------------------------- +double VideoManager::thermalHfov() +{ + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); + if(pInfo) { + return pInfo->aspectRatio(); + } + } + return _videoSettings->aspectRatio()->rawValue().toDouble(); +} + +//----------------------------------------------------------------------------- +bool +VideoManager::hasThermal() +{ + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); + if(pInfo) { + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +bool +VideoManager::autoStreamConfigured() +{ +#if defined(QGC_GST_STREAMING) + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); + if(pInfo) { + return !pInfo->uri().isEmpty(); + } + } +#endif + return false; +} + +//----------------------------------------------------------------------------- +void +VideoManager::_updateUVC() +{ +#ifndef QGC_DISABLE_UVC + QString videoSource = _videoSettings->videoSource()->rawValue().toString(); + QList cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo &cameraInfo: cameras) { + if(cameraInfo.description() == videoSource) { + _videoSourceID = cameraInfo.deviceName(); + emit videoSourceIDChanged(); + qCDebug(VideoManagerLog) << "Found USB source:" << _videoSourceID << " Name:" << videoSource; + break; + } + } +#endif +} + +//----------------------------------------------------------------------------- +void +VideoManager::_videoSourceChanged() +{ + _updateUVC(); + emit hasVideoChanged(); + emit isGStreamerChanged(); + emit isAutoStreamChanged(); + restartVideo(); +} + +//----------------------------------------------------------------------------- +void +VideoManager::_udpPortChanged() +{ + restartVideo(); +} + +//----------------------------------------------------------------------------- +void +VideoManager::_rtspUrlChanged() +{ + restartVideo(); +} + +//----------------------------------------------------------------------------- +void +VideoManager::_tcpUrlChanged() +{ + restartVideo(); +} + +//----------------------------------------------------------------------------- +bool +VideoManager::hasVideo() +{ + if(autoStreamConfigured()) { + return true; + } + QString videoSource = _videoSettings->videoSource()->rawValue().toString(); + return !videoSource.isEmpty() && videoSource != VideoSettings::videoSourceNoVideo && videoSource != VideoSettings::videoDisabled; +} + +//----------------------------------------------------------------------------- +bool +VideoManager::isGStreamer() +{ +#if defined(QGC_GST_STREAMING) + QString videoSource = _videoSettings->videoSource()->rawValue().toString(); + return + videoSource == VideoSettings::videoSourceUDPH264 || + videoSource == VideoSettings::videoSourceUDPH265 || + videoSource == VideoSettings::videoSourceRTSP || + videoSource == VideoSettings::videoSourceTCP || + videoSource == VideoSettings::videoSourceMPEGTS || + autoStreamConfigured(); +#else + return false; +#endif +} + +//----------------------------------------------------------------------------- +#ifndef QGC_DISABLE_UVC +bool +VideoManager::uvcEnabled() +{ + return QCameraInfo::availableCameras().count() > 0; +} +#endif + +//----------------------------------------------------------------------------- +void +VideoManager::setfullScreen(bool f) +{ + if(f) { + //-- No can do if no vehicle or connection lost + if(!_activeVehicle || _activeVehicle->connectionLost()) { + f = false; + } + } + _fullScreen = f; + emit fullScreenChanged(); +} + +//----------------------------------------------------------------------------- +#if defined(QGC_GST_STREAMING) +GstElement* +VideoManager::_makeVideoSink(gpointer widget) +{ + GstElement* sink; + + if ((sink = gst_element_factory_make("qgcvideosinkbin", nullptr)) != nullptr) { + g_object_set(sink, "widget", widget, NULL); + } else { + qCritical() << "VideoManager::_makeVideoSink() failed. Error with gst_element_factory_make('qgcvideosinkbin')"; + } + + return sink; +} +#endif + +//----------------------------------------------------------------------------- +void +VideoManager::_initVideo() +{ +#if defined(QGC_GST_STREAMING) + QQuickItem* root = qgcApp()->mainRootWindow(); + + if (root == nullptr) { + qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. No root window"; + return; + } + + QQuickItem* widget = root->findChild("videoContent"); + + if (widget != nullptr) { + _videoReceiver->setVideoSink(_makeVideoSink(widget)); + } else { + qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. 'videoContent' widget not found"; + } + + widget = root->findChild("thermalVideo"); + + if (widget != nullptr) { + _thermalVideoReceiver->setVideoSink(_makeVideoSink(widget)); + } else { + qCDebug(VideoManagerLog) << "VideoManager::_makeVideoSink() failed. 'thermalVideo' widget not found"; + } +#endif +} + +//----------------------------------------------------------------------------- +void +VideoManager::_updateSettings() +{ + if(!_videoSettings || !_videoReceiver) + return; + //-- Auto discovery + if(_activeVehicle && _activeVehicle->dynamicCameras()) { + QGCVideoStreamInfo* pInfo = _activeVehicle->dynamicCameras()->currentStreamInstance(); + if(pInfo) { + qCDebug(VideoManagerLog) << "Configure primary stream: " << pInfo->uri(); + switch(pInfo->type()) { + case VIDEO_STREAM_TYPE_RTSP: + _videoReceiver->setUri(pInfo->uri()); + _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceRTSP); + break; + case VIDEO_STREAM_TYPE_TCP_MPEG: + _videoReceiver->setUri(pInfo->uri()); + _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceTCP); + break; + case VIDEO_STREAM_TYPE_RTPUDP: + _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(pInfo->uri())); + _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceUDPH264); + break; + case VIDEO_STREAM_TYPE_MPEG_TS_H264: + _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(pInfo->uri())); + _toolbox->settingsManager()->videoSettings()->videoSource()->setRawValue(VideoSettings::videoSourceMPEGTS); + break; + default: + _videoReceiver->setUri(pInfo->uri()); + break; + } + //-- Thermal stream (if any) + QGCVideoStreamInfo* pTinfo = _activeVehicle->dynamicCameras()->thermalStreamInstance(); + if(pTinfo) { + qCDebug(VideoManagerLog) << "Configure secondary stream: " << pTinfo->uri(); + switch(pTinfo->type()) { + case VIDEO_STREAM_TYPE_RTSP: + case VIDEO_STREAM_TYPE_TCP_MPEG: + _thermalVideoReceiver->setUri(pTinfo->uri()); + break; + case VIDEO_STREAM_TYPE_RTPUDP: + _thermalVideoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(pTinfo->uri())); + break; + case VIDEO_STREAM_TYPE_MPEG_TS_H264: + _thermalVideoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(pTinfo->uri())); + break; + default: + _thermalVideoReceiver->setUri(pTinfo->uri()); + break; + } + } + return; + } + } + QString source = _videoSettings->videoSource()->rawValue().toString(); + if (source == VideoSettings::videoSourceUDPH264) + _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); + else if (source == VideoSettings::videoSourceUDPH265) + _videoReceiver->setUri(QStringLiteral("udp265://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); + else if (source == VideoSettings::videoSourceMPEGTS) + _videoReceiver->setUri(QStringLiteral("mpegts://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); + else if (source == VideoSettings::videoSourceRTSP) + _videoReceiver->setUri(_videoSettings->rtspUrl()->rawValue().toString()); + else if (source == VideoSettings::videoSourceTCP) + _videoReceiver->setUri(QStringLiteral("tcp://%1").arg(_videoSettings->tcpUrl()->rawValue().toString())); +} + +//----------------------------------------------------------------------------- +void +VideoManager::restartVideo() +{ +#if defined(QGC_GST_STREAMING) + qCDebug(VideoManagerLog) << "Restart video streaming"; + stopVideo(); + _updateSettings(); + startVideo(); + emit aspectRatioChanged(); +#endif +} + +//---------------------------------------------------------------------------------------- +void +VideoManager::_setActiveVehicle(Vehicle* vehicle) +{ + if(_activeVehicle) { + disconnect(_activeVehicle, &Vehicle::connectionLostChanged, this, &VideoManager::_connectionLostChanged); + if(_activeVehicle->dynamicCameras()) { + QGCCameraControl* pCamera = _activeVehicle->dynamicCameras()->currentCameraInstance(); + if(pCamera) { + pCamera->stopStream(); + } + disconnect(_activeVehicle->dynamicCameras(), &QGCCameraManager::streamChanged, this, &VideoManager::restartVideo); + } + } + _activeVehicle = vehicle; + if(_activeVehicle) { + connect(_activeVehicle, &Vehicle::connectionLostChanged, this, &VideoManager::_connectionLostChanged); + if(_activeVehicle->dynamicCameras()) { + connect(_activeVehicle->dynamicCameras(), &QGCCameraManager::streamChanged, this, &VideoManager::restartVideo); + QGCCameraControl* pCamera = _activeVehicle->dynamicCameras()->currentCameraInstance(); + if(pCamera) { + pCamera->resumeStream(); + } + } + } else { + //-- Disable full screen video if vehicle is gone + setfullScreen(false); + } + emit autoStreamConfiguredChanged(); + restartVideo(); +} + +//---------------------------------------------------------------------------------------- +void +VideoManager::_connectionLostChanged(bool connectionLost) +{ + if(connectionLost) { + //-- Disable full screen video if connection is lost + setfullScreen(false); + } +} + +//---------------------------------------------------------------------------------------- +void +VideoManager::_aspectRatioChanged() +{ + emit aspectRatioChanged(); +} diff --git a/src/VideoStreaming/VideoManager.h b/src/VideoStreaming/VideoManager.h new file mode 100644 index 0000000..f53f282 --- /dev/null +++ b/src/VideoStreaming/VideoManager.h @@ -0,0 +1,125 @@ +/**************************************************************************** + * + * (c) 2009-2020 QGROUNDCONTROL PROJECT + * + * QGroundControl is licensed according to the terms in the file + * COPYING.md in the root of the source code directory. + * + ****************************************************************************/ + + +#ifndef VideoManager_H +#define VideoManager_H + +#include +#include +#include +#include + +#include "QGCMAVLink.h" +#include "QGCLoggingCategory.h" +#include "VideoReceiver.h" +#include "QGCToolbox.h" +#include "SubtitleWriter.h" + +Q_DECLARE_LOGGING_CATEGORY(VideoManagerLog) + +class VideoSettings; +class Vehicle; +class Joystick; + +class VideoManager : public QGCTool +{ + Q_OBJECT + +public: + VideoManager (QGCApplication* app, QGCToolbox* toolbox); + virtual ~VideoManager (); + + Q_PROPERTY(bool hasVideo READ hasVideo NOTIFY hasVideoChanged) + Q_PROPERTY(bool isGStreamer READ isGStreamer NOTIFY isGStreamerChanged) + Q_PROPERTY(bool isTaisync READ isTaisync WRITE setIsTaisync NOTIFY isTaisyncChanged) + Q_PROPERTY(QString videoSourceID READ videoSourceID NOTIFY videoSourceIDChanged) + Q_PROPERTY(bool uvcEnabled READ uvcEnabled CONSTANT) + Q_PROPERTY(bool fullScreen READ fullScreen WRITE setfullScreen NOTIFY fullScreenChanged) + Q_PROPERTY(VideoReceiver* videoReceiver READ videoReceiver CONSTANT) + Q_PROPERTY(VideoReceiver* thermalVideoReceiver READ thermalVideoReceiver CONSTANT) + Q_PROPERTY(double aspectRatio READ aspectRatio NOTIFY aspectRatioChanged) + Q_PROPERTY(double thermalAspectRatio READ thermalAspectRatio NOTIFY aspectRatioChanged) + Q_PROPERTY(double hfov READ hfov NOTIFY aspectRatioChanged) + Q_PROPERTY(double thermalHfov READ thermalHfov NOTIFY aspectRatioChanged) + Q_PROPERTY(bool autoStreamConfigured READ autoStreamConfigured NOTIFY autoStreamConfiguredChanged) + Q_PROPERTY(bool hasThermal READ hasThermal NOTIFY aspectRatioChanged) + + virtual bool hasVideo (); + virtual bool isGStreamer (); + virtual bool isTaisync () { return _isTaisync; } + virtual bool fullScreen () { return _fullScreen; } + virtual QString videoSourceID () { return _videoSourceID; } + virtual double aspectRatio (); + virtual double thermalAspectRatio (); + virtual double hfov (); + virtual double thermalHfov (); + virtual bool autoStreamConfigured(); + virtual bool hasThermal (); + virtual void restartVideo (); + + virtual VideoReceiver* videoReceiver () { return _videoReceiver; } + virtual VideoReceiver* thermalVideoReceiver () { return _thermalVideoReceiver; } + +#if defined(QGC_DISABLE_UVC) + virtual bool uvcEnabled () { return false; } +#else + virtual bool uvcEnabled (); +#endif + + virtual void setfullScreen (bool f); + virtual void setIsTaisync (bool t) { _isTaisync = t; emit isTaisyncChanged(); } + + // Override from QGCTool + virtual void setToolbox (QGCToolbox *toolbox); + + Q_INVOKABLE void startVideo (); + Q_INVOKABLE void stopVideo (); + +signals: + void hasVideoChanged (); + void isGStreamerChanged (); + void videoSourceIDChanged (); + void fullScreenChanged (); + void isAutoStreamChanged (); + void isTaisyncChanged (); + void aspectRatioChanged (); + void autoStreamConfiguredChanged(); + +protected slots: + void _videoSourceChanged (); + void _udpPortChanged (); + void _rtspUrlChanged (); + void _tcpUrlChanged (); + void _updateUVC (); + void _setActiveVehicle (Vehicle* vehicle); + void _aspectRatioChanged (); + void _connectionLostChanged (bool connectionLost); + +protected: + friend class FinishVideoInitialization; +#if defined(QGC_GST_STREAMING) + static gboolean _videoSinkQuery (GstPad* pad, GstObject* parent, GstQuery* query); + GstElement* _makeVideoSink (gpointer widget); +#endif + void _initVideo (); + void _updateSettings (); + +protected: + SubtitleWriter _subtitleWriter; + bool _isTaisync = false; + VideoReceiver* _videoReceiver = nullptr; + VideoReceiver* _thermalVideoReceiver = nullptr; + VideoSettings* _videoSettings = nullptr; + QString _videoSourceID; + bool _fullScreen = false; + Vehicle* _activeVehicle = nullptr; +}; + +#endif From f4927eab42b040ebeed4b46df259277acc41c4fb Mon Sep 17 00:00:00 2001 From: Tomaz Canabrava Date: Wed, 19 Feb 2020 18:37:42 +0000 Subject: [PATCH 2/2] Move the VideoManager also in CMake --- src/CMakeLists.txt | 1 - src/FlightDisplay/CMakeLists.txt | 11 ----------- src/VideoStreaming/CMakeLists.txt | 2 ++ 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0dff558..6be6af8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -157,7 +157,6 @@ target_link_libraries(qgc comm FactSystem FirmwarePlugin - FlightDisplay FlightMap FollowMe Geo diff --git a/src/FlightDisplay/CMakeLists.txt b/src/FlightDisplay/CMakeLists.txt index 93dc18b..d7a3ea2 100644 --- a/src/FlightDisplay/CMakeLists.txt +++ b/src/FlightDisplay/CMakeLists.txt @@ -1,13 +1,4 @@ -add_library(FlightDisplay - VideoManager.cc -) - -target_link_libraries(FlightDisplay - PRIVATE - qgc -) - add_custom_target(FligthDisplayQml SOURCES FlightDisplayView.qml @@ -28,5 +19,3 @@ SOURCES PreFlightSoundCheck.qml VirtualJoystick.qml ) - -target_include_directories(FlightDisplay PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/src/VideoStreaming/CMakeLists.txt b/src/VideoStreaming/CMakeLists.txt index 45f6805..7b14257 100644 --- a/src/VideoStreaming/CMakeLists.txt +++ b/src/VideoStreaming/CMakeLists.txt @@ -13,6 +13,8 @@ add_library(VideoStreaming VideoReceiver.h VideoStreaming.cc VideoStreaming.h + VideoManager.cc + VideoManager.h ) target_link_libraries(VideoStreaming