Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 112 additions & 33 deletions src/FlightDisplay/FlightDisplayViewVideo.qml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ Item {
visible: QGroundControl.videoManager.decoding
function getWidth() {
if(_ar != 0.0){
if(_isMode_FIT_HEIGHT
if(_isMode_FIT_HEIGHT
|| (_isMode_FILL && (root.width/root.height < _ar))
|| (_isMode_NO_CROP && (root.width/root.height > _ar))){
// This return value has different implications depending on the mode
Expand All @@ -100,8 +100,8 @@ Item {
}
function getHeight() {
if(_ar != 0.0){
if(_isMode_FIT_WIDTH
|| (_isMode_FILL && (root.width/root.height > _ar))
if(_isMode_FIT_WIDTH
|| (_isMode_FILL && (root.width/root.height > _ar))
|| (_isMode_NO_CROP && (root.width/root.height < _ar))){
// This return value has different implications depending on the mode
// For FIT_WIDTH and FILL
Expand Down Expand Up @@ -173,42 +173,121 @@ Item {
property bool videoDisabled: QGroundControl.settingsManager.videoSettings.videoSource.rawValue === QGroundControl.settingsManager.videoSettings.disabledVideoSource
}

//-- Thermal Image
//-- Backup Image
Item {
id: thermalItem
width: height * QGroundControl.videoManager.thermalAspectRatio
height: _camera ? (_camera.thermalMode === MavlinkCameraControl.THERMAL_FULL ? parent.height : (_camera.thermalMode === MavlinkCameraControl.THERMAL_PIP ? ScreenTools.defaultFontPixelHeight * 12 : parent.height * _thermalHeightFactor)) : 0
anchors.centerIn: parent
visible: QGroundControl.videoManager.hasThermal && _camera.thermalMode !== MavlinkCameraControl.THERMAL_OFF
function pipOrNot() {
if(_camera) {
if(_camera.thermalMode === MavlinkCameraControl.THERMAL_PIP) {
anchors.centerIn = undefined
anchors.top = parent.top
anchors.topMargin = mainWindow.header.height + (ScreenTools.defaultFontPixelHeight * 0.5)
anchors.left = parent.left
anchors.leftMargin = ScreenTools.defaultFontPixelWidth * 12
} else {
anchors.top = undefined
anchors.topMargin = undefined
anchors.left = undefined
anchors.leftMargin = undefined
anchors.centerIn = parent
}
}
id: backupItem
width: height * QGroundControl.videoManager.aspectRatio
height: parent.height / 4
visible: QGroundControl.settingsManager.videoSettings.rtspUrlBackup.rawValue !== "" && QGroundControl.videoManager.decoding
anchors.centerIn : undefined
anchors.verticalCenter: parent.verticalCenter
anchors.left : parent.left

function undefinePosition() {
anchors.centerIn = undefined
anchors.horizontalCenter = undefined
anchors.top = undefined
anchors.bottom = undefined
anchors.verticalCenter = undefined
anchors.left = undefined
anchors.right = undefined
}
Connections {
target: _camera
function onThermalModeChanged() { thermalItem.pipOrNot() }

function leftPosition() {
undefinePosition()

anchors.verticalCenter = parent.verticalCenter
anchors.left = parent.left
}
onVisibleChanged: {
thermalItem.pipOrNot()

function rightPosition() {
undefinePosition()
anchors.verticalCenter = parent.verticalCenter
anchors.right = parent.right
}

function topPosition() {
undefinePosition()
anchors.horizontalCenter = parent.horizontalCenter
anchors.top = parent.top
}

function bottomPosition() {
undefinePosition()
anchors.horizontalCenter = parent.horizontalCenter
anchors.bottom = parent.bottom
}

QGCVideoBackground {
id: thermalVideo
objectName: "thermalVideo"
id: backupVideo
objectName: "backupVideo"
anchors.fill: parent
opacity: _camera ? (_camera.thermalMode === MavlinkCameraControl.THERMAL_BLEND ? _camera.thermalOpacity / 100 : 1.0) : 0
opacity: 1.0
}

ToolTip {
delay: 1000
timeout: 3000
visible: parent.visible
anchors.centerIn: parent.centerIn
text: qsTr("Right-click to open control menu")
}

MouseArea {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: backupItemPositionMenu.popup()
}

QGCMenu {
id: backupItemPositionMenu

property bool hasAuxStream: QGroundControl.videoManager.hasAuxStream
property bool usesPrimaryStream: QGroundControl.videoManager.isPrimaryStream

QGCMenuItem {
text: qsTr("Left")
onTriggered: backupItem.leftPosition()
}

QGCMenuItem {
text: qsTr("Right")
onTriggered: backupItem.rightPosition()
}

QGCMenuItem {
text: qsTr("Top")
onTriggered: backupItem.topPosition()
}

QGCMenuItem {
text: qsTr("Bottom")
onTriggered: backupItem.bottomPosition()
}

QGCMenuSeparator {
visible: true // should be visible when backup stream is configured
}

QGCMenuItem {
id: switchStreamMenuItem
text: qsTr("Switch video streams")
visible: true
enabled: false
onTriggered: QGroundControl.videoManager.isPrimaryStream = !QGroundControl.videoManager.isPrimaryStream
}

onHasAuxStreamChanged: {
switchStreamMenuItem.enabled = hasAuxStream
}

onUsesPrimaryStreamChanged: {
if (usesPrimaryStream) {
switchStreamMenuItem.text = qsTr("Switch to auxiliary video stream")
} else {
switchStreamMenuItem.text = qsTr("Switch to primary video stream")
}
}
}
}
//-- Zoom
Expand Down
28 changes: 28 additions & 0 deletions src/Settings/Video.SettingsGroup.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,34 @@
"type": "string",
"default": ""
},
{
"name": "rtspUrlBackup",
"shortDesc": "Backup Video RTSP Url",
"longDesc": "Backup RTSP url address and port to bind to for video stream. Example: rtsp://192.168.42.1:554/live",
"type": "string",
"default": ""
},
{
"name": "rtspUseAux",
"shortDesc": "Enable auxiliary video streams",
"longDesc": "Enable auxiliary RTSP video streams and add possibility to switch between primary and aux ones",
"type": "bool",
"default": false
},
{
"name": "rtspUrlAux",
"shortDesc": "Video RTSP Url Aux",
"longDesc": "Additional RTSP url address and port to bind to for video stream. Example: rtsp://192.168.42.1:554/live",
"type": "string",
"default": ""
},
{
"name": "rtspUrlBackupAux",
"shortDesc": "Backup Video RTSP Url Aux",
"longDesc": "Additional backup RTSP url address and port to bind to for video stream. Example: rtsp://192.168.42.1:554/live",
"type": "string",
"default": ""
},
{
"name": "tcpUrl",
"shortDesc": "Video TCP Url",
Expand Down
69 changes: 65 additions & 4 deletions src/Settings/VideoSettings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,38 @@ DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUrl)
return _rtspUrlFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUrlBackup) {
if (!_rtspUrlBackupFact) {
_rtspUrlBackupFact = _createSettingsFact(rtspUrlBackupName);
connect(_rtspUrlBackupFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
return _rtspUrlBackupFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUseAux) {
if (!_rtspUseAuxFact) {
_rtspUseAuxFact = _createSettingsFact(rtspUseAuxName);
connect(_rtspUseAuxFact, &Fact::valueChanged, this, &VideoSettings::_auxConfigChanged);
}
return _rtspUseAuxFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUrlAux) {
if (!_rtspUrlAuxFact) {
_rtspUrlAuxFact = _createSettingsFact(rtspUrlAuxName);
connect(_rtspUrlAuxFact, &Fact::valueChanged, this, &VideoSettings::_auxConfigChanged);
}
return _rtspUrlAuxFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUrlBackupAux) {
if (!_rtspUrlBackupAuxFact) {
_rtspUrlBackupAuxFact = _createSettingsFact(rtspUrlBackupAuxName);
connect(_rtspUrlBackupAuxFact, &Fact::valueChanged, this, &VideoSettings::_auxConfigChanged);
}
return _rtspUrlBackupAuxFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, tcpUrl)
{
if (!_tcpUrlFact) {
Expand All @@ -199,22 +231,22 @@ bool VideoSettings::streamConfigured(void)
//-- If UDP, check for URL
if(vSource == videoSourceUDPH264 || vSource == videoSourceUDPH265) {
qCDebug(VideoManagerLog) << "Testing configuration for UDP Stream:" << udpUrl()->rawValue().toString();
return !udpUrl()->rawValue().toString().isEmpty();
return _isConfigured(udpUrl());
}
//-- If RTSP, check for URL
if(vSource == videoSourceRTSP) {
qCDebug(VideoManagerLog) << "Testing configuration for RTSP Stream:" << rtspUrl()->rawValue().toString();
return !rtspUrl()->rawValue().toString().isEmpty();
return _isConfigured(rtspUrl());
}
//-- If TCP, check for URL
if(vSource == videoSourceTCP) {
qCDebug(VideoManagerLog) << "Testing configuration for TCP Stream:" << tcpUrl()->rawValue().toString();
return !tcpUrl()->rawValue().toString().isEmpty();
return _isConfigured(tcpUrl());
}
//-- If MPEG-TS, check for URL
if(vSource == videoSourceMPEGTS) {
qCDebug(VideoManagerLog) << "Testing configuration for MPEG-TS Stream:" << udpUrl()->rawValue().toString();
return !udpUrl()->rawValue().toString().isEmpty();
return _isConfigured(udpUrl());
}
//-- If Herelink Air unit, good to go
if(vSource == videoSourceHerelinkAirUnit) {
Expand All @@ -235,11 +267,32 @@ bool VideoSettings::streamConfigured(void)
return false;
}

bool VideoSettings::auxStreamConfigured()
{
QString vSource = videoSource()->rawValue().toString();
if(vSource != videoSourceRTSP || !rtspUseAux()->rawValue().toBool()) {
return false;
}

const bool primaryConfigured = _isConfigured(rtspUrl());
const bool backupConfigured = _isConfigured(rtspUrlBackup());

const bool auxConfigured = primaryConfigured ? _isConfigured(rtspUrlAux()) : false;
const bool auxBackupConfigured = backupConfigured ? _isConfigured(rtspUrlBackupAux()) : false;

return auxConfigured || auxBackupConfigured;
}

void VideoSettings::_configChanged(QVariant)
{
emit streamConfiguredChanged(streamConfigured());
}

void VideoSettings::_auxConfigChanged(QVariant)
{
emit auxStreamConfiguredChanged(auxStreamConfigured());
}

void VideoSettings::_setForceVideoDecodeList()
{
#ifdef QGC_GST_STREAMING
Expand Down Expand Up @@ -272,3 +325,11 @@ void VideoSettings::_setForceVideoDecodeList()
}
#endif
}

bool VideoSettings::_isConfigured(const Fact* parameter)
{
if (!parameter)
return false;

return !parameter->rawValue().toString().isEmpty();
}
12 changes: 10 additions & 2 deletions src/Settings/VideoSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class VideoSettings : public SettingsGroup
DEFINE_SETTINGFACT(udpUrl)
DEFINE_SETTINGFACT(tcpUrl)
DEFINE_SETTINGFACT(rtspUrl)
DEFINE_SETTINGFACT(rtspUrlBackup)
DEFINE_SETTINGFACT(rtspUseAux)
DEFINE_SETTINGFACT(rtspUrlAux)
DEFINE_SETTINGFACT(rtspUrlBackupAux)
DEFINE_SETTINGFACT(aspectRatio)
DEFINE_SETTINGFACT(videoFit)
DEFINE_SETTINGFACT(gridLines)
Expand All @@ -48,6 +52,7 @@ class VideoSettings : public SettingsGroup
Q_PROPERTY(QString disabledVideoSource READ disabledVideoSource CONSTANT)

bool streamConfigured ();
bool auxStreamConfigured ();
QString rtspVideoSource () { return videoSourceRTSP; }
QString udp264VideoSource () { return videoSourceUDPH264; }
QString udp265VideoSource () { return videoSourceUDPH265; }
Expand All @@ -69,14 +74,17 @@ class VideoSettings : public SettingsGroup
static constexpr const char* videoSourceHerelinkHotspot = QT_TRANSLATE_NOOP("VideoSettings", "Herelink Hotspot");

signals:
void streamConfiguredChanged (bool configured);
void streamConfiguredChanged(bool configured);
void auxStreamConfiguredChanged(bool configured);

private slots:
void _configChanged (QVariant value);
void _configChanged(QVariant value);
void _auxConfigChanged(QVariant value);

private:
void _setDefaults ();
void _setForceVideoDecodeList();
static bool _isConfigured(const Fact* parameter);

private:
bool _noVideo = false;
Expand Down
32 changes: 32 additions & 0 deletions src/UI/AppSettings/VideoSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,38 @@ SettingsPage {
visible: _isRTSP && _videoSettings.rtspUrl.visible
}

LabelledFactTextField {
Layout.fillWidth: true
textFieldPreferredWidth: _urlFieldWidth
label: qsTr("RTSP URL Backup")
fact: _videoSettings.rtspUrlBackup
visible: _isRTSP && _videoSettings.rtspUrlBackup.visible
}

FactCheckBoxSlider {
id: auxStreamCheckBox
Layout.fillWidth: true
text: fact.shortDescription
fact: _videoSettings.rtspUseAux
visible: fact.visible
}

LabelledFactTextField {
Layout.fillWidth: true
textFieldPreferredWidth: _urlFieldWidth
label: qsTr("Aux RTSP URL")
fact: _videoSettings.rtspUrlAux
visible: _isRTSP && _videoSettings.rtspUrlAux.visible && auxStreamCheckBox.checked
}

LabelledFactTextField {
Layout.fillWidth: true
textFieldPreferredWidth: _urlFieldWidth
label: qsTr("Aux RTSP URL Backup")
fact: _videoSettings.rtspUrlBackupAux
visible: _isRTSP && _videoSettings.rtspUrlBackupAux.visible && auxStreamCheckBox.checked
}

LabelledFactTextField {
Layout.fillWidth: true
label: qsTr("TCP URL")
Expand Down
Loading
Loading