diff --git a/.travis.yml b/.travis.yml
index d49f311900fc456d7a55f7cb3699f87862fa0372..dcac7c7693a6b2c08b81332a9d9a0f6000cef286 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -116,11 +116,23 @@ install:
# osx dependencies: qt, gstreamer, gstreamer-devel
- if [ "${SPEC}" = "macx-clang" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/Qt5.9.1-mac-clang-min.tar.bz2 &&
- tar jxf Qt5.9.1-mac-clang-min.tar.bz2 -C /tmp &&
+ tar jxf Qt5.9.1-mac-clang-min.tar.bz2 -C /tmp
+ ;
+ fi
+
+ - if [ "${SPEC}" = "macx-clang" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/gstreamer-1.0-1.5.2-x86_64.pkg &&
- sudo installer -verboseR -pkg gstreamer-1.0-1.5.2-x86_64.pkg -target / &&
+ sudo installer -verboseR -pkg gstreamer-1.0-1.5.2-x86_64.pkg -target /
+ ;
+ fi
+
+ - if [ "${SPEC}" = "macx-clang" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/gstreamer-1.0-devel-1.5.2-x86_64.pkg &&
- sudo installer -verboseR -pkg gstreamer-1.0-devel-1.5.2-x86_64.pkg -target / &&
+ sudo installer -verboseR -pkg gstreamer-1.0-devel-1.5.2-x86_64.pkg -target /
+ ;
+ fi
+
+ - if [ "${SPEC}" = "macx-clang" ]; then
wget --quiet https://s3-us-west-2.amazonaws.com/qgroundcontrol/dependencies/osx-gstreamer.tar.bz2 &&
sudo tar jxf osx-gstreamer.tar.bz2 -C /Library/Frameworks &&
export QT_DIR=Qt5.9-mac-clang/5.9.1/clang_64 &&
diff --git a/qgroundcontrol.qrc b/qgroundcontrol.qrc
index 5a743baf9caed70fc9b10fd98611dd23a4dd7f83..8fccc74e16e2f4a7e24dbc7d3ed0c096ec67beef 100644
--- a/qgroundcontrol.qrc
+++ b/qgroundcontrol.qrc
@@ -92,6 +92,7 @@
src/QmlControls/QGCPipable.qml
src/QmlControls/QGCRadioButton.qml
src/QmlControls/QGCSlider.qml
+ src/QmlControls/QGCSwitch.qml
src/QmlControls/QGCTextField.qml
src/QmlControls/QGCToolBarButton.qml
src/QmlControls/QGCView.qml
@@ -179,6 +180,7 @@
src/VehicleSetup/VehicleSummary.qml
src/FlightDisplay/VirtualJoystick.qml
src/FlightMap/Widgets/CameraPageWidget.qml
+ src/FlightMap/Widgets/VideoPageWidget.qml
src/FlightMap/Widgets/ValuePageWidget.qml
src/FlightMap/Widgets/HealthPageWidget.qml
src/FlightMap/Widgets/VibrationPageWidget.qml
diff --git a/src/FlightDisplay/FlightDisplayView.qml b/src/FlightDisplay/FlightDisplayView.qml
index 3c87dc13aa576040dca443faee06d60d178dd8a3..e2ff0b2348db9aac725d564c915d67363258ca0c 100644
--- a/src/FlightDisplay/FlightDisplayView.qml
+++ b/src/FlightDisplay/FlightDisplayView.qml
@@ -43,8 +43,6 @@ QGCView {
property var _geoFenceController: _planMasterController.geoFenceController
property var _rallyPointController: _planMasterController.rallyPointController
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
- property var _videoReceiver: QGroundControl.videoManager.videoReceiver
- property bool _recordingVideo: _videoReceiver && _videoReceiver.recording
property bool _mainIsMap: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_mainIsMapKey, true) : true
property bool _isPipVisible: QGroundControl.videoManager.hasVideo ? QGroundControl.loadBoolGlobalSetting(_PIPVisibleKey, true) : false
property real _savedZoomLevel: 0
@@ -346,63 +344,6 @@ QGCView {
property var qgcView: root
}
- // Button to start/stop video recording
- Item {
- z: _flightVideoPipControl.z + 1
- anchors.margins: ScreenTools.defaultFontPixelHeight / 2
- anchors.bottom: _flightVideo.bottom
- anchors.right: _flightVideo.right
- height: ScreenTools.defaultFontPixelHeight * 2
- width: height
- visible: _videoReceiver && _videoReceiver.videoRunning && QGroundControl.settingsManager.videoSettings.showRecControl.rawValue && _flightVideo.visible && !_isCamera && !QGroundControl.videoManager.fullScreen
- opacity: 0.75
-
- readonly property string recordBtnBackground: "BackgroundName"
-
- Rectangle {
- id: recordBtnBackground
- anchors.top: parent.top
- anchors.bottom: parent.bottom
- width: height
- radius: _recordingVideo ? 0 : height
- color: "red"
-
- SequentialAnimation on visible {
- running: _recordingVideo
- loops: Animation.Infinite
- PropertyAnimation { to: false; duration: 1000 }
- PropertyAnimation { to: true; duration: 1000 }
- }
- }
-
- QGCColoredImage {
- anchors.top: parent.top
- anchors.bottom: parent.bottom
- anchors.horizontalCenter: parent.horizontalCenter
- width: height * 0.625
- sourceSize.width: width
- source: "/qmlimages/CameraIcon.svg"
- visible: recordBtnBackground.visible
- fillMode: Image.PreserveAspectFit
- color: "white"
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (_videoReceiver) {
- if (_recordingVideo) {
- _videoReceiver.stopRecording()
- // reset blinking animation
- recordBtnBackground.visible = true
- } else {
- _videoReceiver.startRecording()
- }
- }
- }
- }
- }
-
MultiVehicleList {
anchors.margins: _margins
anchors.top: singleMultiSelector.bottom
diff --git a/src/FlightDisplay/FlightDisplayViewVideo.qml b/src/FlightDisplay/FlightDisplayViewVideo.qml
index a3d39fd822ec9bea0fb79623ba108d0956c28810..0ed7eed06c52d2d51be399a794aa5108e788aa5d 100644
--- a/src/FlightDisplay/FlightDisplayViewVideo.qml
+++ b/src/FlightDisplay/FlightDisplayViewVideo.qml
@@ -34,7 +34,7 @@ Item {
color: Qt.rgba(0,0,0,0.75)
visible: !(_videoReceiver && _videoReceiver.videoRunning)
QGCLabel {
- text: qsTr("WAITING FOR VIDEO")
+ text: QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue ? qsTr("WAITING FOR VIDEO") : qsTr("VIDEO DISABLED")
font.family: ScreenTools.demiboldFontFamily
color: "white"
font.pointSize: _mainIsMap ? ScreenTools.smallFontPointSize : ScreenTools.largeFontPointSize
diff --git a/src/FlightDisplay/FlightDisplayViewWidgets.qml b/src/FlightDisplay/FlightDisplayViewWidgets.qml
index 4caab475fca7838b6de1b5eaea18c8212f650e5b..7f9751123eda24fa070d565eaa54d6fd398dcc47 100644
--- a/src/FlightDisplay/FlightDisplayViewWidgets.qml
+++ b/src/FlightDisplay/FlightDisplayViewWidgets.qml
@@ -40,7 +40,7 @@ Item {
function getPreferredInstrumentWidth() {
if(ScreenTools.isMobile) {
- return ScreenTools.isTinyScreen ? mainWindow.width * 0.2 : mainWindow.width * 0.15
+ return mainWindow.width * 0.25
}
return ScreenTools.defaultFontPixelWidth * 30
}
diff --git a/src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml b/src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml
index 4e2fe1dc7d3711e3b52a5ee00e4c89cd221691e4..290fec81fec381820564febe485d2dfd4644c683 100644
--- a/src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml
+++ b/src/FlightMap/Widgets/QGCInstrumentWidgetAlternate.qml
@@ -20,7 +20,7 @@ import QGroundControl.Palette 1.0
/// Instrument panel shown when virtual thumbsticks are visible
Rectangle {
id: root
- width: ScreenTools.isTinyScreen ? getPreferredInstrumentWidth() * 1.5 : getPreferredInstrumentWidth()
+ width: getPreferredInstrumentWidth()
height: _outerRadius * 2
radius: _outerRadius
color: qgcPal.window
diff --git a/src/FlightMap/Widgets/VideoPageWidget.qml b/src/FlightMap/Widgets/VideoPageWidget.qml
new file mode 100644
index 0000000000000000000000000000000000000000..10d0e6503e9577ee7784a0fcef6bae1efc2a5258
--- /dev/null
+++ b/src/FlightMap/Widgets/VideoPageWidget.qml
@@ -0,0 +1,150 @@
+/****************************************************************************
+ *
+ * (c) 2009-2016 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.4
+import QtPositioning 5.2
+import QtQuick.Layouts 1.2
+import QtQuick.Controls 1.4
+import QtQuick.Dialogs 1.2
+import QtGraphicalEffects 1.0
+
+import QGroundControl 1.0
+import QGroundControl.ScreenTools 1.0
+import QGroundControl.Controls 1.0
+import QGroundControl.Palette 1.0
+import QGroundControl.Vehicle 1.0
+import QGroundControl.Controllers 1.0
+import QGroundControl.FactSystem 1.0
+import QGroundControl.FactControls 1.0
+
+/// Video streaming page for Instrument Panel PageView
+Item {
+ width: pageWidth
+ height: videoGrid.height + (ScreenTools.defaultFontPixelHeight * 2)
+ anchors.margins: ScreenTools.defaultFontPixelWidth * 2
+ anchors.centerIn: parent
+
+ property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
+ property bool _communicationLost: _activeVehicle ? _activeVehicle.connectionLost : false
+ property var _videoReceiver: QGroundControl.videoManager.videoReceiver
+ property bool _recordingVideo: _videoReceiver && _videoReceiver.recording
+ property bool _videoRunning: _videoReceiver && _videoReceiver.videoRunning
+ property bool _streamingEnabled: QGroundControl.settingsManager.videoSettings.streamConfigured
+
+ QGCPalette { id:qgcPal; colorGroupEnabled: true }
+
+ GridLayout {
+ id: videoGrid
+ columns: 2
+ columnSpacing: ScreenTools.defaultFontPixelWidth * 2
+ rowSpacing: ScreenTools.defaultFontPixelHeight
+ anchors.centerIn: parent
+ Connections {
+ // For some reason, the normal signal is not reflected in the control below
+ target: QGroundControl.settingsManager.videoSettings.streamEnabled
+ onRawValueChanged: {
+ enableSwitch.checked = QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue
+ }
+ }
+ // Enable/Disable Video Streaming
+ QGCLabel {
+ text: qsTr("Enable Stream")
+ font.pointSize: ScreenTools.smallFontPointSize
+ }
+ QGCSwitch {
+ id: enableSwitch
+ enabled: _streamingEnabled
+ checked: QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue
+ onClicked: {
+ if(checked) {
+ QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue = 1
+ _videoReceiver.start()
+ } else {
+ QGroundControl.settingsManager.videoSettings.streamEnabled.rawValue = 0
+ _videoReceiver.stop()
+ }
+ }
+ }
+ // Grid Lines
+ QGCLabel {
+ text: qsTr("Grid Lines")
+ font.pointSize: ScreenTools.smallFontPointSize
+ visible: QGroundControl.videoManager.isGStreamer && QGroundControl.settingsManager.videoSettings.gridLines.visible
+ }
+ QGCSwitch {
+ enabled: _streamingEnabled && _activeVehicle
+ checked: QGroundControl.settingsManager.videoSettings.gridLines.rawValue
+ visible: QGroundControl.videoManager.isGStreamer && QGroundControl.settingsManager.videoSettings.gridLines.visible
+ onClicked: {
+ if(checked) {
+ QGroundControl.settingsManager.videoSettings.gridLines.rawValue = 1
+ } else {
+ QGroundControl.settingsManager.videoSettings.gridLines.rawValue = 0
+ }
+ }
+ }
+ QGCLabel {
+ text: _recordingVideo ? qsTr("Stop Recording") : qsTr("Record Stream")
+ font.pointSize: ScreenTools.smallFontPointSize
+ visible: QGroundControl.settingsManager.videoSettings.showRecControl.rawValue
+ }
+ // Button to start/stop video recording
+ Item {
+ anchors.margins: ScreenTools.defaultFontPixelHeight / 2
+ height: ScreenTools.defaultFontPixelHeight * 2
+ width: height
+ Layout.alignment: Qt.AlignHCenter
+ visible: QGroundControl.settingsManager.videoSettings.showRecControl.rawValue
+ Rectangle {
+ id: recordBtnBackground
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ width: height
+ radius: _recordingVideo ? 0 : height
+ color: (_videoRunning && _streamingEnabled) ? "red" : "gray"
+ SequentialAnimation on opacity {
+ running: _recordingVideo
+ loops: Animation.Infinite
+ PropertyAnimation { to: 0.5; duration: 500 }
+ PropertyAnimation { to: 1.0; duration: 500 }
+ }
+ }
+ QGCColoredImage {
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: height * 0.625
+ sourceSize.width: width
+ source: "/qmlimages/CameraIcon.svg"
+ visible: recordBtnBackground.visible
+ fillMode: Image.PreserveAspectFit
+ color: "white"
+ }
+ MouseArea {
+ anchors.fill: parent
+ enabled: _videoRunning && _streamingEnabled
+ onClicked: {
+ if (_recordingVideo) {
+ _videoReceiver.stopRecording()
+ // reset blinking animation
+ recordBtnBackground.opacity = 1
+ } else {
+ _videoReceiver.startRecording()
+ }
+ }
+ }
+ }
+ QGCLabel {
+ text: qsTr("Video Streaming Not Configured")
+ font.pointSize: ScreenTools.smallFontPointSize
+ visible: !_streamingEnabled
+ Layout.columnSpan: 2
+ }
+ }
+}
diff --git a/src/QmlControls/PageView.qml b/src/QmlControls/PageView.qml
index 80196383c57ca0623df00631fa437cdf9047fc53..6dfdc6cb4c2944bc81a19130e471c8b5a50ea278 100644
--- a/src/QmlControls/PageView.qml
+++ b/src/QmlControls/PageView.qml
@@ -38,7 +38,7 @@ Rectangle {
width: parent.height -(_margins * 2)
sourceSize.width: width
fillMode: Image.PreserveAspectFit
- visible: pageWidgetLoader.item.showSettingsIcon
+ visible: pageWidgetLoader.item ? (pageWidgetLoader.item.showSettingsIcon ? pageWidgetLoader.item.showSettingsIcon : false) : false
QGCMouseArea {
fillItem: parent
diff --git a/src/QmlControls/QGCSwitch.qml b/src/QmlControls/QGCSwitch.qml
new file mode 100644
index 0000000000000000000000000000000000000000..74da42b1306b40dca49bf8d1354fb5a39b589d23
--- /dev/null
+++ b/src/QmlControls/QGCSwitch.qml
@@ -0,0 +1,30 @@
+/****************************************************************************
+ *
+ * (c) 2009-2016 QGROUNDCONTROL PROJECT
+ *
+ * QGroundControl is licensed according to the terms in the file
+ * COPYING.md in the root of the source code directory.
+ *
+ ****************************************************************************/
+
+import QtQuick 2.3
+import QtQuick.Controls 1.2
+import QtQuick.Controls.Styles 1.4
+
+import QGroundControl.Palette 1.0
+import QGroundControl.ScreenTools 1.0
+
+Switch {
+ id: _root
+ QGCPalette { id:qgcPal; colorGroupEnabled: true }
+ style: SwitchStyle {
+ groove: Rectangle {
+ implicitWidth: ScreenTools.defaultFontPixelWidth * 6
+ implicitHeight: ScreenTools.defaultFontPixelHeight
+ color: (control.checked && control.enabled) ? qgcPal.colorGreen : qgcPal.colorGrey
+ radius: 3
+ border.color: qgcPal.button
+ border.width: 1
+ }
+ }
+}
diff --git a/src/QmlControls/QGroundControl.Controls.qmldir b/src/QmlControls/QGroundControl.Controls.qmldir
index ad49c42db7e48ea25142897cd184e6ab7a540404..514aeb14a92752e1b45b73e6da27990a24106432 100644
--- a/src/QmlControls/QGroundControl.Controls.qmldir
+++ b/src/QmlControls/QGroundControl.Controls.qmldir
@@ -52,6 +52,7 @@ QGCMovableItem 1.0 QGCMovableItem.qml
QGCPipable 1.0 QGCPipable.qml
QGCRadioButton 1.0 QGCRadioButton.qml
QGCSlider 1.0 QGCSlider.qml
+QGCSwitch 1.0 QGCSwitch.qml
QGCTextField 1.0 QGCTextField.qml
QGCToolBarButton 1.0 QGCToolBarButton.qml
QGCView 1.0 QGCView.qml
diff --git a/src/Settings/Video.SettingsGroup.json b/src/Settings/Video.SettingsGroup.json
index 68088d4e68c7fe160f5beed4678f8b7ed10cf0bb..20ee46b381866722d25f8381900954497fad390c 100644
--- a/src/Settings/Video.SettingsGroup.json
+++ b/src/Settings/Video.SettingsGroup.json
@@ -94,5 +94,19 @@
"min": 1,
"units": "s",
"defaultValue": 2
+},
+{
+ "name": "StreamEnabled",
+ "shortDescription": "Video Stream Enabled",
+ "longDescription": "Start/Stop Video Stream.",
+ "type": "bool",
+ "defaultValue": true
+},
+{
+ "name": "DisableWhenDisarmed",
+ "shortDescription": "Video Stream Disnabled When Armed",
+ "longDescription": "Disable Video Stream when disarmed.",
+ "type": "bool",
+ "defaultValue": false
}
]
diff --git a/src/Settings/VideoSettings.cc b/src/Settings/VideoSettings.cc
index 631a7d14a202390924513fe4984a4e38a6df3759..cb6ab514f1eeca4f5250f42d4d82017caf65d53e 100644
--- a/src/Settings/VideoSettings.cc
+++ b/src/Settings/VideoSettings.cc
@@ -30,6 +30,8 @@ const char* VideoSettings::recordingFormatName = "RecordingFormat";
const char* VideoSettings::maxVideoSizeName = "MaxVideoSize";
const char* VideoSettings::enableStorageLimitName = "EnableStorageLimit";
const char* VideoSettings::rtspTimeoutName = "RtspTimeout";
+const char* VideoSettings::streamEnabledName = "StreamEnabled";
+const char* VideoSettings::disableWhenDisarmedName ="DisableWhenDisarmed";
const char* VideoSettings::videoSourceNoVideo = "No Video Available";
const char* VideoSettings::videoDisabled = "Video Stream Disabled";
@@ -50,6 +52,8 @@ VideoSettings::VideoSettings(QObject* parent)
, _maxVideoSizeFact(NULL)
, _enableStorageLimitFact(NULL)
, _rtspTimeoutFact(NULL)
+ , _streamEnabledFact(NULL)
+ , _disableWhenDisarmedFact(NULL)
{
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType("QGroundControl.SettingsManager", 1, 0, "VideoSettings", "Reference only");
@@ -94,8 +98,8 @@ Fact* VideoSettings::videoSource(void)
{
if (!_videoSourceFact) {
_videoSourceFact = _createSettingsFact(videoSourceName);
+ connect(_videoSourceFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
-
return _videoSourceFact;
}
@@ -103,8 +107,8 @@ Fact* VideoSettings::udpPort(void)
{
if (!_udpPortFact) {
_udpPortFact = _createSettingsFact(udpPortName);
+ connect(_udpPortFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
-
return _udpPortFact;
}
@@ -112,8 +116,8 @@ Fact* VideoSettings::rtspUrl(void)
{
if (!_rtspUrlFact) {
_rtspUrlFact = _createSettingsFact(rtspUrlName);
+ connect(_rtspUrlFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
-
return _rtspUrlFact;
}
@@ -121,8 +125,8 @@ Fact* VideoSettings::tcpUrl(void)
{
if (!_tcpUrlFact) {
_tcpUrlFact = _createSettingsFact(tcpUrlName);
+ connect(_tcpUrlFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
-
return _tcpUrlFact;
}
@@ -131,7 +135,6 @@ Fact* VideoSettings::aspectRatio(void)
if (!_videoAspectRatioFact) {
_videoAspectRatioFact = _createSettingsFact(videoAspectRatioName);
}
-
return _videoAspectRatioFact;
}
@@ -140,7 +143,6 @@ Fact* VideoSettings::gridLines(void)
if (!_gridLinesFact) {
_gridLinesFact = _createSettingsFact(videoGridLinesName);
}
-
return _gridLinesFact;
}
@@ -149,7 +151,6 @@ Fact* VideoSettings::showRecControl(void)
if (!_showRecControlFact) {
_showRecControlFact = _createSettingsFact(showRecControlName);
}
-
return _showRecControlFact;
}
@@ -158,7 +159,6 @@ Fact* VideoSettings::recordingFormat(void)
if (!_recordingFormatFact) {
_recordingFormatFact = _createSettingsFact(recordingFormatName);
}
-
return _recordingFormatFact;
}
@@ -167,7 +167,6 @@ Fact* VideoSettings::maxVideoSize(void)
if (!_maxVideoSizeFact) {
_maxVideoSizeFact = _createSettingsFact(maxVideoSizeName);
}
-
return _maxVideoSizeFact;
}
@@ -176,7 +175,6 @@ Fact* VideoSettings::enableStorageLimit(void)
if (!_enableStorageLimitFact) {
_enableStorageLimitFact = _createSettingsFact(enableStorageLimitName);
}
-
return _enableStorageLimitFact;
}
@@ -185,6 +183,50 @@ Fact* VideoSettings::rtspTimeout(void)
if (!_rtspTimeoutFact) {
_rtspTimeoutFact = _createSettingsFact(rtspTimeoutName);
}
-
return _rtspTimeoutFact;
}
+
+Fact* VideoSettings::streamEnabled(void)
+{
+ if (!_streamEnabledFact) {
+ _streamEnabledFact = _createSettingsFact(streamEnabledName);
+ }
+ return _streamEnabledFact;
+}
+
+Fact* VideoSettings::disableWhenDisarmed(void)
+{
+ if (!_disableWhenDisarmedFact) {
+ _disableWhenDisarmedFact = _createSettingsFact(disableWhenDisarmedName);
+ }
+ return _disableWhenDisarmedFact;
+}
+
+bool VideoSettings::streamConfigured(void)
+{
+#if !defined(QGC_GST_STREAMING)
+ return false;
+#endif
+ QString vSource = videoSource()->rawValue().toString();
+ if(vSource == videoSourceNoVideo || vSource == videoDisabled) {
+ return false;
+ }
+ //-- If UDP, check if port is set
+ if(vSource == videoSourceUDP) {
+ return udpPort()->rawValue().toInt() != 0;
+ }
+ //-- If RTSP, check for URL
+ if(vSource == videoSourceRTSP) {
+ return !rtspUrl()->rawValue().toString().isEmpty();
+ }
+ //-- If TCP, check for URL
+ if(vSource == videoSourceTCP) {
+ return !tcpUrl()->rawValue().toString().isEmpty();
+ }
+ return false;
+}
+
+void VideoSettings::_configChanged(QVariant)
+{
+ emit streamConfiguredChanged();
+}
diff --git a/src/Settings/VideoSettings.h b/src/Settings/VideoSettings.h
index e05816a1cc561cbd4b05c029cf8b3c1e36ddb062..63b6840d165d5d110b478f0e34608c53f70dec5b 100644
--- a/src/Settings/VideoSettings.h
+++ b/src/Settings/VideoSettings.h
@@ -19,29 +19,35 @@ class VideoSettings : public SettingsGroup
public:
VideoSettings(QObject* parent = NULL);
- Q_PROPERTY(Fact* videoSource READ videoSource CONSTANT)
- Q_PROPERTY(Fact* udpPort READ udpPort CONSTANT)
- Q_PROPERTY(Fact* tcpUrl READ tcpUrl CONSTANT)
- Q_PROPERTY(Fact* rtspUrl READ rtspUrl CONSTANT)
- Q_PROPERTY(Fact* aspectRatio READ aspectRatio CONSTANT)
- Q_PROPERTY(Fact* gridLines READ gridLines CONSTANT)
- Q_PROPERTY(Fact* showRecControl READ showRecControl CONSTANT)
- Q_PROPERTY(Fact* recordingFormat READ recordingFormat CONSTANT)
- Q_PROPERTY(Fact* maxVideoSize READ maxVideoSize CONSTANT)
- Q_PROPERTY(Fact* enableStorageLimit READ enableStorageLimit CONSTANT)
- Q_PROPERTY(Fact* rtspTimeout READ rtspTimeout CONSTANT)
+ Q_PROPERTY(Fact* videoSource READ videoSource CONSTANT)
+ Q_PROPERTY(Fact* udpPort READ udpPort CONSTANT)
+ Q_PROPERTY(Fact* tcpUrl READ tcpUrl CONSTANT)
+ Q_PROPERTY(Fact* rtspUrl READ rtspUrl CONSTANT)
+ Q_PROPERTY(Fact* aspectRatio READ aspectRatio CONSTANT)
+ Q_PROPERTY(Fact* gridLines READ gridLines CONSTANT)
+ Q_PROPERTY(Fact* showRecControl READ showRecControl CONSTANT)
+ Q_PROPERTY(Fact* recordingFormat READ recordingFormat CONSTANT)
+ Q_PROPERTY(Fact* maxVideoSize READ maxVideoSize CONSTANT)
+ Q_PROPERTY(Fact* enableStorageLimit READ enableStorageLimit CONSTANT)
+ Q_PROPERTY(Fact* rtspTimeout READ rtspTimeout CONSTANT)
+ Q_PROPERTY(Fact* streamEnabled READ streamEnabled CONSTANT)
+ Q_PROPERTY(Fact* disableWhenDisarmed READ disableWhenDisarmed CONSTANT)
+ Q_PROPERTY(bool streamConfigured READ streamConfigured NOTIFY streamConfiguredChanged)
- Fact* videoSource (void);
- Fact* udpPort (void);
- Fact* rtspUrl (void);
- Fact* tcpUrl (void);
- Fact* aspectRatio (void);
- Fact* gridLines (void);
- Fact* showRecControl (void);
- Fact* recordingFormat (void);
- Fact* maxVideoSize (void);
- Fact* enableStorageLimit(void);
- Fact* rtspTimeout (void);
+ Fact* videoSource (void);
+ Fact* udpPort (void);
+ Fact* rtspUrl (void);
+ Fact* tcpUrl (void);
+ Fact* aspectRatio (void);
+ Fact* gridLines (void);
+ Fact* showRecControl (void);
+ Fact* recordingFormat (void);
+ Fact* maxVideoSize (void);
+ Fact* enableStorageLimit (void);
+ Fact* rtspTimeout (void);
+ Fact* streamEnabled (void);
+ Fact* disableWhenDisarmed (void);
+ bool streamConfigured (void);
static const char* videoSettingsGroupName;
@@ -56,6 +62,8 @@ public:
static const char* maxVideoSizeName;
static const char* enableStorageLimitName;
static const char* rtspTimeoutName;
+ static const char* streamEnabledName;
+ static const char* disableWhenDisarmedName;
static const char* videoSourceNoVideo;
static const char* videoDisabled;
@@ -63,6 +71,12 @@ public:
static const char* videoSourceRTSP;
static const char* videoSourceTCP;
+signals:
+ void streamConfiguredChanged ();
+
+private slots:
+ void _configChanged (QVariant value);
+
private:
SettingsFact* _videoSourceFact;
SettingsFact* _udpPortFact;
@@ -75,6 +89,8 @@ private:
SettingsFact* _maxVideoSizeFact;
SettingsFact* _enableStorageLimitFact;
SettingsFact* _rtspTimeoutFact;
+ SettingsFact* _streamEnabledFact;
+ SettingsFact* _disableWhenDisarmedFact;
};
#endif
diff --git a/src/Vehicle/Vehicle.cc b/src/Vehicle/Vehicle.cc
index 422637e5ab223974eaa81e8f4e09802195ee2dff..99b8ba000166ca52cc3cd746410f57b8f64476f2 100644
--- a/src/Vehicle/Vehicle.cc
+++ b/src/Vehicle/Vehicle.cc
@@ -33,6 +33,8 @@
#include "QGCCorePlugin.h"
#include "ADSBVehicle.h"
#include "QGCCameraManager.h"
+#include "VideoReceiver.h"
+#include "VideoManager.h"
QGC_LOGGING_CATEGORY(VehicleLog, "VehicleLog")
@@ -1121,6 +1123,11 @@ void Vehicle::_handleHeartbeat(mavlink_message_t& message)
_clearCameraTriggerPoints();
} else {
_mapTrajectoryStop();
+ // Also handle Video Streaming
+ if(_settingsManager->videoSettings()->disableWhenDisarmed()->rawValue().toBool()) {
+ _settingsManager->videoSettings()->streamEnabled()->setRawValue(false);
+ qgcApp()->toolbox()->videoManager()->videoReceiver()->stop();
+ }
}
}
diff --git a/src/VideoStreaming/VideoReceiver.cc b/src/VideoStreaming/VideoReceiver.cc
index 5091f215a1bc134c1f65ea02c50dcced9ae1143a..341558bd1f57fb58ead5c6ff7de9e51ad2b88354 100644
--- a/src/VideoStreaming/VideoReceiver.cc
+++ b/src/VideoStreaming/VideoReceiver.cc
@@ -67,8 +67,10 @@ VideoReceiver::VideoReceiver(QObject* parent)
, _videoSurface(NULL)
, _videoRunning(false)
, _showFullScreen(false)
+ , _videoSettings(NULL)
{
- _videoSurface = new VideoSurface;
+ _videoSurface = new VideoSurface;
+ _videoSettings = qgcApp()->toolbox()->settingsManager()->videoSettings();
#if defined(QGC_GST_STREAMING)
_setVideoSink(_videoSurface->videoSink());
_timer.setSingleShot(true);
@@ -147,8 +149,10 @@ VideoReceiver::_connected()
_timer.stop();
_socket->deleteLater();
_socket = NULL;
- _serverPresent = true;
- start();
+ if(_videoSettings->streamEnabled()->rawValue().toBool()) {
+ _serverPresent = true;
+ start();
+ }
}
#endif
@@ -161,7 +165,9 @@ VideoReceiver::_socketError(QAbstractSocket::SocketError socketError)
_socket->deleteLater();
_socket = NULL;
//-- Try again in 5 seconds
- _timer.start(5000);
+ if(_videoSettings->streamEnabled()->rawValue().toBool()) {
+ _timer.start(5000);
+ }
}
#endif
@@ -175,18 +181,19 @@ VideoReceiver::_timeout()
delete _socket;
_socket = NULL;
}
- //-- RTSP will try to connect to the server. If it cannot connect,
- // it will simply give up and never try again. Instead, we keep
- // attempting a connection on this timer. Once a connection is
- // found to be working, only then we actually start the stream.
- QUrl url(_uri);
- _socket = new QTcpSocket;
- _socket->setProxy(QNetworkProxy::NoProxy);
- connect(_socket, static_cast(&QTcpSocket::error), this, &VideoReceiver::_socketError);
- connect(_socket, &QTcpSocket::connected, this, &VideoReceiver::_connected);
- //qCDebug(VideoReceiverLog) << "Trying to connect to:" << url.host() << url.port();
- _socket->connectToHost(url.host(), url.port());
- _timer.start(5000);
+ if(_videoSettings->streamEnabled()->rawValue().toBool()) {
+ //-- RTSP will try to connect to the server. If it cannot connect,
+ // it will simply give up and never try again. Instead, we keep
+ // attempting a connection on this timer. Once a connection is
+ // found to be working, only then we actually start the stream.
+ QUrl url(_uri);
+ _socket = new QTcpSocket;
+ _socket->setProxy(QNetworkProxy::NoProxy);
+ connect(_socket, static_cast(&QTcpSocket::error), this, &VideoReceiver::_socketError);
+ connect(_socket, &QTcpSocket::connected, this, &VideoReceiver::_connected);
+ _socket->connectToHost(url.host(), url.port());
+ _timer.start(5000);
+ }
}
#endif
@@ -203,6 +210,11 @@ VideoReceiver::_timeout()
void
VideoReceiver::start()
{
+ if(!_videoSettings->streamEnabled()->rawValue().toBool() ||
+ !_videoSettings->streamConfigured()) {
+ qCDebug(VideoReceiverLog) << "start() but not enabled/configured";
+ return;
+ }
#if defined(QGC_GST_STREAMING)
qCDebug(VideoReceiverLog) << "start()";
@@ -550,7 +562,7 @@ void
VideoReceiver::_cleanupOldVideos()
{
//-- Only perform cleanup if storage limit is enabled
- if(qgcApp()->toolbox()->settingsManager()->videoSettings()->enableStorageLimit()->rawValue().toBool()) {
+ if(_videoSettings->enableStorageLimit()->rawValue().toBool()) {
QString savePath = qgcApp()->toolbox()->settingsManager()->appSettings()->videoSavePath();
QDir videoDir = QDir(savePath);
videoDir.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable);
@@ -566,7 +578,7 @@ VideoReceiver::_cleanupOldVideos()
if(!vidList.isEmpty()) {
uint64_t total = 0;
//-- Settings are stored using MB
- uint64_t maxSize = (qgcApp()->toolbox()->settingsManager()->videoSettings()->maxVideoSize()->rawValue().toUInt() * 1024 * 1024);
+ uint64_t maxSize = (_videoSettings->maxVideoSize()->rawValue().toUInt() * 1024 * 1024);
//-- Compute total used storage
for(int i = 0; i < vidList.size(); i++) {
total += vidList[i].size();
@@ -614,7 +626,7 @@ VideoReceiver::startRecording(void)
return;
}
- uint32_t muxIdx = qgcApp()->toolbox()->settingsManager()->videoSettings()->recordingFormat()->rawValue().toUInt();
+ uint32_t muxIdx = _videoSettings->recordingFormat()->rawValue().toUInt();
if(muxIdx >= NUM_MUXES) {
qgcApp()->showMessage(tr("Invalid video format defined."));
return;
@@ -803,7 +815,7 @@ VideoReceiver::_updateTimer()
if(_videoRunning) {
uint32_t timeout = 1;
if(qgcApp()->toolbox() && qgcApp()->toolbox()->settingsManager()) {
- timeout = qgcApp()->toolbox()->settingsManager()->videoSettings()->rtspTimeout()->rawValue().toUInt();
+ timeout = _videoSettings->rtspTimeout()->rawValue().toUInt();
}
time_t elapsed = 0;
time_t lastFrame = _videoSurface->lastFrame();
@@ -814,7 +826,7 @@ VideoReceiver::_updateTimer()
stop();
}
} else {
- if(!running() && !_uri.isEmpty()) {
+ if(!running() && !_uri.isEmpty() && _videoSettings->streamEnabled()->rawValue().toBool()) {
start();
}
}
diff --git a/src/VideoStreaming/VideoReceiver.h b/src/VideoStreaming/VideoReceiver.h
index 7e7cfaf5601d61500e06ac8fc1aaf1b137c24404..f21380a78ec4925894f65d01f6b8b5ec7993858c 100644
--- a/src/VideoStreaming/VideoReceiver.h
+++ b/src/VideoStreaming/VideoReceiver.h
@@ -30,6 +30,8 @@
Q_DECLARE_LOGGING_CATEGORY(VideoReceiverLog)
+class VideoSettings;
+
class VideoReceiver : public QObject
{
Q_OBJECT
@@ -38,9 +40,9 @@ public:
Q_PROPERTY(bool recording READ recording NOTIFY recordingChanged)
#endif
Q_PROPERTY(VideoSurface* videoSurface READ videoSurface CONSTANT)
- Q_PROPERTY(bool videoRunning READ videoRunning NOTIFY videoRunningChanged)
- Q_PROPERTY(QString imageFile READ imageFile NOTIFY imageFileChanged)
- Q_PROPERTY(bool showFullScreen READ showFullScreen WRITE setShowFullScreen NOTIFY showFullScreenChanged)
+ Q_PROPERTY(bool videoRunning READ videoRunning NOTIFY videoRunningChanged)
+ Q_PROPERTY(QString imageFile READ imageFile NOTIFY imageFileChanged)
+ Q_PROPERTY(bool showFullScreen READ showFullScreen WRITE setShowFullScreen NOTIFY showFullScreenChanged)
explicit VideoReceiver(QObject* parent = 0);
~VideoReceiver();
@@ -57,6 +59,7 @@ public:
bool videoRunning () { return _videoRunning; }
QString imageFile () { return _imageFile; }
bool showFullScreen () { return _showFullScreen; }
+
void grabImage (QString imageFile);
void setShowFullScreen (bool show) { _showFullScreen = show; emit showFullScreenChanged(); }
@@ -136,7 +139,7 @@ private:
VideoSurface* _videoSurface;
bool _videoRunning;
bool _showFullScreen;
-
+ VideoSettings* _videoSettings;
};
#endif // VIDEORECEIVER_H
diff --git a/src/api/QGCCorePlugin.cc b/src/api/QGCCorePlugin.cc
index de2d76d00ee6a22dde0e3298ee74223b646c46a2..58b06834e82948323797611d4de59f72d147f161 100644
--- a/src/api/QGCCorePlugin.cc
+++ b/src/api/QGCCorePlugin.cc
@@ -39,6 +39,7 @@ public:
, defaultOptions (NULL)
, valuesPageWidgetInfo (NULL)
, cameraPageWidgetInfo (NULL)
+ , videoPageWidgetInfo (NULL)
, healthPageWidgetInfo (NULL)
, vibrationPageWidgetInfo (NULL)
{
@@ -80,6 +81,7 @@ public:
QmlComponentInfo* valuesPageWidgetInfo;
QmlComponentInfo* cameraPageWidgetInfo;
+ QmlComponentInfo* videoPageWidgetInfo;
QmlComponentInfo* healthPageWidgetInfo;
QmlComponentInfo* vibrationPageWidgetInfo;
QVariantList instrumentPageWidgetList;
@@ -148,13 +150,19 @@ QVariantList &QGCCorePlugin::settingsPages()
QVariantList& QGCCorePlugin::instrumentPages(void)
{
if (!_p->valuesPageWidgetInfo) {
- _p->valuesPageWidgetInfo = new QmlComponentInfo(tr("Values"), QUrl::fromUserInput("qrc:/qml/ValuePageWidget.qml"));
- _p->cameraPageWidgetInfo = new QmlComponentInfo(tr("Camera"), QUrl::fromUserInput("qrc:/qml/CameraPageWidget.qml"));
- _p->healthPageWidgetInfo = new QmlComponentInfo(tr("Health"), QUrl::fromUserInput("qrc:/qml/HealthPageWidget.qml"));
+ _p->valuesPageWidgetInfo = new QmlComponentInfo(tr("Values"), QUrl::fromUserInput("qrc:/qml/ValuePageWidget.qml"));
+ _p->cameraPageWidgetInfo = new QmlComponentInfo(tr("Camera"), QUrl::fromUserInput("qrc:/qml/CameraPageWidget.qml"));
+#if defined(QGC_GST_STREAMING)
+ _p->videoPageWidgetInfo = new QmlComponentInfo(tr("Video Stream"), QUrl::fromUserInput("qrc:/qml/VideoPageWidget.qml"));
+#endif
+ _p->healthPageWidgetInfo = new QmlComponentInfo(tr("Health"), QUrl::fromUserInput("qrc:/qml/HealthPageWidget.qml"));
_p->vibrationPageWidgetInfo = new QmlComponentInfo(tr("Vibration"), QUrl::fromUserInput("qrc:/qml/VibrationPageWidget.qml"));
_p->instrumentPageWidgetList.append(QVariant::fromValue(_p->valuesPageWidgetInfo));
_p->instrumentPageWidgetList.append(QVariant::fromValue(_p->cameraPageWidgetInfo));
+#if defined(QGC_GST_STREAMING)
+ _p->instrumentPageWidgetList.append(QVariant::fromValue(_p->videoPageWidgetInfo));
+#endif
_p->instrumentPageWidgetList.append(QVariant::fromValue(_p->healthPageWidgetInfo));
_p->instrumentPageWidgetList.append(QVariant::fromValue(_p->vibrationPageWidgetInfo));
}
diff --git a/src/ui/preferences/GeneralSettings.qml b/src/ui/preferences/GeneralSettings.qml
index 4d6c4ae3df6d95ccec2b1dc8c66c955938fe8597..cc853858727291c25c13194bfa825ca344399fcd 100644
--- a/src/ui/preferences/GeneralSettings.qml
+++ b/src/ui/preferences/GeneralSettings.qml
@@ -37,7 +37,7 @@ QGCView {
property Fact _appFontPointSize: QGroundControl.settingsManager.appSettings.appFontPointSize
property Fact _userBrandImageIndoor: QGroundControl.settingsManager.brandImageSettings.userBrandImageIndoor
property Fact _userBrandImageOutdoor: QGroundControl.settingsManager.brandImageSettings.userBrandImageOutdoor
- property real _labelWidth: ScreenTools.defaultFontPixelWidth * 15
+ property real _labelWidth: ScreenTools.defaultFontPixelWidth * 20
property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 30
property Fact _mapProvider: QGroundControl.settingsManager.flightMapSettings.mapProvider
property Fact _mapType: QGroundControl.settingsManager.flightMapSettings.mapType
@@ -590,13 +590,13 @@ QGCView {
spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 3 && QGroundControl.settingsManager.videoSettings.gridLines.visible
QGCLabel {
- text: qsTr("Grid Lines:")
+ text: qsTr("Disable When Disarmed:")
width: _labelWidth
anchors.verticalCenter: parent.verticalCenter
}
- FactComboBox {
- width: _editFieldWidth
- fact: QGroundControl.settingsManager.videoSettings.gridLines
+ FactCheckBox {
+ text: ""
+ fact: QGroundControl.settingsManager.videoSettings.disableWhenDisarmed
anchors.verticalCenter: parent.verticalCenter
}
}