Skip to content

Commit

Permalink
VideoManager: Minor Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey committed Dec 21, 2024
1 parent 523403d commit 5ec94e7
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 91 deletions.
6 changes: 2 additions & 4 deletions src/QGCApplication.cc
Original file line number Diff line number Diff line change
Expand Up @@ -320,8 +320,6 @@ void QGCApplication::init()

if (!_runningUnitTests) {
_initForNormalAppBoot();
} else {
AudioOutput::instance()->setMuted(true);
}
}

Expand All @@ -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");
Expand All @@ -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;

Expand Down
87 changes: 64 additions & 23 deletions src/Settings/VideoSettings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
{
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
3 changes: 3 additions & 0 deletions src/Settings/VideoSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ private slots:

private:
void _setDefaults ();
#ifdef QGC_GST_STREAMING
void _setForceVideoDecodeList();
#endif

private:
bool _noVideo = false;
Expand Down
114 changes: 50 additions & 64 deletions src/VideoManager/VideoManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -97,10 +83,7 @@ void VideoManager::registerQmlTypes()
{
(void) qmlRegisterUncreatableType<VideoManager>("QGroundControl.VideoManager", 1, 0, "VideoManager", "Reference only");
(void) qmlRegisterUncreatableType<VideoReceiver>("QGroundControl", 1, 0, "VideoReceiver","Reference only");
#ifdef QGC_GST_STREAMING
GStreamer::initialize();
GStreamer::blacklist(static_cast<GStreamer::VideoDecoderOptions>(SettingsManager::instance()->videoSettings()->forceVideoDecoder()->rawValue().toInt()));
#else
#ifndef QGC_GST_STREAMING
(void) qmlRegisterType<GLVideoItemStub>("org.freedesktop.gstreamer.Qt6GLVideoItem", 1, 0, "GstGLQt6VideoItem");
#endif
}
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -231,22 +213,22 @@ 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);
}
}

void VideoManager::startRecording(const QString &videoFile)
{
const VideoReceiver::FILE_FORMAT fileFormat = static_cast<VideoReceiver::FILE_FORMAT>(_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;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<QQuickItem*>(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<QQuickItem*>(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);
}
}
}
Expand All @@ -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();
}
}

Expand Down Expand Up @@ -534,7 +520,7 @@ bool VideoManager::_updateUVC()
} else {
const QString videoSource = _videoSettings->videoSource()->rawValue().toString();
const QList<QCameraDevice> 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;
Expand All @@ -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."));
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
}
Expand Down
1 change: 1 addition & 0 deletions src/VideoManager/VideoManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ private slots:
bool started = false;
bool lowLatencyStreaming = false;
size_t index = 0;
QString name;
};
QList<VideoReceiverData> _videoReceiverData = QList<VideoReceiverData>(MAX_VIDEO_RECEIVERS);

Expand Down
Loading

0 comments on commit 5ec94e7

Please sign in to comment.