Commit f1559638 authored by dogmaphobic's avatar dogmaphobic

Work on RTSP Video Stream, x86 Android, etc.

parent 5fc24cfa
...@@ -30,12 +30,18 @@ linux { ...@@ -30,12 +30,18 @@ linux {
CONFIG += LinuxBuild CONFIG += LinuxBuild
DEFINES += __STDC_LIMIT_MACROS __rasp_pi2__ DEFINES += __STDC_LIMIT_MACROS __rasp_pi2__
} else : android-g++ { } else : android-g++ {
message("Android build")
CONFIG += AndroidBuild MobileBuild CONFIG += AndroidBuild MobileBuild
DEFINES += __android__ DEFINES += __android__
DEFINES += __STDC_LIMIT_MACROS DEFINES += __STDC_LIMIT_MACROS
DEFINES += QGC_ENABLE_BLUETOOTH DEFINES += QGC_ENABLE_BLUETOOTH
target.path = $$DESTDIR target.path = $$DESTDIR
equals(ANDROID_TARGET_ARCH, x86) {
CONFIG += Androidx86Build
DEFINES += __androidx86__
message("Android x86 build")
} else {
message("Android Arm build")
}
} else { } else {
error("Unsuported Linux toolchain, only GCC 32- or 64-bit is supported") error("Unsuported Linux toolchain, only GCC 32- or 64-bit is supported")
} }
...@@ -54,11 +60,11 @@ linux { ...@@ -54,11 +60,11 @@ linux {
DEFINES += __macos__ DEFINES += __macos__
CONFIG += x86_64 CONFIG += x86_64
CONFIG -= x86 CONFIG -= x86
equals(QT_MAJOR_VERSION, 5) | greaterThan(QT_MINOR_VERSION, 5) { equals(QT_MAJOR_VERSION, 5) | greaterThan(QT_MINOR_VERSION, 5) {
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7 QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.7
} else { } else {
QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6 QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.6
} }
QMAKE_MAC_SDK = macosx10.11 QMAKE_MAC_SDK = macosx10.11
QMAKE_CXXFLAGS += -fvisibility=hidden QMAKE_CXXFLAGS += -fvisibility=hidden
} else { } else {
......
...@@ -46,6 +46,15 @@ contains (DEFINES, QGC_DISABLE_BLUETOOTH) { ...@@ -46,6 +46,15 @@ contains (DEFINES, QGC_DISABLE_BLUETOOTH) {
DEFINES += QGC_ENABLE_BLUETOOTH DEFINES += QGC_ENABLE_BLUETOOTH
} }
# USB Camera and UVC Video Sources
contains (DEFINES, QGC_DISABLE_UVC) {
message("Skipping support for UVC devices (manual override from command line)")
DEFINES -= QGC_DISABLE_UVC
} else:exists(user_config.pri):infile(user_config.pri, DEFINES, QGC_DISABLE_UVC) {
message("Skipping support for UVC devices (manual override from user_config.pri)")
DEFINES -= QGC_DISABLE_UVC
}
LinuxBuild { LinuxBuild {
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
} }
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
<file alias="LogDownload.qml">src/ViewWidgets/LogDownload.qml</file> <file alias="LogDownload.qml">src/ViewWidgets/LogDownload.qml</file>
<file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file> <file alias="FirmwareUpgrade.qml">src/VehicleSetup/FirmwareUpgrade.qml</file>
<file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file> <file alias="FlightDisplayView.qml">src/FlightDisplay/FlightDisplayView.qml</file>
<file alias="FlightDisplayViewUVC.qml">src/FlightDisplay/FlightDisplayViewUVC.qml</file>
<file alias="FlightDisplayViewDummy.qml">src/FlightDisplay/FlightDisplayViewDummy.qml</file>
<file alias="PX4FlightModes.qml">src/AutoPilotPlugins/PX4/PX4FlightModes.qml</file> <file alias="PX4FlightModes.qml">src/AutoPilotPlugins/PX4/PX4FlightModes.qml</file>
<file alias="PX4AdvancedFlightModes.qml">src/AutoPilotPlugins/PX4/PX4AdvancedFlightModes.qml</file> <file alias="PX4AdvancedFlightModes.qml">src/AutoPilotPlugins/PX4/PX4AdvancedFlightModes.qml</file>
<file alias="PX4SimpleFlightModes.qml">src/AutoPilotPlugins/PX4/PX4SimpleFlightModes.qml</file> <file alias="PX4SimpleFlightModes.qml">src/AutoPilotPlugins/PX4/PX4SimpleFlightModes.qml</file>
......
...@@ -184,34 +184,17 @@ QGCView { ...@@ -184,34 +184,17 @@ QGCView {
} }
} }
] ]
//-- UDP Video Streaming //-- Video Streaming
FlightDisplayViewVideo { FlightDisplayViewVideo {
anchors.fill: parent anchors.fill: parent
visible: QGroundControl.videoManager.isGStreamer visible: QGroundControl.videoManager.isGStreamer
} }
//-- UVC Video (USB Camera or Video Device) //-- UVC Video (USB Camera or Video Device)
Rectangle { Loader {
id: noVideo id: cameraLoader
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(0,0,0,0.75)
visible: !QGroundControl.videoManager.isGStreamer visible: !QGroundControl.videoManager.isGStreamer
Camera { source: QGroundControl.videoManager.uvcEnabled ? "qrc:/qml/FlightDisplayViewUVC.qml" : "qrc:/qml/FlightDisplayViewDummy.qml"
id: camera
deviceId: QGroundControl.videoManager.videoSourceID
captureMode: Camera.CaptureViewfinder
}
VideoOutput {
id: viewFinder
source: camera
anchors.fill: parent
visible: !QGroundControl.videoManager.isGStreamer
}
onVisibleChanged: {
if(visible)
camera.start()
else
camera.stop()
}
} }
} }
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
import QtQuick 2.5
Rectangle {
anchors.fill: parent
color: Qt.rgba(0,0,0,0.75)
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
import QtQuick 2.5
import QtMultimedia 5.5
import QGroundControl 1.0
Rectangle {
anchors.fill: parent
color: Qt.rgba(0,0,0,0.75)
Camera {
id: camera
deviceId: QGroundControl.videoManager.videoSourceID
captureMode: Camera.CaptureViewfinder
}
VideoOutput {
source: camera
anchors.fill: parent
fillMode: VideoOutput.PreserveAspectCrop
visible: !QGroundControl.videoManager.isGStreamer
}
onVisibleChanged: {
if(visible)
camera.start()
else
camera.stop()
}
}
...@@ -41,7 +41,6 @@ Item { ...@@ -41,7 +41,6 @@ Item {
display: QGroundControl.videoManager.videoSurface display: QGroundControl.videoManager.videoSurface
receiver: QGroundControl.videoManager.videoReceiver receiver: QGroundControl.videoManager.videoReceiver
visible: QGroundControl.videoManager.videoRunning visible: QGroundControl.videoManager.videoRunning
runVideo: true
/* TODO: Come up with a way to make this an option /* TODO: Come up with a way to make this an option
QGCAttitudeHUD { QGCAttitudeHUD {
id: attitudeHUD id: attitudeHUD
......
...@@ -19,51 +19,33 @@ ...@@ -19,51 +19,33 @@
#include "VideoManager.h" #include "VideoManager.h"
static const char* kVideoSourceKey = "VideoSource"; static const char* kVideoSourceKey = "VideoSource";
static const char* kGStreamerSource = "UDP Video Stream"; static const char* kVideoUDPPortKey = "VideoUDPPort";
static const char* kVideoRTSPUrlKey = "VideoRTSPUrl";
static const char* kUDPStream = "UDP Video Stream";
static const char* kRTSPStream = "RTSP Video Stream";
QGC_LOGGING_CATEGORY(VideoManagerLog, "VideoManagerLog") QGC_LOGGING_CATEGORY(VideoManagerLog, "VideoManagerLog")
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
VideoManager::VideoManager(QGCApplication* app) VideoManager::VideoManager(QGCApplication* app)
: QGCTool(app) : QGCTool(app)
, _videoSurface(NULL)
, _videoReceiver(NULL)
, _videoRunning(false) , _videoRunning(false)
, _udpPort(5600) //-- Defalut Port 5600 == Solo UDP Port
, _init(false)
{ {
/* //-- Get saved settings
* This is the receiving end of an UDP RTP stream. The sender can be setup with this command: QSettings settings;
* setVideoSource(settings.value(kVideoSourceKey, kUDPStream).toString());
* gst-launch-1.0 uvch264src initial-bitrate=1000000 average-bitrate=1000000 iframe-period=1000 name=src auto-start=true src.vidsrc ! \ setUdpPort(settings.value(kVideoUDPPortKey, 5600).toUInt());
* video/x-h264,width=1280,height=720,framerate=24/1 ! h264parse ! rtph264pay ! udpsink host=192.168.1.9 port=5600 setRtspURL(settings.value(kVideoRTSPUrlKey, "rtsp://192.168.42.1:554/live").toString()); //-- Example RTSP URL
* _init = true;
* Where the main parameters are:
*
* uvch264src: Your h264 video source (the example above uses a Logitech C920 on an Raspberry PI 2+ or Odroid C1
* host=192.168.1.9 This is the IP address of QGC. You can use Avahi/Zeroconf to find QGC using the "_qgroundcontrol._udp" service.
*
* Advanced settings (you should probably read the gstreamer documentation before changing these):
*
* initial-bitrate=1000000 average-bitrate=1000000
* The bit rate to use. The greater, the better quality at the cost of higher bandwidth.
*
* width=1280,height=720,framerate=24/1
* The video resolution and frame rate. This depends on the camera used.
*
* iframe-period=1000
* Interval between iFrames. The greater the interval the lesser bandwidth at the cost of a longer time to recover from lost packets.
*
* Do not change anything else unless you know what you are doing. Any other change will require a matching change on the receiving end.
*
*/
_videoSurface = new VideoSurface;
_videoReceiver = new VideoReceiver(this);
_videoReceiver->setUri(QLatin1Literal("udp://0.0.0.0:5600")); // Port 5600=Solo UDP port, if you change it, you will break Solo video support
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
_videoReceiver->setVideoSink(_videoSurface->videoSink()); _updateVideo();
connect(&_frameTimer, &QTimer::timeout, this, &VideoManager::_updateTimer); connect(&_frameTimer, &QTimer::timeout, this, &VideoManager::_updateTimer);
_frameTimer.start(1000); _frameTimer.start(1000);
#endif #endif
//-- Get saved video source
QSettings settings;
setVideoSource(settings.value(kVideoSourceKey, kGStreamerSource).toString());
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -96,12 +78,21 @@ bool ...@@ -96,12 +78,21 @@ bool
VideoManager::isGStreamer() VideoManager::isGStreamer()
{ {
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
return _videoSource == kGStreamerSource; return _videoSource == kUDPStream || _videoSource == kRTSPStream;
#else #else
return false; return false;
#endif #endif
} }
//-----------------------------------------------------------------------------
#ifndef QGC_DISABLE_UVC
bool
VideoManager::uvcEnabled()
{
return QCameraInfo::availableCameras().count() > 0;
}
#endif
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void void
VideoManager::setVideoSource(QString vSource) VideoManager::setVideoSource(QString vSource)
...@@ -110,6 +101,7 @@ VideoManager::setVideoSource(QString vSource) ...@@ -110,6 +101,7 @@ VideoManager::setVideoSource(QString vSource)
QSettings settings; QSettings settings;
settings.setValue(kVideoSourceKey, vSource); settings.setValue(kVideoSourceKey, vSource);
emit videoSourceChanged(); emit videoSourceChanged();
#ifndef QGC_DISABLE_UVC
QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
foreach (const QCameraInfo &cameraInfo, cameras) { foreach (const QCameraInfo &cameraInfo, cameras) {
if(cameraInfo.description() == vSource) { if(cameraInfo.description() == vSource) {
...@@ -119,8 +111,51 @@ VideoManager::setVideoSource(QString vSource) ...@@ -119,8 +111,51 @@ VideoManager::setVideoSource(QString vSource)
break; break;
} }
} }
#endif
emit isGStreamerChanged(); emit isGStreamerChanged();
qCDebug(VideoManagerLog) << "New Video Source:" << vSource; qCDebug(VideoManagerLog) << "New Video Source:" << vSource;
/*
* Not working. Requires restart for now
if(isGStreamer())
_updateVideo();
*/
if(_videoReceiver) {
if(isGStreamer()) {
_videoReceiver->start();
} else {
_videoReceiver->stop();
}
}
}
//-----------------------------------------------------------------------------
void
VideoManager::setUdpPort(quint16 port)
{
_udpPort = port;
QSettings settings;
settings.setValue(kVideoUDPPortKey, port);
emit udpPortChanged();
/*
* Not working. Requires restart for now
if(_videoSource == kUDPStream)
_updateVideo();
*/
}
//-----------------------------------------------------------------------------
void
VideoManager::setRtspURL(QString url)
{
_rtspURL = url;
QSettings settings;
settings.setValue(kVideoRTSPUrlKey, url);
emit rtspURLChanged();
/*
* Not working. Requires restart for now
if(_videoSource == kRTSPStream)
_updateVideo();
*/
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
...@@ -129,20 +164,23 @@ VideoManager::videoSourceList() ...@@ -129,20 +164,23 @@ VideoManager::videoSourceList()
{ {
_videoSourceList.clear(); _videoSourceList.clear();
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
_videoSourceList.append(kGStreamerSource); _videoSourceList.append(kUDPStream);
_videoSourceList.append(kRTSPStream);
#endif #endif
#ifndef QGC_DISABLE_UVC
QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
foreach (const QCameraInfo &cameraInfo, cameras) { foreach (const QCameraInfo &cameraInfo, cameras) {
qCDebug(VideoManagerLog) << "UVC Video source ID:" << cameraInfo.deviceName() << " Name:" << cameraInfo.description(); qCDebug(VideoManagerLog) << "UVC Video source ID:" << cameraInfo.deviceName() << " Name:" << cameraInfo.description();
_videoSourceList.append(cameraInfo.description()); _videoSourceList.append(cameraInfo.description());
} }
#endif
return _videoSourceList; return _videoSourceList;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#if defined(QGC_GST_STREAMING) void VideoManager::_updateTimer()
void VideoManager::_updateTimer(void)
{ {
#if defined(QGC_GST_STREAMING)
if(_videoRunning) if(_videoRunning)
{ {
time_t elapsed = 0; time_t elapsed = 0;
...@@ -150,7 +188,7 @@ void VideoManager::_updateTimer(void) ...@@ -150,7 +188,7 @@ void VideoManager::_updateTimer(void)
{ {
elapsed = time(0) - _videoSurface->lastFrame(); elapsed = time(0) - _videoSurface->lastFrame();
} }
if(elapsed > 2) if(elapsed > 2 && _videoSurface)
{ {
_videoRunning = false; _videoRunning = false;
_videoSurface->setLastFrame(0); _videoSurface->setLastFrame(0);
...@@ -167,5 +205,26 @@ void VideoManager::_updateTimer(void) ...@@ -167,5 +205,26 @@ void VideoManager::_updateTimer(void)
} }
} }
} }
}
#endif #endif
}
//-----------------------------------------------------------------------------
void VideoManager::_updateVideo()
{
if(_init) {
if(_videoReceiver)
delete _videoReceiver;
if(_videoSurface)
delete _videoSurface;
_videoSurface = new VideoSurface;
_videoReceiver = new VideoReceiver(this);
_videoReceiver->setVideoSink(_videoSurface->videoSink());
#if defined(QGC_GST_STREAMING)
if(_videoSource == kUDPStream)
_videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_udpPort));
else
_videoReceiver->setUri(_rtspURL);
#endif
_videoReceiver->start();
}
}
...@@ -35,6 +35,9 @@ public: ...@@ -35,6 +35,9 @@ public:
Q_PROPERTY(QString videoSource READ videoSource WRITE setVideoSource NOTIFY videoSourceChanged) Q_PROPERTY(QString videoSource READ videoSource WRITE setVideoSource NOTIFY videoSourceChanged)
Q_PROPERTY(QStringList videoSourceList READ videoSourceList NOTIFY videoSourceListChanged) Q_PROPERTY(QStringList videoSourceList READ videoSourceList NOTIFY videoSourceListChanged)
Q_PROPERTY(bool videoRunning READ videoRunning NOTIFY videoRunningChanged) Q_PROPERTY(bool videoRunning READ videoRunning NOTIFY videoRunningChanged)
Q_PROPERTY(quint16 udpPort READ udpPort WRITE setUdpPort NOTIFY udpPortChanged)
Q_PROPERTY(QString rtspURL READ rtspURL WRITE setRtspURL NOTIFY rtspURLChanged)
Q_PROPERTY(bool uvcEnabled READ uvcEnabled CONSTANT)
Q_PROPERTY(VideoSurface* videoSurface MEMBER _videoSurface CONSTANT) Q_PROPERTY(VideoSurface* videoSurface MEMBER _videoSurface CONSTANT)
Q_PROPERTY(VideoReceiver* videoReceiver MEMBER _videoReceiver CONSTANT) Q_PROPERTY(VideoReceiver* videoReceiver MEMBER _videoReceiver CONSTANT)
...@@ -44,7 +47,18 @@ public: ...@@ -44,7 +47,18 @@ public:
QString videoSourceID () { return _videoSourceID; } QString videoSourceID () { return _videoSourceID; }
QString videoSource () { return _videoSource; } QString videoSource () { return _videoSource; }
QStringList videoSourceList (); QStringList videoSourceList ();
quint16 udpPort () { return _udpPort; }
QString rtspURL () { return _rtspURL; }
#if defined(QGC_DISABLE_UVC)
bool uvcEnabled () { return false; }
#else
bool uvcEnabled ();
#endif
void setVideoSource (QString vSource); void setVideoSource (QString vSource);
void setUdpPort (quint16 port);
void setRtspURL (QString url);
// Override from QGCTool // Override from QGCTool
void setToolbox (QGCToolbox *toolbox); void setToolbox (QGCToolbox *toolbox);
...@@ -56,9 +70,12 @@ signals: ...@@ -56,9 +70,12 @@ signals:
void videoSourceListChanged (); void videoSourceListChanged ();
void isGStreamerChanged (); void isGStreamerChanged ();
void videoSourceIDChanged (); void videoSourceIDChanged ();
void udpPortChanged ();
void rtspURLChanged ();
private: private:
void _updateTimer(void); void _updateTimer ();
void _updateVideo ();
private: private:
VideoSurface* _videoSurface; VideoSurface* _videoSurface;
...@@ -70,6 +87,9 @@ private: ...@@ -70,6 +87,9 @@ private:
QString _videoSource; QString _videoSource;
QString _videoSourceID; QString _videoSourceID;
QStringList _videoSourceList; QStringList _videoSourceList;
quint16 _udpPort;
QString _rtspURL;
bool _init;
}; };
#endif #endif
...@@ -22,20 +22,5 @@ VideoItem { ...@@ -22,20 +22,5 @@ VideoItem {
id: videoBackground id: videoBackground
property var display property var display
property var receiver property var receiver
property var runVideo: false
surface: display surface: display
onRunVideoChanged: {
if(videoBackground.receiver && videoBackground.display) {
if(videoBackground.runVideo) {
videoBackground.receiver.start();
} else {
videoBackground.receiver.stop();
}
}
}
Component.onCompleted: {
if(videoBackground.runVideo && videoBackground.receiver) {
videoBackground.receiver.start();
}
}
} }
...@@ -49,6 +49,21 @@ void VideoReceiver::setVideoSink(GstElement* sink) ...@@ -49,6 +49,21 @@ void VideoReceiver::setVideoSink(GstElement* sink)
} }
#endif #endif
static void newPadCB(GstElement * element, GstPad* pad, gpointer data)
{
gchar *name;
name = gst_pad_get_name(pad);
g_print("A new pad %s was created\n", name);
GstCaps * p_caps = gst_pad_get_pad_template_caps (pad);
gchar * description = gst_caps_to_string(p_caps);
qDebug() << p_caps << ", " << description;
g_free(description);
GstElement * p_rtph264depay = GST_ELEMENT(data);
if(gst_element_link_pads(element, name, p_rtph264depay, "sink") == false)
qCritical() << "newPadCB : failed to link elements\n";
g_free(name);
}
void VideoReceiver::start() void VideoReceiver::start()
{ {
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
...@@ -56,7 +71,6 @@ void VideoReceiver::start() ...@@ -56,7 +71,6 @@ void VideoReceiver::start()
qCritical() << "VideoReceiver::start() failed because URI is not specified"; qCritical() << "VideoReceiver::start() failed because URI is not specified";
return; return;
} }
if (_videoSink == NULL) { if (_videoSink == NULL) {
qCritical() << "VideoReceiver::start() failed because video sink is not set"; qCritical() << "VideoReceiver::start() failed because video sink is not set";
return; return;
...@@ -72,29 +86,44 @@ void VideoReceiver::start() ...@@ -72,29 +86,44 @@ void VideoReceiver::start()
GstElement* parser = NULL; GstElement* parser = NULL;
GstElement* decoder = NULL; GstElement* decoder = NULL;
bool isUdp = _uri.contains("udp://");
do { do {
if ((_pipeline = gst_pipeline_new("receiver")) == NULL) { if ((_pipeline = gst_pipeline_new("receiver")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_pipeline_new()"; qCritical() << "VideoReceiver::start() failed. Error with gst_pipeline_new()";
break; break;
} }
if ((dataSource = gst_element_factory_make("udpsrc", "udp-source")) == NULL) { if(isUdp) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('udpsrc')"; dataSource = gst_element_factory_make("udpsrc", "udp-source");
break; } else {
dataSource = gst_element_factory_make("rtspsrc", "rtsp-source");
} }
if ((caps = gst_caps_from_string("application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264")) == NULL) { if (!dataSource) {
qCritical() << "VideoReceiver::start() failed. Error with gst_caps_from_string()"; qCritical() << "VideoReceiver::start() failed. Error with data source for gst_element_factory_make()";
break; break;
} }
g_object_set(G_OBJECT(dataSource), "uri", qPrintable(_uri), "caps", caps, NULL); if(isUdp) {
if ((caps = gst_caps_from_string("application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_caps_from_string()";
break;
}
g_object_set(G_OBJECT(dataSource), "uri", qPrintable(_uri), "caps", caps, NULL);
} else {
g_object_set(G_OBJECT(dataSource), "location", qPrintable(_uri), "latency", 0, NULL);
}
if ((demux = gst_element_factory_make("rtph264depay", "rtp-h264-depacketizer")) == NULL) { if ((demux = gst_element_factory_make("rtph264depay", "rtp-h264-depacketizer")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('rtph264depay')"; qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('rtph264depay')";
break; break;
} }
if(!isUdp) {
g_signal_connect(dataSource, "pad-added", G_CALLBACK(newPadCB), demux);
}
if ((parser = gst_element_factory_make("h264parse", "h264-parser")) == NULL) { if ((parser = gst_element_factory_make("h264parse", "h264-parser")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('h264parse')"; qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('h264parse')";
break; break;
...@@ -107,7 +136,15 @@ void VideoReceiver::start() ...@@ -107,7 +136,15 @@ void VideoReceiver::start()
gst_bin_add_many(GST_BIN(_pipeline), dataSource, demux, parser, decoder, _videoSink, NULL); gst_bin_add_many(GST_BIN(_pipeline), dataSource, demux, parser, decoder, _videoSink, NULL);
if (gst_element_link_many(dataSource, demux, parser, decoder, _videoSink, NULL) != (gboolean)TRUE) { gboolean res = FALSE;
if(isUdp) {
res = gst_element_link_many(dataSource, demux, parser, decoder, _videoSink, NULL);
} else {
res = gst_element_link_many(demux, parser, decoder, _videoSink, NULL);
}
if (!res) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_link_many()"; qCritical() << "VideoReceiver::start() failed. Error with gst_element_link_many()";
break; break;
} }
......
...@@ -73,8 +73,12 @@ LinuxBuild { ...@@ -73,8 +73,12 @@ LinuxBuild {
QMAKE_POST_LINK += $$escape_expand(\\n) xcopy \"$$GST_ROOT_WIN\\lib\\gstreamer-1.0\\validate\\*.dll\" \"$$DESTDIR_WIN\\gstreamer-plugins\\validate\\\" /Y $$escape_expand(\\n) QMAKE_POST_LINK += $$escape_expand(\\n) xcopy \"$$GST_ROOT_WIN\\lib\\gstreamer-1.0\\validate\\*.dll\" \"$$DESTDIR_WIN\\gstreamer-plugins\\validate\\\" /Y $$escape_expand(\\n)
} }
} else:AndroidBuild { } else:AndroidBuild {
#- gstreamer assumed to be installed in $$PWD/../../android/gstreamer-1.0-android-armv7-1.5.2 #- gstreamer assumed to be installed in $$PWD/../../android/gstreamer-1.0-android-armv7-1.5.2 (or x86)
GST_ROOT = $$PWD/../../gstreamer-1.0-android-armv7-1.5.2 Androidx86Build {
GST_ROOT = $$PWD/../../gstreamer-1.0-android-x86-1.5.2
} else {
GST_ROOT = $$PWD/../../gstreamer-1.0-android-armv7-1.5.2
}
exists($$GST_ROOT) { exists($$GST_ROOT) {
QMAKE_CXXFLAGS += -pthread QMAKE_CXXFLAGS += -pthread
CONFIG += VideoEnabled CONFIG += VideoEnabled
......
...@@ -27,6 +27,7 @@ VideoSurface::VideoSurface(QObject *parent) ...@@ -27,6 +27,7 @@ VideoSurface::VideoSurface(QObject *parent)
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
, _data(new VideoSurfacePrivate) , _data(new VideoSurfacePrivate)
, _lastFrame(0) , _lastFrame(0)
, _refed(false)
#endif #endif
{ {
} }
...@@ -34,7 +35,7 @@ VideoSurface::VideoSurface(QObject *parent) ...@@ -34,7 +35,7 @@ VideoSurface::VideoSurface(QObject *parent)
VideoSurface::~VideoSurface() VideoSurface::~VideoSurface()
{ {
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
if (_data->videoSink != NULL) { if (!_refed && _data->videoSink != NULL) {
gst_element_set_state(_data->videoSink, GST_STATE_NULL); gst_element_set_state(_data->videoSink, GST_STATE_NULL);
} }
delete _data; delete _data;
...@@ -42,7 +43,7 @@ VideoSurface::~VideoSurface() ...@@ -42,7 +43,7 @@ VideoSurface::~VideoSurface()
} }
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
GstElement* VideoSurface::videoSink() const GstElement* VideoSurface::videoSink()
{ {
if (_data->videoSink == NULL) { if (_data->videoSink == NULL) {
if ((_data->videoSink = gst_element_factory_make("qtquick2videosink", NULL)) == NULL) { if ((_data->videoSink = gst_element_factory_make("qtquick2videosink", NULL)) == NULL) {
...@@ -50,6 +51,7 @@ GstElement* VideoSurface::videoSink() const ...@@ -50,6 +51,7 @@ GstElement* VideoSurface::videoSink() const
return NULL; return NULL;
} }
g_signal_connect(_data->videoSink, "update", G_CALLBACK(onUpdateThunk), (void* )this); g_signal_connect(_data->videoSink, "update", G_CALLBACK(onUpdateThunk), (void* )this);
_refed = true;
} }
return _data->videoSink; return _data->videoSink;
} }
......
...@@ -40,7 +40,7 @@ public: ...@@ -40,7 +40,7 @@ public:
* is called. The surface will always keep a reference to this element. * is called. The surface will always keep a reference to this element.
*/ */
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
GstElement* videoSink() const; GstElement* videoSink();
time_t lastFrame() { return _lastFrame; } time_t lastFrame() { return _lastFrame; }
void setLastFrame(time_t t) { _lastFrame = t; } void setLastFrame(time_t t) { _lastFrame = t; }
#endif #endif
...@@ -55,7 +55,8 @@ private: ...@@ -55,7 +55,8 @@ private:
friend class VideoItem; friend class VideoItem;
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
VideoSurfacePrivate * const _data; VideoSurfacePrivate * const _data;
time_t _lastFrame; time_t _lastFrame;
bool _refed;
#endif #endif
}; };
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
#include "gstqwidgetvideosink.h" #include "gstqwidgetvideosink.h"
#define PACKAGE "mini-qt-gstreamer" #define PACKAGE "mini-qt-gstreamer"
#define PACKAGE_NAME "QgcQtGStreamer" #define PACKAGE_NAME "QgcQtGStreamer"
#define PACKAGE_ORIGIN "http://gstreamer.freedesktop.org/" #define PACKAGE_ORIGIN "http://gstreamer.freedesktop.org/"
#define PACKAGE_VERSION "1.2.0" #define PACKAGE_VERSION "1.2.0"
...@@ -44,7 +44,7 @@ static gboolean plugin_init(GstPlugin *plugin) ...@@ -44,7 +44,7 @@ static gboolean plugin_init(GstPlugin *plugin)
G_STRINGIFY(QGC_VIDEOSINK_PLUGIN), 0, G_STRINGIFY(QGC_VIDEOSINK_PLUGIN), 0,
"Debug category for GstQtVideoSink"); "Debug category for GstQtVideoSink");
if(!gst_element_register(plugin, G_STRINGIFY(QGC_VIDEOSINK_PLUGIN), if(!gst_element_register(plugin, G_STRINGIFY(QGC_VIDEOSINK_PLUGIN),
GST_RANK_NONE, GST_TYPE_QT_VIDEO_SINK)) { GST_RANK_NONE, GST_TYPE_QT_VIDEO_SINK)) {
GST_ERROR("Failed to register " G_STRINGIFY(QGC_VIDEOSINK_PLUGIN)); GST_ERROR("Failed to register " G_STRINGIFY(QGC_VIDEOSINK_PLUGIN));
return FALSE; return FALSE;
......
...@@ -31,493 +31,546 @@ QGCView { ...@@ -31,493 +31,546 @@ QGCView {
anchors.margins: ScreenTools.defaultFontPixelWidth anchors.margins: ScreenTools.defaultFontPixelWidth
property Fact _percentRemainingAnnounce: QGroundControl.batteryPercentRemainingAnnounce property Fact _percentRemainingAnnounce: QGroundControl.batteryPercentRemainingAnnounce
property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 20 property real _labelWidth: ScreenTools.defaultFontPixelWidth * 15
property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 30
QGCPalette { id: qgcPal } QGCPalette { id: qgcPal }
QGCViewPanel { QGCViewPanel {
id: panel id: panel
anchors.fill: parent anchors.fill: parent
QGCFlickable { QGCFlickable {
clip: true clip: true
anchors.fill: parent anchors.fill: parent
contentHeight: settingsColumn.height contentHeight: settingsColumn.height
contentWidth: settingsColumn.width contentWidth: settingsColumn.width
Column { Column {
id: settingsColumn id: settingsColumn
width: qgcView.width
spacing: ScreenTools.defaultFontPixelHeight * 0.5
anchors.margins: ScreenTools.defaultFontPixelWidth anchors.margins: ScreenTools.defaultFontPixelWidth
spacing: ScreenTools.defaultFontPixelHeight / 2
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Base UI Font Point Size //-- Units
Row { Item {
spacing: ScreenTools.defaultFontPixelWidth width: qgcView.width * 0.8
height: unitLabel.height
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel { QGCLabel {
id: baseFontLabel id: unitLabel
text: qsTr("Base UI font size:") text: qsTr("Units (Requires Restart)")
anchors.verticalCenter: parent.verticalCenter font.family: ScreenTools.demiboldFontFamily
} }
}
Row { Rectangle {
id: baseFontRow height: unitsCol.height + (ScreenTools.defaultFontPixelHeight * 2)
spacing: ScreenTools.defaultFontPixelWidth / 2 width: qgcView.width * 0.8
anchors.verticalCenter: parent.verticalCenter color: qgcPal.windowShade
anchors.margins: ScreenTools.defaultFontPixelWidth
QGCButton { anchors.horizontalCenter: parent.horizontalCenter
id: decrementButton Column {
width: height id: unitsCol
height: baseFontEdit.height spacing: ScreenTools.defaultFontPixelWidth
text: "-" anchors.centerIn: parent
Row {
onClicked: { spacing: ScreenTools.defaultFontPixelWidth
if(ScreenTools.defaultFontPointSize > 6) { QGCLabel {
QGroundControl.baseFontPointSize = QGroundControl.baseFontPointSize - 1 width: _labelWidth
} anchors.baseline: distanceUnitsCombo.baseline
text: qsTr("Distance:")
}
FactComboBox {
id: distanceUnitsCombo
width: _editFieldWidth
fact: QGroundControl.distanceUnits
indexModel: false
} }
} }
Row {
QGCTextField { spacing: ScreenTools.defaultFontPixelWidth
id: baseFontEdit QGCLabel {
width: _editFieldWidth - (decrementButton.width * 2) - (baseFontRow.spacing * 2) width: _labelWidth
text: QGroundControl.baseFontPointSize anchors.baseline: areaUnitsCombo.baseline
showUnits: true text: qsTr("Area:")
unitsLabel: "pt" }
maximumLength: 6 FactComboBox {
validator: DoubleValidator {bottom: 6.0; top: 48.0; decimals: 2;} id: areaUnitsCombo
width: _editFieldWidth
onEditingFinished: { fact: QGroundControl.areaUnits
var point = parseFloat(text) indexModel: false
if(point >= 6.0 && point <= 48.0)
QGroundControl.baseFontPointSize = point;
} }
} }
Row {
QGCButton { spacing: ScreenTools.defaultFontPixelWidth
width: height QGCLabel {
height: baseFontEdit.height width: _labelWidth
text: "+" anchors.baseline: speedUnitsCombo.baseline
text: qsTr("Speed:")
onClicked: { }
if(ScreenTools.defaultFontPointSize < 49) { FactComboBox {
QGroundControl.baseFontPointSize = QGroundControl.baseFontPointSize + 1 id: speedUnitsCombo
} width: _editFieldWidth
fact: QGroundControl.speedUnits
indexModel: false
} }
} }
} }
QGCLabel {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("(requires app restart)")
}
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Units //-- Video Source
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
width: baseFontLabel.width
anchors.baseline: distanceUnitsCombo.baseline
text: qsTr("Distance units:")
}
FactComboBox {
id: distanceUnitsCombo
width: _editFieldWidth
fact: QGroundControl.distanceUnits
indexModel: false
}
QGCLabel {
anchors.baseline: distanceUnitsCombo.baseline
text: qsTr("(requires app restart)")
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
width: baseFontLabel.width
anchors.baseline: areaUnitsCombo.baseline
text: qsTr("Area units:")
}
FactComboBox {
id: areaUnitsCombo
width: _editFieldWidth
fact: QGroundControl.areaUnits
indexModel: false
}
QGCLabel {
anchors.baseline: areaUnitsCombo.baseline
text: qsTr("(requires app restart)")
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
width: baseFontLabel.width
anchors.baseline: speedUnitsCombo.baseline
text: qsTr("Speed units:")
}
FactComboBox {
id: speedUnitsCombo
width: _editFieldWidth
fact: QGroundControl.speedUnits
indexModel: false
}
QGCLabel {
anchors.baseline: speedUnitsCombo.baseline
text: qsTr("(requires app restart)")
}
}
Item { Item {
height: ScreenTools.defaultFontPixelHeight / 2 width: qgcView.width * 0.8
width: parent.width height: videoLabel.height
} anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
//----------------------------------------------------------------- QGCLabel {
//-- Audio preferences id: videoLabel
QGCCheckBox { text: qsTr("Video (Requires Restart)")
text: qsTr("Mute all audio output") font.family: ScreenTools.demiboldFontFamily
checked: QGroundControl.isAudioMuted
onClicked: {
QGroundControl.isAudioMuted = checked
}
}
//-----------------------------------------------------------------
//-- Prompt Save Log
QGCCheckBox {
id: promptSaveLog
text: qsTr("Prompt to save Flight Data Log after each flight")
checked: QGroundControl.isSaveLogPrompt
visible: !ScreenTools.isMobile
onClicked: {
QGroundControl.isSaveLogPrompt = checked
}
}
//-----------------------------------------------------------------
//-- Prompt Save even if not armed
QGCCheckBox {
text: qsTr("Prompt to save Flight Data Log even if vehicle was not armed")
checked: QGroundControl.isSaveLogPromptNotArmed
visible: !ScreenTools.isMobile
enabled: promptSaveLog.checked
onClicked: {
QGroundControl.isSaveLogPromptNotArmed = checked
} }
} }
//----------------------------------------------------------------- Rectangle {
//-- Clear settings height: videoCol.height + (ScreenTools.defaultFontPixelHeight * 2)
QGCCheckBox { width: qgcView.width * 0.8
id: clearCheck color: qgcPal.windowShade
text: qsTr("Clear all settings on next start") anchors.margins: ScreenTools.defaultFontPixelWidth
checked: false anchors.horizontalCenter: parent.horizontalCenter
onClicked: { Column {
checked ? clearDialog.visible = true : QGroundControl.clearDeleteAllSettingsNextBoot() id: videoCol
} spacing: ScreenTools.defaultFontPixelWidth
MessageDialog { anchors.centerIn: parent
id: clearDialog Row {
visible: false spacing: ScreenTools.defaultFontPixelWidth
icon: StandardIcon.Warning QGCLabel {
standardButtons: StandardButton.Yes | StandardButton.No anchors.baseline: videoSource.baseline
title: qsTr("Clear Settings") text: qsTr("Video Source:")
text: qsTr("All saved settings will be reset the next time you start QGroundControl. Is this really what you want?") width: _labelWidth
onYes: { }
QGroundControl.deleteAllSettingsNextBoot() QGCComboBox {
clearDialog.visible = false id: videoSource
width: _editFieldWidth
model: QGroundControl.videoManager.videoSourceList
Component.onCompleted: {
var index = videoSource.find(QGroundControl.videoManager.videoSource)
if (index >= 0) {
videoSource.currentIndex = index
}
}
onActivated: {
if (index != -1) {
currentIndex = index
QGroundControl.videoManager.videoSource = model[index]
}
}
}
} }
onNo: { Row {
clearCheck.checked = false spacing: ScreenTools.defaultFontPixelWidth
clearDialog.visible = false visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex === 0
QGCLabel {
anchors.baseline: udpField.baseline
text: qsTr("UDP Port:")
width: _labelWidth
}
QGCTextField {
id: udpField
width: _editFieldWidth
text: QGroundControl.videoManager.udpPort
validator: IntValidator {bottom: 1024; top: 65535;}
inputMethodHints: Qt.ImhDigitsOnly
onEditingFinished: {
QGroundControl.videoManager.udpPort = parseInt(text)
}
}
} }
} Row {
} spacing: ScreenTools.defaultFontPixelWidth
//----------------------------------------------------------------- visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex === 1
//-- Battery talker QGCLabel {
Row { anchors.baseline: rtspField.baseline
spacing: ScreenTools.defaultFontPixelWidth text: qsTr("RTSP URL:")
width: _labelWidth
QGCCheckBox { }
id: announcePercentCheckbox QGCTextField {
anchors.baseline: announcePercent.baseline id: rtspField
text: qsTr("Announce battery lower than:") width: _editFieldWidth
checked: _percentRemainingAnnounce.value != 0 text: QGroundControl.videoManager.rtspURL
onEditingFinished: {
onClicked: { QGroundControl.videoManager.rtspURL = text
if (checked) { }
_percentRemainingAnnounce.value = _percentRemainingAnnounce.defaultValueString
} else {
_percentRemainingAnnounce.value = 0
} }
} }
} }
FactTextField {
id: announcePercent
fact: _percentRemainingAnnounce
enabled: announcePercentCheckbox.checked
}
}
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Video Source //-- Offline mission editing
Row { Item {
spacing: ScreenTools.defaultFontPixelWidth width: qgcView.width * 0.8
height: offlineLabel.height
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel { QGCLabel {
anchors.baseline: videoSource.baseline id: offlineLabel
text: qsTr("Video Source:") text: qsTr("Offline Mission Editing")
font.family: ScreenTools.demiboldFontFamily
} }
QGCComboBox { }
id: videoSource Rectangle {
width: _editFieldWidth height: offlineCol.height + (ScreenTools.defaultFontPixelHeight * 2)
model: QGroundControl.videoManager.videoSourceList width: qgcView.width * 0.8
Component.onCompleted: { color: qgcPal.windowShade
var index = videoSource.find(QGroundControl.videoManager.videoSource) anchors.margins: ScreenTools.defaultFontPixelWidth
if (index >= 0) { anchors.horizontalCenter: parent.horizontalCenter
videoSource.currentIndex = index Column {
id: offlineCol
spacing: ScreenTools.defaultFontPixelWidth
anchors.centerIn: parent
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: qsTr("Firmware:")
width: _labelWidth
anchors.baseline: offlineTypeCombo.baseline
}
FactComboBox {
id: offlineTypeCombo
width: _editFieldWidth
fact: QGroundControl.offlineEditingFirmwareType
indexModel: false
} }
} }
onActivated: { Row {
if (index != -1) { spacing: ScreenTools.defaultFontPixelWidth
currentIndex = index QGCLabel {
QGroundControl.videoManager.videoSource = model[index] text: qsTr("Vehicle:")
width: _labelWidth
anchors.baseline: offlineVehicleCombo.baseline
}
FactComboBox {
id: offlineVehicleCombo
width: _editFieldWidth
fact: QGroundControl.offlineEditingVehicleType
indexModel: false
} }
} }
} Row {
} spacing: ScreenTools.defaultFontPixelWidth
//----------------------------------------------------------------- visible: offlineVehicleCombo.currentText != "Multicopter"
//-- Map Providers QGCLabel {
Row { text: qsTr("Cruise speed:")
width: _labelWidth
/* anchors.baseline: cruiseSpeedField.baseline
TODO: Map settings should come from QGroundControl.mapEngineManager. What is currently in }
QGroundControl.flightMapSettings should be moved there so all map related funtions are in FactTextField {
one place. id: cruiseSpeedField
*/ width: _editFieldWidth
fact: QGroundControl.offlineEditingCruiseSpeed
spacing: ScreenTools.defaultFontPixelWidth enabled: true
visible: QGroundControl.flightMapSettings.googleMapEnabled
QGCLabel {
id: mapProvidersLabel
anchors.baseline: mapProviders.baseline
text: qsTr("Map Provider:")
}
QGCComboBox {
id: mapProviders
width: _editFieldWidth
model: QGroundControl.flightMapSettings.mapProviders
Component.onCompleted: {
var index = mapProviders.find(QGroundControl.flightMapSettings.mapProvider)
if (index < 0) {
console.warn(qsTr("Active map provider not in combobox"), QGroundControl.flightMapSettings.mapProvider)
} else {
mapProviders.currentIndex = index
} }
} }
onActivated: { Row {
if (index != -1) { spacing: ScreenTools.defaultFontPixelWidth
currentIndex = index visible: offlineVehicleCombo.currentText != "Fixedwing"
console.log(qsTr("New map provider: ") + model[index]) QGCLabel {
QGroundControl.flightMapSettings.mapProvider = model[index] id: hoverSpeedLabel
text: qsTr("Hover speed:")
width: _labelWidth
anchors.baseline: hoverSpeedField.baseline
}
FactTextField {
id: hoverSpeedField
width: _editFieldWidth
fact: QGroundControl.offlineEditingHoverSpeed
enabled: true
} }
} }
} }
} }
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Palette Styles //-- Miscelanous
Row { Item {
spacing: ScreenTools.defaultFontPixelWidth width: qgcView.width * 0.8
height: miscLabel.height
anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
QGCLabel { QGCLabel {
width: mapProvidersLabel.width id: miscLabel
anchors.baseline: paletteCombo.baseline text: qsTr("Miscelaneous")
text: qsTr("Style:") font.family: ScreenTools.demiboldFontFamily
} }
}
QGCComboBox { Rectangle {
id: paletteCombo height: miscCol.height + (ScreenTools.defaultFontPixelHeight * 2)
width: _editFieldWidth width: qgcView.width * 0.8
model: [ qsTr("Indoor"), qsTr("Outdoor") ] color: qgcPal.windowShade
currentIndex: QGroundControl.isDarkStyle ? 0 : 1 anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
onActivated: { Column {
if (index != -1) { id: miscCol
currentIndex = index spacing: ScreenTools.defaultFontPixelWidth
QGroundControl.isDarkStyle = index === 0 ? true : false anchors.centerIn: parent
//-----------------------------------------------------------------
//-- Base UI Font Point Size
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
id: baseFontLabel
text: qsTr("Base UI font size:")
anchors.verticalCenter: parent.verticalCenter
}
Row {
id: baseFontRow
spacing: ScreenTools.defaultFontPixelWidth / 2
anchors.verticalCenter: parent.verticalCenter
QGCButton {
id: decrementButton
width: height
height: baseFontEdit.height
text: "-"
onClicked: {
if(ScreenTools.defaultFontPointSize > 6) {
QGroundControl.baseFontPointSize = QGroundControl.baseFontPointSize - 1
}
}
}
QGCTextField {
id: baseFontEdit
width: _editFieldWidth - (decrementButton.width * 2) - (baseFontRow.spacing * 2)
text: QGroundControl.baseFontPointSize
showUnits: true
unitsLabel: "pt"
maximumLength: 6
validator: DoubleValidator {bottom: 6.0; top: 48.0; decimals: 2;}
onEditingFinished: {
var point = parseFloat(text)
if(point >= 6.0 && point <= 48.0)
QGroundControl.baseFontPointSize = point;
}
}
QGCButton {
width: height
height: baseFontEdit.height
text: "+"
onClicked: {
if(ScreenTools.defaultFontPointSize < 49) {
QGroundControl.baseFontPointSize = QGroundControl.baseFontPointSize + 1
}
}
}
}
QGCLabel {
anchors.verticalCenter: parent.verticalCenter
text: qsTr("(Requires Restart)")
}
}
//-----------------------------------------------------------------
//-- Audio preferences
QGCCheckBox {
text: qsTr("Mute all audio output")
checked: QGroundControl.isAudioMuted
onClicked: {
QGroundControl.isAudioMuted = checked
}
}
//-----------------------------------------------------------------
//-- Prompt Save Log
QGCCheckBox {
id: promptSaveLog
text: qsTr("Prompt to save Flight Data Log after each flight")
checked: QGroundControl.isSaveLogPrompt
visible: !ScreenTools.isMobile
onClicked: {
QGroundControl.isSaveLogPrompt = checked
}
}
//-----------------------------------------------------------------
//-- Prompt Save even if not armed
QGCCheckBox {
text: qsTr("Prompt to save Flight Data Log even if vehicle was not armed")
checked: QGroundControl.isSaveLogPromptNotArmed
visible: !ScreenTools.isMobile
enabled: promptSaveLog.checked
onClicked: {
QGroundControl.isSaveLogPromptNotArmed = checked
}
}
//-----------------------------------------------------------------
//-- Clear settings
QGCCheckBox {
id: clearCheck
text: qsTr("Clear all settings on next start")
checked: false
onClicked: {
checked ? clearDialog.visible = true : QGroundControl.clearDeleteAllSettingsNextBoot()
}
MessageDialog {
id: clearDialog
visible: false
icon: StandardIcon.Warning
standardButtons: StandardButton.Yes | StandardButton.No
title: qsTr("Clear Settings")
text: qsTr("All saved settings will be reset the next time you start QGroundControl. Is this really what you want?")
onYes: {
QGroundControl.deleteAllSettingsNextBoot()
clearDialog.visible = false
}
onNo: {
clearCheck.checked = false
clearDialog.visible = false
}
}
}
//-----------------------------------------------------------------
//-- Battery talker
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCCheckBox {
id: announcePercentCheckbox
anchors.verticalCenter: parent.verticalCenter
text: qsTr("Announce battery lower than:")
checked: _percentRemainingAnnounce.value != 0
onClicked: {
if (checked) {
_percentRemainingAnnounce.value = _percentRemainingAnnounce.defaultValueString
} else {
_percentRemainingAnnounce.value = 0
}
}
}
FactTextField {
id: announcePercent
fact: _percentRemainingAnnounce
enabled: announcePercentCheckbox.checked
anchors.verticalCenter: parent.verticalCenter
}
}
//-----------------------------------------------------------------
//-- Virtual joystick settings
QGCCheckBox {
text: qsTr("Virtual Joystick")
checked: QGroundControl.virtualTabletJoystick
onClicked: QGroundControl.virtualTabletJoystick = checked
}
//-----------------------------------------------------------------
//-- Map Providers
Row {
/*
TODO: Map settings should come from QGroundControl.mapEngineManager. What is currently in
QGroundControl.flightMapSettings should be moved there so all map related funtions are in
one place.
*/
spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.flightMapSettings.googleMapEnabled
QGCLabel {
id: mapProvidersLabel
anchors.baseline: mapProviders.baseline
text: qsTr("Map Provider:")
width: _labelWidth
}
QGCComboBox {
id: mapProviders
width: _editFieldWidth
model: QGroundControl.flightMapSettings.mapProviders
Component.onCompleted: {
var index = mapProviders.find(QGroundControl.flightMapSettings.mapProvider)
if (index < 0) {
console.warn(qsTr("Active map provider not in combobox"), QGroundControl.flightMapSettings.mapProvider)
} else {
mapProviders.currentIndex = index
}
}
onActivated: {
if (index != -1) {
currentIndex = index
console.log(qsTr("New map provider: ") + model[index])
QGroundControl.flightMapSettings.mapProvider = model[index]
}
}
}
}
//-----------------------------------------------------------------
//-- Palette Styles
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
anchors.baseline: paletteCombo.baseline
text: qsTr("Style:")
width: _labelWidth
}
QGCComboBox {
id: paletteCombo
width: _editFieldWidth
model: [ qsTr("Indoor"), qsTr("Outdoor") ]
currentIndex: QGroundControl.isDarkStyle ? 0 : 1
onActivated: {
if (index != -1) {
currentIndex = index
QGroundControl.isDarkStyle = index === 0 ? true : false
}
}
} }
} }
} }
} }
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
//----------------------------------------------------------------- //-----------------------------------------------------------------
//-- Autoconnect settings //-- Autoconnect settings
QGCLabel { text: "Autoconnect to the following devices:" }
Row {
spacing: ScreenTools.defaultFontPixelWidth * 2
QGCCheckBox {
text: qsTr("Pixhawk")
visible: !ScreenTools.isiOS
checked: QGroundControl.linkManager.autoconnectPixhawk
onClicked: QGroundControl.linkManager.autoconnectPixhawk = checked
}
QGCCheckBox {
text: qsTr("SiK Radio")
visible: !ScreenTools.isiOS
checked: QGroundControl.linkManager.autoconnect3DRRadio
onClicked: QGroundControl.linkManager.autoconnect3DRRadio = checked
}
QGCCheckBox {
text: qsTr("PX4 Flow")
visible: !ScreenTools.isiOS
checked: QGroundControl.linkManager.autoconnectPX4Flow
onClicked: QGroundControl.linkManager.autoconnectPX4Flow = checked
}
QGCCheckBox {
text: qsTr("UDP")
checked: QGroundControl.linkManager.autoconnectUDP
onClicked: QGroundControl.linkManager.autoconnectUDP = checked
}
QGCCheckBox {
text: qsTr("RTK GPS")
checked: QGroundControl.linkManager.autoconnectRTKGPS
onClicked: QGroundControl.linkManager.autoconnectRTKGPS = checked
}
}
Item {
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
//-----------------------------------------------------------------
//-- Virtual joystick settings
QGCCheckBox {
text: qsTr("Virtual Joystick")
checked: QGroundControl.virtualTabletJoystick
onClicked: QGroundControl.virtualTabletJoystick = checked
}
Item { Item {
height: ScreenTools.defaultFontPixelHeight / 2 width: qgcView.width * 0.8
width: parent.width height: autoConnectLabel.height
} anchors.margins: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
//-----------------------------------------------------------------
//-- Offline mission editing settings
QGCLabel { text: "Offline mission editing" }
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel {
text: qsTr("Firmware:")
width: hoverSpeedLabel.width
anchors.baseline: offlineTypeCombo.baseline
}
FactComboBox {
id: offlineTypeCombo
width: ScreenTools.defaultFontPixelWidth * 18
fact: QGroundControl.offlineEditingFirmwareType
indexModel: false
}
}
Row {
spacing: ScreenTools.defaultFontPixelWidth
QGCLabel { QGCLabel {
text: qsTr("Vehicle:") id: autoConnectLabel
width: hoverSpeedLabel.width text: qsTr("Autoconnect to the following devices:")
anchors.baseline: offlineVehicleCombo.baseline font.family: ScreenTools.demiboldFontFamily
}
FactComboBox {
id: offlineVehicleCombo
width: offlineTypeCombo.width
fact: QGroundControl.offlineEditingVehicleType
indexModel: false
} }
} }
Rectangle {
Row { height: autoConnectCol.height + (ScreenTools.defaultFontPixelHeight * 2)
spacing: ScreenTools.defaultFontPixelWidth width: qgcView.width * 0.8
visible: offlineVehicleCombo.currentText != "Multicopter" color: qgcPal.windowShade
anchors.margins: ScreenTools.defaultFontPixelWidth
QGCLabel { anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Cruise speed:") Column {
width: hoverSpeedLabel.width id: autoConnectCol
anchors.baseline: cruiseSpeedField.baseline spacing: ScreenTools.defaultFontPixelWidth
} anchors.centerIn: parent
//-----------------------------------------------------------------
//-- Autoconnect settings
FactTextField { Row {
id: cruiseSpeedField spacing: ScreenTools.defaultFontPixelWidth * 2
width: offlineTypeCombo.width QGCCheckBox {
fact: QGroundControl.offlineEditingCruiseSpeed text: qsTr("Pixhawk")
enabled: true visible: !ScreenTools.isiOS
} checked: QGroundControl.linkManager.autoconnectPixhawk
} onClicked: QGroundControl.linkManager.autoconnectPixhawk = checked
}
Row { QGCCheckBox {
spacing: ScreenTools.defaultFontPixelWidth text: qsTr("SiK Radio")
visible: offlineVehicleCombo.currentText != "Fixedwing" visible: !ScreenTools.isiOS
checked: QGroundControl.linkManager.autoconnect3DRRadio
QGCLabel { onClicked: QGroundControl.linkManager.autoconnect3DRRadio = checked
id: hoverSpeedLabel }
text: qsTr("Hover speed:") QGCCheckBox {
width: baseFontLabel.width text: qsTr("PX4 Flow")
anchors.baseline: hoverSpeedField.baseline visible: !ScreenTools.isiOS
} checked: QGroundControl.linkManager.autoconnectPX4Flow
onClicked: QGroundControl.linkManager.autoconnectPX4Flow = checked
}
FactTextField { QGCCheckBox {
id: hoverSpeedField text: qsTr("UDP")
width: offlineTypeCombo.width checked: QGroundControl.linkManager.autoconnectUDP
fact: QGroundControl.offlineEditingHoverSpeed onClicked: QGroundControl.linkManager.autoconnectUDP = checked
enabled: true }
QGCCheckBox {
text: qsTr("RTK GPS")
checked: QGroundControl.linkManager.autoconnectRTKGPS
onClicked: QGroundControl.linkManager.autoconnectRTKGPS = checked
}
}
} }
} }
} // settingsColumn
Item { } // QGCFlickable
height: ScreenTools.defaultFontPixelHeight / 2
width: parent.width
}
}
}
} // QGCViewPanel } // QGCViewPanel
} // QGCView } // QGCView
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment