From d8cd3f8368068e9c5528c7f8abcabebc4652be6f Mon Sep 17 00:00:00 2001 From: Andrew Voznytsa Date: Sat, 29 Feb 2020 21:10:19 +0200 Subject: [PATCH] Revert "Handle gstreamer signals on main QGC thread to avoid deadlock; Remove video sink from pipeline if pipeline failed to start" This reverts commit a9401de70ee15cf85b7d7e7fb1a6f7cb0028046f. --- src/VideoStreaming/VideoReceiver.cc | 84 +++++++++++++++++++++++++++-- src/VideoStreaming/VideoReceiver.h | 7 +++ 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/src/VideoStreaming/VideoReceiver.cc b/src/VideoStreaming/VideoReceiver.cc index 36b3ef9b0..339da10cf 100644 --- a/src/VideoStreaming/VideoReceiver.cc +++ b/src/VideoStreaming/VideoReceiver.cc @@ -66,21 +66,24 @@ VideoReceiver::VideoReceiver(QObject* parent) , _lastFrameId(G_MAXUINT64) , _lastFrameTime(0) , _restart_time_ms(1389) + , _socket(nullptr) + , _serverPresent(false) + , _tcpTestInterval_ms(5000) , _udpReconnect_us(5000000) #endif , _videoRunning(false) , _showFullScreen(false) , _videoSettings(nullptr) { - // FIXME: AV: temporal workaround to allow for Qt::QueuedConnection for gstreamer signals. Need to evaluate proper solution - perhaps QtGst will be helpful - moveToThread(qgcApp()->thread()); _videoSettings = qgcApp()->toolbox()->settingsManager()->videoSettings(); #if defined(QGC_GST_STREAMING) _restart_timer.setSingleShot(true); connect(&_restart_timer, &QTimer::timeout, this, &VideoReceiver::_restart_timeout); - connect(this, &VideoReceiver::msgErrorReceived, this, &VideoReceiver::_handleError, Qt::QueuedConnection); - connect(this, &VideoReceiver::msgEOSReceived, this, &VideoReceiver::_handleEOS, Qt::QueuedConnection); - connect(this, &VideoReceiver::msgStateChangedReceived, this, &VideoReceiver::_handleStateChanged, Qt::QueuedConnection); + _tcp_timer.setSingleShot(true); + connect(&_tcp_timer, &QTimer::timeout, this, &VideoReceiver::_tcp_timeout); + connect(this, &VideoReceiver::msgErrorReceived, this, &VideoReceiver::_handleError); + connect(this, &VideoReceiver::msgEOSReceived, this, &VideoReceiver::_handleEOS); + connect(this, &VideoReceiver::msgStateChangedReceived, this, &VideoReceiver::_handleStateChanged); connect(&_frameTimer, &QTimer::timeout, this, &VideoReceiver::_updateTimer); _frameTimer.start(1000); #endif @@ -441,6 +444,68 @@ VideoReceiver::_restart_timeout() } #endif +//----------------------------------------------------------------------------- +#if defined(QGC_GST_STREAMING) +void +VideoReceiver::_tcp_timeout() +{ + //-- If socket is live, we got no connection nor a socket error + delete _socket; + _socket = nullptr; + + 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); + //-- If RTSP and no port is defined, set default RTSP port (554) + if(_uri.contains("rtsp://") && url.port() <= 0) { + url.setPort(554); + } + _socket = new QTcpSocket; + QNetworkProxy tempProxy; + tempProxy.setType(QNetworkProxy::DefaultProxy); + _socket->setProxy(tempProxy); + connect(_socket, static_cast(&QTcpSocket::error), this, &VideoReceiver::_socketError); + connect(_socket, &QTcpSocket::connected, this, &VideoReceiver::_connected); + _socket->connectToHost(url.host(), static_cast(url.port())); + _tcp_timer.start(_tcpTestInterval_ms); + } +} +#endif + +//----------------------------------------------------------------------------- +#if defined(QGC_GST_STREAMING) +void +VideoReceiver::_connected() +{ + //-- Server showed up. Now we start the stream. + _tcp_timer.stop(); + _socket->deleteLater(); + _socket = nullptr; + if(_videoSettings->streamEnabled()->rawValue().toBool()) { + _serverPresent = true; + start(); + } +} +#endif + +//----------------------------------------------------------------------------- +#if defined(QGC_GST_STREAMING) +void +VideoReceiver::_socketError(QAbstractSocket::SocketError socketError) +{ + Q_UNUSED(socketError); + _socket->deleteLater(); + _socket = nullptr; + //-- Try again in a while + if(_videoSettings->streamEnabled()->rawValue().toBool()) { + _tcp_timer.start(_tcpTestInterval_ms); + } +} +#endif + //----------------------------------------------------------------------------- // When we finish our pipeline will look like this: // @@ -480,6 +545,8 @@ VideoReceiver::start() return; } + bool useTcpConnection = uri.contains("rtsp://") || uri.contains("tcp://"); + if (_videoSink == nullptr) { qCWarning(VideoReceiverLog) << "Failed because video sink is not set"; return; @@ -491,6 +558,12 @@ VideoReceiver::start() _starting = true; + //-- For RTSP and TCP, check to see if server is there first + if(!_serverPresent && useTcpConnection) { + _tcp_timer.start(100); + return; + } + _lastFrameId = G_MAXUINT64; _lastFrameTime = 0; @@ -664,6 +737,7 @@ VideoReceiver::_shutdownPipeline() { _pipeline = nullptr; delete _sink; _sink = nullptr; + _serverPresent = false; _streaming = false; _recording = false; _stopping = false; diff --git a/src/VideoStreaming/VideoReceiver.h b/src/VideoStreaming/VideoReceiver.h index 7f6e73a88..bb059e540 100644 --- a/src/VideoStreaming/VideoReceiver.h +++ b/src/VideoStreaming/VideoReceiver.h @@ -87,6 +87,9 @@ protected slots: GstElement* _makeSource (const QString& uri); GstElement* _makeFileSink (const QString& videoFile, unsigned format); virtual void _restart_timeout (); + virtual void _tcp_timeout (); + virtual void _connected (); + virtual void _socketError (QAbstractSocket::SocketError socketError); virtual void _handleError (); virtual void _handleEOS (); virtual void _handleStateChanged (); @@ -133,6 +136,10 @@ protected: QTimer _frameTimer; QTimer _restart_timer; int _restart_time_ms; + QTimer _tcp_timer; + QTcpSocket* _socket; + bool _serverPresent; + int _tcpTestInterval_ms; //-- RTSP UDP reconnect timeout uint64_t _udpReconnect_us; -- 2.22.0