From 5ec94e7ce933c3b677de279abaa905803ee5da0b Mon Sep 17 00:00:00 2001 From: Holden Date: Fri, 20 Dec 2024 19:13:53 -0500 Subject: [PATCH] VideoManager: Minor Cleanup --- src/QGCApplication.cc | 6 +- src/Settings/VideoSettings.cc | 87 +++++++++---- src/Settings/VideoSettings.h | 3 + src/VideoManager/VideoManager.cc | 114 ++++++++---------- src/VideoManager/VideoManager.h | 1 + .../VideoReceiver/GStreamer/GStreamer.cc | 4 + 6 files changed, 124 insertions(+), 91 deletions(-) diff --git a/src/QGCApplication.cc b/src/QGCApplication.cc index cf2e0c546cb..0cee51a7a90 100644 --- a/src/QGCApplication.cc +++ b/src/QGCApplication.cc @@ -320,8 +320,6 @@ void QGCApplication::init() if (!_runningUnitTests) { _initForNormalAppBoot(); - } else { - AudioOutput::instance()->setMuted(true); } } @@ -332,6 +330,7 @@ void QGCApplication::_initForNormalAppBoot() QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); #endif + QGCCorePlugin::instance(); // CorePlugin must be initialized before VideoManager for Video Cleanup VideoManager::instance(); // GStreamer must be initialized before QmlEngine QQuickStyle::setStyle("Basic"); @@ -346,12 +345,11 @@ void QGCApplication::_initForNormalAppBoot() LinkManager::instance()->init(); MultiVehicleManager::instance()->init(); MAVLinkProtocol::instance()->init(); + VideoManager::instance()->init(); // Image provider for Optical Flow _qmlAppEngine->addImageProvider(qgcImageProviderId, new QGCImageProvider()); - VideoManager::instance()->init(); - // Safe to show popup error messages now that main window is created _showErrorsInToolbar = true; diff --git a/src/Settings/VideoSettings.cc b/src/Settings/VideoSettings.cc index ce10efb1988..3eb7a3eee67 100644 --- a/src/Settings/VideoSettings.cc +++ b/src/Settings/VideoSettings.cc @@ -67,27 +67,7 @@ DECLARE_SETTINGGROUP(Video, "Video") _nameToMetaDataMap[videoSourceName]->setEnumInfo(videoSourceCookedList, videoSourceList); #ifdef QGC_GST_STREAMING - const QVariantList removeForceVideoDecodeList{ -#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, - GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, -#elif defined(Q_OS_WIN) - GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, - GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, -#elif defined(Q_OS_MAC) - GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, - GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, -#elif defined(Q_OS_ANDROID) - GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, - GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, - GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, - GStreamer::VideoDecoderOptions::ForceVideoDecoderNVIDIA, -#endif - }; - - for (const auto &value : removeForceVideoDecodeList) { - _nameToMetaDataMap[forceVideoDecoderName]->removeEnumInfo(value); - } + _setForceVideoDecodeList(); #endif // Set default value for videoSource @@ -110,10 +90,8 @@ DECLARE_SETTINGSFACT(VideoSettings, showRecControl) DECLARE_SETTINGSFACT(VideoSettings, recordingFormat) DECLARE_SETTINGSFACT(VideoSettings, maxVideoSize) DECLARE_SETTINGSFACT(VideoSettings, enableStorageLimit) -DECLARE_SETTINGSFACT(VideoSettings, rtspTimeout) DECLARE_SETTINGSFACT(VideoSettings, streamEnabled) DECLARE_SETTINGSFACT(VideoSettings, disableWhenDisarmed) -DECLARE_SETTINGSFACT(VideoSettings, lowLatencyMode) DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, videoSource) { @@ -150,6 +128,42 @@ DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, forceVideoDecoder) return _forceVideoDecoderFact; } +DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, lowLatencyMode) +{ + if (!_lowLatencyModeFact) { + _lowLatencyModeFact = _createSettingsFact(lowLatencyModeName); + + _lowLatencyModeFact->setVisible( +#ifdef QGC_GST_STREAMING + true +#else + false +#endif + ); + + connect(_lowLatencyModeFact, &Fact::valueChanged, this, &VideoSettings::_configChanged); + } + return _lowLatencyModeFact; +} + +DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspTimeout) +{ + if (!_rtspTimeoutFact) { + _rtspTimeoutFact = _createSettingsFact(rtspTimeoutName); + + _rtspTimeoutFact->setVisible( +#ifdef QGC_GST_STREAMING + true +#else + false +#endif + ); + + connect(_rtspTimeoutFact, &Fact::valueChanged, this, &VideoSettings::_configChanged); + } + return _rtspTimeoutFact; +} + DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, udpPort) { if (!_udpPortFact) { @@ -235,3 +249,30 @@ void VideoSettings::_configChanged(QVariant) { emit streamConfiguredChanged(streamConfigured()); } + +#ifdef QGC_GST_STREAMING +void VideoSettings::_setForceVideoDecodeList() +{ + const QVariantList removeForceVideoDecodeList{ +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, +#elif defined(Q_OS_WIN) + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, +#elif defined(Q_OS_MAC) + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, +#elif defined(Q_OS_ANDROID) + GStreamer::VideoDecoderOptions::ForceVideoDecoderDirectX3D, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVideoToolbox, + GStreamer::VideoDecoderOptions::ForceVideoDecoderVAAPI, + GStreamer::VideoDecoderOptions::ForceVideoDecoderNVIDIA, +#endif + }; + + for (const auto &value : removeForceVideoDecodeList) { + _nameToMetaDataMap[forceVideoDecoderName]->removeEnumInfo(value); + } +} +#endif diff --git a/src/Settings/VideoSettings.h b/src/Settings/VideoSettings.h index 51437f6cb86..20ceb1680a8 100644 --- a/src/Settings/VideoSettings.h +++ b/src/Settings/VideoSettings.h @@ -73,6 +73,9 @@ private slots: private: void _setDefaults (); +#ifdef QGC_GST_STREAMING + void _setForceVideoDecodeList(); +#endif private: bool _noVideo = false; diff --git a/src/VideoManager/VideoManager.cc b/src/VideoManager/VideoManager.cc index 729c25479da..06c669e2936 100644 --- a/src/VideoManager/VideoManager.cc +++ b/src/VideoManager/VideoManager.cc @@ -58,31 +58,17 @@ VideoManager::VideoManager(QObject *parent) { // qCDebug(VideoManagerLog) << Q_FUNC_INFO << this; - if (qgcApp()->runningUnitTests()) { - return; - } +#ifdef QGC_GST_STREAMING + GStreamer::initialize(); +#endif } VideoManager::~VideoManager() { for (VideoReceiverData &videoReceiver : _videoReceiverData) { - if (videoReceiver.receiver != nullptr) { - delete videoReceiver.receiver; - videoReceiver.receiver = nullptr; - } - - if (videoReceiver.sink != nullptr) { - // QGCCorePlugin::instance()->releaseVideoSink(videoReceiver.sink); -#ifdef QGC_GST_STREAMING - // FIXME: AV: we need some interaface for video sink with .release() call - // Currently VideoManager is destroyed after corePlugin() and we are crashing on app exit - // calling QGCCorePlugin::instance()->releaseVideoSink(_videoSink[i]); - // As for now let's call GStreamer::releaseVideoSink() directly - GStreamer::releaseVideoSink(videoReceiver.sink); -#elif defined(QGC_QT_STREAMING) - QtMultimediaReceiver::releaseVideoSink(videoReceiver.sink); -#endif - } + QGCCorePlugin::instance()->releaseVideoSink(videoReceiver.sink); + delete videoReceiver.receiver; + videoReceiver.receiver = nullptr; } // qCDebug(VideoManagerLog) << Q_FUNC_INFO << this; @@ -97,10 +83,7 @@ void VideoManager::registerQmlTypes() { (void) qmlRegisterUncreatableType("QGroundControl.VideoManager", 1, 0, "VideoManager", "Reference only"); (void) qmlRegisterUncreatableType("QGroundControl", 1, 0, "VideoReceiver","Reference only"); - #ifdef QGC_GST_STREAMING - GStreamer::initialize(); - GStreamer::blacklist(static_cast(SettingsManager::instance()->videoSettings()->forceVideoDecoder()->rawValue().toInt())); - #else + #ifndef QGC_GST_STREAMING (void) qmlRegisterType("org.freedesktop.gstreamer.Qt6GLVideoItem", 1, 0, "GstGLQt6VideoItem"); #endif } @@ -111,10 +94,6 @@ void VideoManager::init() return; } -#ifdef QGC_GST_STREAMING - -#endif - // TODO: Those connections should be Per Video, not per VideoManager. (void) connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged); (void) connect(_videoSettings->udpPort(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged); @@ -125,19 +104,22 @@ void VideoManager::init() (void) connect(MultiVehicleManager::instance(), &MultiVehicleManager::activeVehicleChanged, this, &VideoManager::_setActiveVehicle); int index = 0; + const QStringList widgetTypes = {"videoContent", "thermalVideo"}; + Q_ASSERT(widgetTypes.length() <= _videoReceiverData.length()); for (VideoReceiverData &videoReceiver : _videoReceiverData) { videoReceiver.index = index++; videoReceiver.receiver = QGCCorePlugin::instance()->createVideoReceiver(this); if (!videoReceiver.receiver) { continue; } + videoReceiver.name = widgetTypes[videoReceiver.index]; (void) connect(videoReceiver.receiver, &VideoReceiver::onStartComplete, this, [this, &videoReceiver](VideoReceiver::STATUS status) { qCDebug(VideoManagerLog) << "Video" << videoReceiver.index << "Start complete, status:" << status; switch (status) { case VideoReceiver::STATUS_OK: videoReceiver.started = true; - if (videoReceiver.sink != nullptr) { + if (videoReceiver.sink) { videoReceiver.receiver->startDecoding(videoReceiver.sink); } break; @@ -231,14 +213,14 @@ void VideoManager::startVideo() return; } - for (VideoReceiverData &videoReceiver : _videoReceiverData) { + for (const VideoReceiverData &videoReceiver : _videoReceiverData) { _startReceiver(videoReceiver.index); } } void VideoManager::stopVideo() { - for (VideoReceiverData &videoReceiver : _videoReceiverData) { + for (const VideoReceiverData &videoReceiver : _videoReceiverData) { _stopReceiver(videoReceiver.index); } } @@ -246,7 +228,7 @@ void VideoManager::stopVideo() void VideoManager::startRecording(const QString &videoFile) { const VideoReceiver::FILE_FORMAT fileFormat = static_cast(_videoSettings->recordingFormat()->rawValue().toInt()); - if (fileFormat < VideoReceiver::FILE_FORMAT_MIN || fileFormat >= VideoReceiver::FILE_FORMAT_MAX) { + if ((fileFormat < VideoReceiver::FILE_FORMAT_MIN) || (fileFormat >= VideoReceiver::FILE_FORMAT_MAX)) { qgcApp()->showAppMessage(tr("Invalid video format defined.")); return; } @@ -393,7 +375,7 @@ bool VideoManager::isStreamSource() const VideoSettings::videoSourceHerelinkHotspot, }; const QString videoSource = _videoSettings->videoSource()->rawValue().toString(); - return videoSourceList.contains(videoSource) || autoStreamConfigured(); + return (videoSourceList.contains(videoSource) || autoStreamConfigured()); } bool VideoManager::isUvc() const @@ -445,25 +427,27 @@ void VideoManager::setfullScreen(bool on) void VideoManager::_initVideo() { QQuickWindow *const root = qgcApp()->mainRootWindow(); - if (root == nullptr) { + if (!root) { qCDebug(VideoManagerLog) << "mainRootWindow() failed. No root window"; return; } - const QStringList widgetTypes = {"videoContent", "thermalVideo"}; for (VideoReceiverData &videoReceiver : _videoReceiverData) { - QQuickItem* const widget = root->findChild(widgetTypes.at(videoReceiver.index)); - if ((widget != nullptr) && (videoReceiver.receiver != nullptr)) { - videoReceiver.sink = QGCCorePlugin::instance()->createVideoSink(this, widget); - if (videoReceiver.sink != nullptr) { - if (videoReceiver.started) { - videoReceiver.receiver->startDecoding(videoReceiver.sink); - } - } else { - qCDebug(VideoManagerLog) << "createVideoSink() failed" << videoReceiver.index; - } - } else { - qCDebug(VideoManagerLog) << widgetTypes.at(videoReceiver.index) << "receiver disabled"; + QQuickItem* const widget = root->findChild(videoReceiver.name); + if (!widget || !videoReceiver.receiver) { + qCDebug(VideoManagerLog) << videoReceiver.name << "receiver disabled"; + continue; + } + + videoReceiver.sink = QGCCorePlugin::instance()->createVideoSink(this, widget); + if (!videoReceiver.sink) { + qCDebug(VideoManagerLog) << "createVideoSink() failed" << videoReceiver.index; + continue; + } + + if (videoReceiver.started) { + qCDebug(VideoManagerLog) << videoReceiver.name << "receiver start decoding"; + videoReceiver.receiver->startDecoding(videoReceiver.sink); } } } @@ -486,20 +470,22 @@ void VideoManager::_cleanupOldVideos() videoDir.setNameFilters(nameFilters); QFileInfoList vidList = videoDir.entryInfoList(); - if (!vidList.isEmpty()) { - uint64_t total = 0; - for (int i = 0; i < vidList.size(); i++) { - total += vidList[i].size(); - } + if (vidList.isEmpty()) { + return; + } - const uint64_t maxSize = SettingsManager::instance()->videoSettings()->maxVideoSize()->rawValue().toUInt() * qPow(1024, 2); - while ((total >= maxSize) && !vidList.isEmpty()) { - total -= vidList.last().size(); - qCDebug(VideoManagerLog) << "Removing old video file:" << vidList.last().filePath(); - QFile file(vidList.last().filePath()); - (void) file.remove(); - vidList.removeLast(); - } + uint64_t total = 0; + for (const QFileInfo &video : vidList) { + total += video.size(); + } + + const uint64_t maxSize = SettingsManager::instance()->videoSettings()->maxVideoSize()->rawValue().toUInt() * qPow(1024, 2); + while ((total >= maxSize) && !vidList.isEmpty()) { + total -= vidList.last().size(); + qCDebug(VideoManagerLog) << "Removing old video file:" << vidList.last().filePath(); + QFile file(vidList.last().filePath()); + (void) file.remove(); + vidList.removeLast(); } } @@ -534,7 +520,7 @@ bool VideoManager::_updateUVC() } else { const QString videoSource = _videoSettings->videoSource()->rawValue().toString(); const QList videoInputs = QMediaDevices::videoInputs(); - for (const auto& cameraDevice: videoInputs) { + for (const QCameraDevice &cameraDevice: videoInputs) { if (cameraDevice.description() == videoSource) { _uvcVideoSourceID = cameraDevice.description(); qCDebug(VideoManagerLog) << "Found USB source:" << _uvcVideoSourceID << " Name:" << videoSource; @@ -547,7 +533,7 @@ bool VideoManager::_updateUVC() qCDebug(VideoManagerLog) << "UVC changed from [" << oldUvcVideoSrcID << "] to [" << _uvcVideoSourceID << "]"; const QCameraPermission cameraPermission; if (qgcApp()->checkPermission(cameraPermission) == Qt::PermissionStatus::Undetermined) { - qgcApp()->requestPermission(cameraPermission, [this](const QPermission &permission) { + qgcApp()->requestPermission(cameraPermission, [](const QPermission &permission) { if (permission.status() == Qt::PermissionStatus::Granted) { qgcApp()->showRebootAppMessage(tr("Restart application for changes to take effect.")); } @@ -744,7 +730,7 @@ void VideoManager::_startReceiver(unsigned id) return; } - if (_videoReceiverData[id].receiver == nullptr) { + if (!_videoReceiverData[id].receiver) { qCDebug(VideoManagerLog) << "VideoReceiver is NULL" << id; return; } @@ -758,7 +744,7 @@ void VideoManager::_startReceiver(unsigned id) const unsigned rtsptimeout = _videoSettings->rtspTimeout()->rawValue().toUInt(); /* The gstreamer rtsp source will switch to tcp if udp is not available after 5 seconds. So we should allow for some negotiation time for rtsp */ - const unsigned timeout = (source == VideoSettings::videoSourceRTSP ? rtsptimeout : 2); + const unsigned timeout = (source == VideoSettings::videoSourceRTSP ? rtsptimeout : 3); _videoReceiverData[id].receiver->start(_videoReceiverData[id].uri, timeout, _videoReceiverData[id].lowLatencyStreaming ? -1 : 0); } diff --git a/src/VideoManager/VideoManager.h b/src/VideoManager/VideoManager.h index db31eecbf9f..3e4f92a664d 100644 --- a/src/VideoManager/VideoManager.h +++ b/src/VideoManager/VideoManager.h @@ -131,6 +131,7 @@ private slots: bool started = false; bool lowLatencyStreaming = false; size_t index = 0; + QString name; }; QList _videoReceiverData = QList(MAX_VIDEO_RECEIVERS); diff --git a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc index f89235ed353..a57471689ee 100644 --- a/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc +++ b/src/VideoManager/VideoReceiver/GStreamer/GStreamer.cc @@ -9,7 +9,9 @@ #include "GStreamer.h" #include "GstVideoReceiver.h" +#include "SettingsManager.h" #include "AppSettings.h" +#include "VideoSettings.h" #include "QGCLoggingCategory.h" #ifdef Q_OS_IOS #include "gst_ios_init.h" @@ -207,6 +209,8 @@ void initialize() GST_PLUGIN_STATIC_REGISTER(qml6); GST_PLUGIN_STATIC_REGISTER(qgc); + + blacklist(static_cast(SettingsManager::instance()->videoSettings()->forceVideoDecoder()->rawValue().toInt())); } void blacklist(VideoDecoderOptions option)