Commit e7a004f5 authored by Zachary Thorson's avatar Zachary Thorson

Add TCP-Mpeg2TS support to available video feeds

- Added menu options to select new mode as well as new settings and defaults
parent 37df3d36
...@@ -59,6 +59,7 @@ VideoManager::setToolbox(QGCToolbox *toolbox) ...@@ -59,6 +59,7 @@ VideoManager::setToolbox(QGCToolbox *toolbox)
connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged); connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
connect(_videoSettings->udpPort(), &Fact::rawValueChanged, this, &VideoManager::_udpPortChanged); connect(_videoSettings->udpPort(), &Fact::rawValueChanged, this, &VideoManager::_udpPortChanged);
connect(_videoSettings->rtspUrl(), &Fact::rawValueChanged, this, &VideoManager::_rtspUrlChanged); connect(_videoSettings->rtspUrl(), &Fact::rawValueChanged, this, &VideoManager::_rtspUrlChanged);
connect(_videoSettings->tcpUrl(), &Fact::rawValueChanged, this, &VideoManager::_tcpUrlChanged);
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
#ifndef QGC_DISABLE_UVC #ifndef QGC_DISABLE_UVC
...@@ -110,6 +111,13 @@ VideoManager::_rtspUrlChanged() ...@@ -110,6 +111,13 @@ VideoManager::_rtspUrlChanged()
_restartVideo(); _restartVideo();
} }
//-----------------------------------------------------------------------------
void
VideoManager::_tcpUrlChanged()
{
_restartVideo();
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool bool
VideoManager::hasVideo() VideoManager::hasVideo()
...@@ -124,7 +132,7 @@ VideoManager::isGStreamer() ...@@ -124,7 +132,7 @@ VideoManager::isGStreamer()
{ {
#if defined(QGC_GST_STREAMING) #if defined(QGC_GST_STREAMING)
QString videoSource = _videoSettings->videoSource()->rawValue().toString(); QString videoSource = _videoSettings->videoSource()->rawValue().toString();
return videoSource == VideoSettings::videoSourceUDP || videoSource == VideoSettings::videoSourceRTSP; return videoSource == VideoSettings::videoSourceUDP || videoSource == VideoSettings::videoSourceRTSP || videoSource == VideoSettings::videoSourceTCP;
#else #else
return false; return false;
#endif #endif
...@@ -149,6 +157,8 @@ VideoManager::_updateSettings() ...@@ -149,6 +157,8 @@ VideoManager::_updateSettings()
_videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt())); _videoReceiver->setUri(QStringLiteral("udp://0.0.0.0:%1").arg(_videoSettings->udpPort()->rawValue().toInt()));
else if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceRTSP) else if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceRTSP)
_videoReceiver->setUri(_videoSettings->rtspUrl()->rawValue().toString()); _videoReceiver->setUri(_videoSettings->rtspUrl()->rawValue().toString());
else if (_videoSettings->videoSource()->rawValue().toString() == VideoSettings::videoSourceTCP)
_videoReceiver->setUri(QStringLiteral("tcp://%1").arg(_videoSettings->tcpUrl()->rawValue().toString()));
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
......
...@@ -61,6 +61,7 @@ private slots: ...@@ -61,6 +61,7 @@ private slots:
void _videoSourceChanged (); void _videoSourceChanged ();
void _udpPortChanged (); void _udpPortChanged ();
void _rtspUrlChanged (); void _rtspUrlChanged ();
void _tcpUrlChanged ();
private: private:
void _updateSettings (); void _updateSettings ();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
{ {
"name": "VideoSource", "name": "VideoSource",
"shortDescription": "Video source", "shortDescription": "Video source",
"longDescription": "Source for video. UDP, RTSP and UVC Cameras may be supported depending on Vehicle and ground station version.", "longDescription": "Source for video. UDP, TCP, RTSP and UVC Cameras may be supported depending on Vehicle and ground station version.",
"type": "string", "type": "string",
"defaultValue": "" "defaultValue": ""
}, },
...@@ -21,6 +21,13 @@ ...@@ -21,6 +21,13 @@
"type": "string", "type": "string",
"defaultValue": "" "defaultValue": ""
}, },
{
"name": "VideoTCPUrl",
"shortDescription": "Video TCP Url",
"longDescription": "TCP url address and port to bind to for video stream. Example: 192.168.143.200:3001",
"type": "string",
"defaultValue": ""
},
{ {
"name": "VideoSavePath", "name": "VideoSavePath",
"shortDescription": "Video save directory", "shortDescription": "Video save directory",
......
...@@ -22,6 +22,7 @@ const char* VideoSettings::videoSettingsGroupName = "Video"; ...@@ -22,6 +22,7 @@ const char* VideoSettings::videoSettingsGroupName = "Video";
const char* VideoSettings::videoSourceName = "VideoSource"; const char* VideoSettings::videoSourceName = "VideoSource";
const char* VideoSettings::udpPortName = "VideoUDPPort"; const char* VideoSettings::udpPortName = "VideoUDPPort";
const char* VideoSettings::rtspUrlName = "VideoRTSPUrl"; const char* VideoSettings::rtspUrlName = "VideoRTSPUrl";
const char* VideoSettings::tcpUrlName = "VideoTCPUrl";
const char* VideoSettings::videoAspectRatioName = "VideoAspectRatio"; const char* VideoSettings::videoAspectRatioName = "VideoAspectRatio";
const char* VideoSettings::videoGridLinesName = "VideoGridLines"; const char* VideoSettings::videoGridLinesName = "VideoGridLines";
const char* VideoSettings::showRecControlName = "ShowRecControl"; const char* VideoSettings::showRecControlName = "ShowRecControl";
...@@ -32,11 +33,13 @@ const char* VideoSettings::videoSourceNoVideo = "No Video Available"; ...@@ -32,11 +33,13 @@ const char* VideoSettings::videoSourceNoVideo = "No Video Available";
const char* VideoSettings::videoDisabled = "Video Stream Disabled"; const char* VideoSettings::videoDisabled = "Video Stream Disabled";
const char* VideoSettings::videoSourceUDP = "UDP Video Stream"; const char* VideoSettings::videoSourceUDP = "UDP Video Stream";
const char* VideoSettings::videoSourceRTSP = "RTSP Video Stream"; const char* VideoSettings::videoSourceRTSP = "RTSP Video Stream";
const char* VideoSettings::videoSourceTCP = "TCP-MPEG2 Video Stream";
VideoSettings::VideoSettings(QObject* parent) VideoSettings::VideoSettings(QObject* parent)
: SettingsGroup(videoSettingsGroupName, QString() /* root settings group */, parent) : SettingsGroup(videoSettingsGroupName, QString() /* root settings group */, parent)
, _videoSourceFact(NULL) , _videoSourceFact(NULL)
, _udpPortFact(NULL) , _udpPortFact(NULL)
, _tcpUrlFact(NULL)
, _rtspUrlFact(NULL) , _rtspUrlFact(NULL)
, _videoAspectRatioFact(NULL) , _videoAspectRatioFact(NULL)
, _gridLinesFact(NULL) , _gridLinesFact(NULL)
...@@ -55,6 +58,7 @@ VideoSettings::VideoSettings(QObject* parent) ...@@ -55,6 +58,7 @@ VideoSettings::VideoSettings(QObject* parent)
videoSourceList.append(videoSourceUDP); videoSourceList.append(videoSourceUDP);
#endif #endif
videoSourceList.append(videoSourceRTSP); videoSourceList.append(videoSourceRTSP);
videoSourceList.append(videoSourceTCP);
#endif #endif
#ifndef QGC_DISABLE_UVC #ifndef QGC_DISABLE_UVC
QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
...@@ -109,6 +113,15 @@ Fact* VideoSettings::rtspUrl(void) ...@@ -109,6 +113,15 @@ Fact* VideoSettings::rtspUrl(void)
return _rtspUrlFact; return _rtspUrlFact;
} }
Fact* VideoSettings::tcpUrl(void)
{
if (!_tcpUrlFact) {
_tcpUrlFact = _createSettingsFact(tcpUrlName);
}
return _tcpUrlFact;
}
Fact* VideoSettings::aspectRatio(void) Fact* VideoSettings::aspectRatio(void)
{ {
if (!_videoAspectRatioFact) { if (!_videoAspectRatioFact) {
......
...@@ -21,6 +21,7 @@ public: ...@@ -21,6 +21,7 @@ public:
Q_PROPERTY(Fact* videoSource READ videoSource CONSTANT) Q_PROPERTY(Fact* videoSource READ videoSource CONSTANT)
Q_PROPERTY(Fact* udpPort READ udpPort 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* rtspUrl READ rtspUrl CONSTANT)
Q_PROPERTY(Fact* aspectRatio READ aspectRatio CONSTANT) Q_PROPERTY(Fact* aspectRatio READ aspectRatio CONSTANT)
Q_PROPERTY(Fact* gridLines READ gridLines CONSTANT) Q_PROPERTY(Fact* gridLines READ gridLines CONSTANT)
...@@ -31,6 +32,7 @@ public: ...@@ -31,6 +32,7 @@ public:
Fact* videoSource (void); Fact* videoSource (void);
Fact* udpPort (void); Fact* udpPort (void);
Fact* rtspUrl (void); Fact* rtspUrl (void);
Fact* tcpUrl (void);
Fact* aspectRatio (void); Fact* aspectRatio (void);
Fact* gridLines (void); Fact* gridLines (void);
Fact* showRecControl (void); Fact* showRecControl (void);
...@@ -42,6 +44,7 @@ public: ...@@ -42,6 +44,7 @@ public:
static const char* videoSourceName; static const char* videoSourceName;
static const char* udpPortName; static const char* udpPortName;
static const char* rtspUrlName; static const char* rtspUrlName;
static const char* tcpUrlName;
static const char* videoAspectRatioName; static const char* videoAspectRatioName;
static const char* videoGridLinesName; static const char* videoGridLinesName;
static const char* showRecControlName; static const char* showRecControlName;
...@@ -52,9 +55,11 @@ public: ...@@ -52,9 +55,11 @@ public:
static const char* videoDisabled; static const char* videoDisabled;
static const char* videoSourceUDP; static const char* videoSourceUDP;
static const char* videoSourceRTSP; static const char* videoSourceRTSP;
static const char* videoSourceTCP;
private: private:
SettingsFact* _videoSourceFact; SettingsFact* _videoSourceFact;
SettingsFact* _tcpUrlFact;
SettingsFact* _udpPortFact; SettingsFact* _udpPortFact;
SettingsFact* _rtspUrlFact; SettingsFact* _rtspUrlFact;
SettingsFact* _videoAspectRatioFact; SettingsFact* _videoAspectRatioFact;
......
...@@ -131,8 +131,8 @@ newPadCB(GstElement* element, GstPad* pad, gpointer data) ...@@ -131,8 +131,8 @@ newPadCB(GstElement* element, GstPad* pad, gpointer data)
gchar* description = gst_caps_to_string(p_caps); gchar* description = gst_caps_to_string(p_caps);
qCDebug(VideoReceiverLog) << p_caps << ", " << description; qCDebug(VideoReceiverLog) << p_caps << ", " << description;
g_free(description); g_free(description);
GstElement* p_rtph264depay = GST_ELEMENT(data); GstElement* sink = GST_ELEMENT(data);
if(gst_element_link_pads(element, name, p_rtph264depay, "sink") == false) if(gst_element_link_pads(element, name, sink, "sink") == false)
qCritical() << "newPadCB : failed to link elements\n"; qCritical() << "newPadCB : failed to link elements\n";
g_free(name); g_free(name);
} }
...@@ -222,14 +222,16 @@ VideoReceiver::start() ...@@ -222,14 +222,16 @@ VideoReceiver::start()
bool isUdp = _uri.contains("udp://"); bool isUdp = _uri.contains("udp://");
bool isRtsp = _uri.contains("rtsp://"); bool isRtsp = _uri.contains("rtsp://");
bool isTCP = _uri.contains("tcp://");
//-- For RTSP, check to see if server is there first //-- For RTSP and TCP, check to see if server is there first
if(!_serverPresent && isRtsp) { if(!_serverPresent && (isRtsp || isTCP)) {
_timer.start(100); _timer.start(100);
return; return;
} }
bool running = false; bool running = false;
bool pipelineUp = false;
GstElement* dataSource = NULL; GstElement* dataSource = NULL;
GstCaps* caps = NULL; GstCaps* caps = NULL;
...@@ -247,6 +249,8 @@ VideoReceiver::start() ...@@ -247,6 +249,8 @@ VideoReceiver::start()
if(isUdp) { if(isUdp) {
dataSource = gst_element_factory_make("udpsrc", "udp-source"); dataSource = gst_element_factory_make("udpsrc", "udp-source");
} else if(isTCP) {
dataSource = gst_element_factory_make("tcpclientsrc", "tcpclient-source");
} else { } else {
dataSource = gst_element_factory_make("rtspsrc", "rtsp-source"); dataSource = gst_element_factory_make("rtspsrc", "rtsp-source");
} }
...@@ -262,17 +266,24 @@ VideoReceiver::start() ...@@ -262,17 +266,24 @@ VideoReceiver::start()
break; break;
} }
g_object_set(G_OBJECT(dataSource), "uri", qPrintable(_uri), "caps", caps, NULL); g_object_set(G_OBJECT(dataSource), "uri", qPrintable(_uri), "caps", caps, NULL);
} else if(isTCP) {
QUrl url(_uri);
g_object_set(G_OBJECT(dataSource), "host", qPrintable(url.host()), "port", url.port(), NULL );
} else { } else {
g_object_set(G_OBJECT(dataSource), "location", qPrintable(_uri), "latency", 17, "udp-reconnect", 1, "timeout", static_cast<guint64>(5000000), NULL); g_object_set(G_OBJECT(dataSource), "location", qPrintable(_uri), "latency", 17, "udp-reconnect", 1, "timeout", static_cast<guint64>(5000000), NULL);
} }
// Currently, we expect H264 when using anything except for TCP. Long term we may want this to be settable
if (isTCP) {
if ((demux = gst_element_factory_make("tsdemux", "mpeg2-ts-demuxer")) == NULL) {
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('tsdemux')";
break;
}
} else {
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) {
...@@ -286,6 +297,8 @@ VideoReceiver::start() ...@@ -286,6 +297,8 @@ VideoReceiver::start()
} }
if((queue = gst_element_factory_make("queue", NULL)) == NULL) { if((queue = gst_element_factory_make("queue", NULL)) == NULL) {
// TODO: We may want to add queue2 max-size-buffers=1 to get lower latency
// We should compare gstreamer scripts to QGroundControl to determine the need
qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('queue')"; qCritical() << "VideoReceiver::start() failed. Error with gst_element_factory_make('queue')";
break; break;
} }
...@@ -301,21 +314,33 @@ VideoReceiver::start() ...@@ -301,21 +314,33 @@ VideoReceiver::start()
} }
gst_bin_add_many(GST_BIN(_pipeline), dataSource, demux, parser, _tee, queue, decoder, queue1, _videoSink, NULL); gst_bin_add_many(GST_BIN(_pipeline), dataSource, demux, parser, _tee, queue, decoder, queue1, _videoSink, NULL);
pipelineUp = true;
if(isUdp) { if(isUdp) {
// Link the pipeline in front of the tee // Link the pipeline in front of the tee
if(!gst_element_link_many(dataSource, demux, parser, _tee, queue, decoder, queue1, _videoSink, NULL)) { if(!gst_element_link_many(dataSource, demux, parser, _tee, queue, decoder, queue1, _videoSink, NULL)) {
qCritical() << "Unable to link elements."; qCritical() << "Unable to link UDP elements.";
break;
}
} else if (isTCP) {
if(!gst_element_link(dataSource, demux)) {
qCritical() << "Unable to link TCP dataSource to Demux.";
break;
}
if(!gst_element_link_many(parser, _tee, queue, decoder, queue1, _videoSink, NULL)) {
qCritical() << "Unable to link TCP pipline to parser.";
break; break;
} }
g_signal_connect(demux, "pad-added", G_CALLBACK(newPadCB), parser);
} else { } else {
g_signal_connect(dataSource, "pad-added", G_CALLBACK(newPadCB), demux);
if(!gst_element_link_many(demux, parser, _tee, queue, decoder, _videoSink, NULL)) { if(!gst_element_link_many(demux, parser, _tee, queue, decoder, _videoSink, NULL)) {
qCritical() << "Unable to link elements."; qCritical() << "Unable to link RTSP elements.";
break; break;
} }
} }
dataSource = demux = parser = queue = decoder = NULL; dataSource = demux = parser = queue = decoder = queue1 = NULL;
GstBus* bus = NULL; GstBus* bus = NULL;
...@@ -338,6 +363,14 @@ VideoReceiver::start() ...@@ -338,6 +363,14 @@ VideoReceiver::start()
if (!running) { if (!running) {
qCritical() << "VideoReceiver::start() failed"; qCritical() << "VideoReceiver::start() failed";
// In newer versions, the pipeline will clean up all references that are added to it
if (_pipeline != NULL) {
gst_object_unref(_pipeline);
_pipeline = NULL;
}
// If we failed before adding items to the pipeline, then clean up
if (!pipelineUp) {
if (decoder != NULL) { if (decoder != NULL) {
gst_object_unref(decoder); gst_object_unref(decoder);
decoder = NULL; decoder = NULL;
...@@ -367,10 +400,6 @@ VideoReceiver::start() ...@@ -367,10 +400,6 @@ VideoReceiver::start()
gst_object_unref(queue); gst_object_unref(queue);
dataSource = NULL; dataSource = NULL;
} }
if (_pipeline != NULL) {
gst_object_unref(_pipeline);
_pipeline = NULL;
} }
_running = false; _running = false;
......
...@@ -555,6 +555,20 @@ QGCView { ...@@ -555,6 +555,20 @@ QGCView {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Row {
spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.settingsManager.videoSettings.tcpUrl.visible && QGroundControl.videoManager.isGStreamer && videoSource.currentIndex === 3
QGCLabel {
text: qsTr("TCP URL:")
width: _labelWidth
anchors.verticalCenter: parent.verticalCenter
}
FactTextField {
width: _editFieldWidth
fact: QGroundControl.settingsManager.videoSettings.tcpUrl
anchors.verticalCenter: parent.verticalCenter
}
}
Row { Row {
spacing: ScreenTools.defaultFontPixelWidth spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 3 && QGroundControl.settingsManager.videoSettings.aspectRatio.visible visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 3 && QGroundControl.settingsManager.videoSettings.aspectRatio.visible
...@@ -613,7 +627,7 @@ QGCView { ...@@ -613,7 +627,7 @@ QGCView {
anchors.centerIn: parent anchors.centerIn: parent
Row { Row {
spacing: ScreenTools.defaultFontPixelWidth spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 3 && QGroundControl.settingsManager.videoSettings.maxVideoSize.visible visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 4 && QGroundControl.settingsManager.videoSettings.maxVideoSize.visible
QGCLabel { QGCLabel {
text: qsTr("Max Storage Usage:") text: qsTr("Max Storage Usage:")
width: _labelWidth width: _labelWidth
...@@ -627,7 +641,7 @@ QGCView { ...@@ -627,7 +641,7 @@ QGCView {
} }
Row { Row {
spacing: ScreenTools.defaultFontPixelWidth spacing: ScreenTools.defaultFontPixelWidth
visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 3 && QGroundControl.settingsManager.videoSettings.recordingFormat.visible visible: QGroundControl.videoManager.isGStreamer && videoSource.currentIndex && videoSource.currentIndex < 4 && QGroundControl.settingsManager.videoSettings.recordingFormat.visible
QGCLabel { QGCLabel {
text: qsTr("Video File Format:") text: qsTr("Video File Format:")
width: _labelWidth width: _labelWidth
......
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