Commit 5b517ec4 authored by Tomaz Canabrava's avatar Tomaz Canabrava

Remove QGCApplication and VideoSettings from the VideoReceiver

The VideoReceiver should work 'as is', without depending on the
whole application or in the settings. This patch removes all the
hard dependencies on QGroundControl, FactSystem and Settings system
so it's easier to isolate and test the code.
parent 7d870207
......@@ -71,7 +71,7 @@ public:
void reportMissingParameter(int componentId, const QString& name);
/// Show a non-modal message to the user
void showMessage(const QString& message);
Q_SLOT void showMessage(const QString& message);
/// @return true: Fake ui into showing mobile interface
bool fakeMobile(void) const { return _fakeMobile; }
......
......@@ -167,5 +167,5 @@ bool VideoSettings::streamConfigured(void)
void VideoSettings::_configChanged(QVariant)
{
emit streamConfiguredChanged();
emit streamConfiguredChanged(streamConfigured());
}
......@@ -60,7 +60,7 @@ public:
static const char* videoSourceMPEGTS;
signals:
void streamConfiguredChanged ();
void streamConfiguredChanged (bool configured);
private slots:
void _configChanged (QVariant value);
......
......@@ -53,6 +53,8 @@ VideoManager::setToolbox(QGCToolbox *toolbox)
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
qmlRegisterUncreatableType<VideoManager> ("QGroundControl.VideoManager", 1, 0, "VideoManager", "Reference only");
qmlRegisterUncreatableType<VideoReceiver>("QGroundControl", 1, 0, "VideoReceiver","Reference only");
// TODO: Those connections should be Per Video, not per VideoManager.
_videoSettings = toolbox->settingsManager()->videoSettings();
QString videoSource = _videoSettings->videoSource()->rawValue().toString();
connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
......@@ -72,7 +74,69 @@ VideoManager::setToolbox(QGCToolbox *toolbox)
emit isGStreamerChanged();
qCDebug(VideoManagerLog) << "New Video Source:" << videoSource;
_videoReceiver = toolbox->corePlugin()->createVideoReceiver(this);
_videoReceiver->setUnittestMode(qgcApp()->runningUnitTests());
_thermalVideoReceiver = toolbox->corePlugin()->createVideoReceiver(this);
_thermalVideoReceiver->setUnittestMode(qgcApp()->runningUnitTests());
_videoReceiver->moveToThread(qgcApp()->thread());
_thermalVideoReceiver->moveToThread(qgcApp()->thread());
// Those connects are temporary: In a perfect world those connections are going to be done on the Qml
// but because currently the videoReceiver is created in the C++ world, this is easier.
// The fact returning a QVariant is a quite annoying to use proper signal / slot connection.
_updateSettings();
auto appSettings = toolbox->settingsManager()->appSettings();
for (auto *videoReceiver : { _videoReceiver, _thermalVideoReceiver}) {
// First, Setup the current values from the settings.
videoReceiver->setRtspTimeout(_videoSettings->rtspTimeout()->rawValue().toInt());
videoReceiver->setMaxVideoSize(_videoSettings->maxVideoSize()->rawValue().toInt());
videoReceiver->setStreamEnabled(_videoSettings->streamEnabled()->rawValue().toBool());
videoReceiver->setRecordingFormatId(_videoSettings->recordingFormat()->rawValue().toInt());
videoReceiver->setStreamConfigured(_videoSettings->streamConfigured());
videoReceiver->setStorageLimit(_videoSettings->enableStorageLimit()->rawValue().toBool());
connect(_videoSettings->rtspTimeout(), &Fact::rawValueChanged,
videoReceiver, [videoReceiver](const QVariant &value) {
videoReceiver->setRtspTimeout(value.toInt());
}
);
connect(_videoSettings->maxVideoSize(), &Fact::rawValueChanged,
videoReceiver, [videoReceiver](const QVariant &value) {
videoReceiver->setMaxVideoSize(value.toInt());
}
);
connect(_videoSettings->streamEnabled(), &Fact::rawValueChanged,
videoReceiver, [videoReceiver](const QVariant &value) {
videoReceiver->setStreamEnabled(value.toBool());
}
);
connect(_videoSettings->recordingFormat(), &Fact::rawValueChanged,
videoReceiver, [videoReceiver](const QVariant &value) {
videoReceiver->setRecordingFormatId(value.toInt());
}
);
connect(_videoSettings->enableStorageLimit(), &Fact::rawValueChanged,
videoReceiver, [videoReceiver](const QVariant &value) {
videoReceiver->setStorageLimit(value.toInt());
}
);
// Why some options are facts while others aren't?
connect(_videoSettings, &VideoSettings::streamConfiguredChanged, videoReceiver, &VideoReceiver::setStreamConfigured);
// Fix those.
// connect(appSettings, &Fact::rawValueChanged, videoReceiver, &VideoReceiver::setVideoPath);
// connect(appSettings->videoSavePath(), &Fact::rawValueChanged, videoReceiver, &VideoReceiver::setImagePath);
// Connect the video receiver with the rest of the app.
connect(videoReceiver, &VideoReceiver::restartTimeout, this, &VideoManager::restartVideo);
connect(videoReceiver, &VideoReceiver::sendMessage, qgcApp(), &QGCApplication::showMessage);
}
_updateSettings();
if(isGStreamer()) {
startVideo();
......
......@@ -15,8 +15,6 @@
*/
#include "VideoReceiver.h"
#include "SettingsManager.h"
#include "QGCApplication.h"
#include "VideoManager.h"
#ifdef QGC_GST_TAISYNC_ENABLED
#include "TaisyncHandler.h"
......@@ -70,14 +68,16 @@ VideoReceiver::VideoReceiver(QObject* parent)
#endif
, _videoRunning(false)
, _showFullScreen(false)
, _videoSettings(nullptr)
, _streamEnabled(false)
, _streamConfigured(false)
, _storageLimit(false)
, _unittTestMode(false)
, _isTaisync(false)
{
// 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(&_restart_timer, &QTimer::timeout, this, &VideoReceiver::restartTimeout);
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);
......@@ -433,12 +433,128 @@ VideoReceiver::_makeSource(const QString& uri)
return srcbin;
}
//-----------------------------------------------------------------------------
void
VideoReceiver::_restart_timeout()
bool VideoReceiver::streamEnabled() const
{
return _streamEnabled;
}
void VideoReceiver::setStreamEnabled(bool enabled)
{
if (_streamEnabled != enabled) {
_streamEnabled = enabled;
emit streamEnabledChanged();
}
}
bool VideoReceiver::streamConfigured() const
{
return _streamConfigured;
}
void VideoReceiver::setStreamConfigured(bool enabled)
{
if (_streamConfigured != enabled) {
_streamConfigured = enabled;
emit streamEnabledChanged();
}
}
bool VideoReceiver::storageLimit() const
{
return _storageLimit;
}
void VideoReceiver::setStorageLimit(bool enabled)
{
if (_storageLimit != enabled) {
_storageLimit = enabled;
emit storageLimitChanged();
}
}
bool VideoReceiver::isTaisync() const
{
return _isTaisync;
}
void VideoReceiver::setIsTaysinc(bool enabled)
{
if (_isTaisync != enabled) {
_isTaisync = enabled;
emit isTaisyncChanged();
}
}
QString VideoReceiver::videoPath() const
{
return _videoPath;
}
void VideoReceiver::setVideoPath(const QString& value)
{
if (_videoPath != value) {
_videoPath = value;
emit videoPathChanged();
}
}
QString VideoReceiver::imagePath() const
{
return _imagePath;
}
void VideoReceiver::setImagePath(const QString& value)
{
if (_imagePath != value) {
_imagePath = value;
emit imagePathChanged();
}
}
int VideoReceiver::maxVideoSize() const
{
return _maxVideoSize;
}
void VideoReceiver::setMaxVideoSize(int value)
{
if (_maxVideoSize != value) {
_maxVideoSize = value;
emit maxVideoSizeChanged();
}
}
int VideoReceiver::recordingFormatId() const
{
qgcApp()->toolbox()->videoManager()->restartVideo();
return _recordingFormatId;
}
void VideoReceiver::setRecordingFormatId(int value)
{
if (_recordingFormatId != value && value < (int) NUM_MUXES) {
_recordingFormatId = value;
emit recordingFormatIdChanged();
}
}
int VideoReceiver::rtspTimeout() const
{
return _rtspTimeout;
}
void VideoReceiver::setRtspTimeout(int value)
{
if (_rtspTimeout != value) {
_rtspTimeout = value;
emit rtspTimeoutChanged();
}
}
void VideoReceiver::setUnittestMode(bool runUnitTests)
{
_unittTestMode = runUnitTests;
}
#endif
//-----------------------------------------------------------------------------
......@@ -454,11 +570,10 @@ void
VideoReceiver::start()
{
qCDebug(VideoReceiverLog) << "Starting " << _uri;
if(qgcApp()->runningUnitTests()) {
if(_unittTestMode) {
return;
}
if(!_videoSettings->streamEnabled()->rawValue().toBool() ||
!_videoSettings->streamConfigured()) {
if(!_streamEnabled || !_streamConfigured) {
qCDebug(VideoReceiverLog) << "Stream not enabled/configured";
return;
}
......@@ -470,7 +585,7 @@ VideoReceiver::start()
#if defined(QGC_GST_TAISYNC_ENABLED) && (defined(__android__) || defined(__ios__))
//-- Taisync on iOS or Android sends a raw h.264 stream
if (qgcApp()->toolbox()->videoManager()->isTaisync()) {
if (_isTaisync) {
uri = QString("tsusb://0.0.0.0:%1").arg(TAISYNC_VIDEO_UDP_PORT);
}
#endif
......@@ -609,7 +724,7 @@ VideoReceiver::start()
void
VideoReceiver::stop()
{
if(qgcApp() && qgcApp()->runningUnitTests()) {
if(_unittTestMode) {
return;
}
#if defined(QGC_GST_STREAMING)
......@@ -768,8 +883,8 @@ void
VideoReceiver::_cleanupOldVideos()
{
//-- Only perform cleanup if storage limit is enabled
if(_videoSettings->enableStorageLimit()->rawValue().toBool()) {
QString savePath = qgcApp()->toolbox()->settingsManager()->appSettings()->videoSavePath();
if(_storageLimit) {
QString savePath = _videoPath;
QDir videoDir = QDir(savePath);
videoDir.setFilter(QDir::Files | QDir::Readable | QDir::NoSymLinks | QDir::Writable);
videoDir.setSorting(QDir::Time);
......@@ -784,7 +899,7 @@ VideoReceiver::_cleanupOldVideos()
if(!vidList.isEmpty()) {
uint64_t total = 0;
//-- Settings are stored using MB
uint64_t maxSize = (_videoSettings->maxVideoSize()->rawValue().toUInt() * 1024 * 1024);
uint64_t maxSize = _maxVideoSize * 1024 * 1024;
//-- Compute total used storage
for(int i = 0; i < vidList.size(); i++) {
total += vidList[i].size();
......@@ -942,18 +1057,18 @@ VideoReceiver::startRecording(const QString &videoFile)
return;
}
uint32_t muxIdx = _videoSettings->recordingFormat()->rawValue().toUInt();
uint32_t muxIdx = _recordingFormatId;
if(muxIdx >= NUM_MUXES) {
qgcApp()->showMessage(tr("Invalid video format defined."));
emit sendMessage(tr("Invalid video format defined."));
return;
}
//-- Disk usage maintenance
_cleanupOldVideos();
QString savePath = qgcApp()->toolbox()->settingsManager()->appSettings()->videoSavePath();
QString savePath = _videoPath;
if(savePath.isEmpty()) {
qgcApp()->showMessage(tr("Unabled to record video. Video save path must be specified in Settings."));
emit sendMessage(tr("Unabled to record video. Video save path must be specified in Settings."));
return;
}
......@@ -1175,11 +1290,7 @@ VideoReceiver::_updateTimer()
}
if(_videoRunning) {
uint32_t timeout = 1;
if(qgcApp()->toolbox() && qgcApp()->toolbox()->settingsManager()) {
timeout = _videoSettings->rtspTimeout()->rawValue().toUInt();
}
uint32_t timeout = _rtspTimeout;
const qint64 now = QDateTime::currentSecsSinceEpoch();
if(now - _lastFrameTime > timeout) {
......@@ -1189,7 +1300,7 @@ VideoReceiver::_updateTimer()
}
} else {
// FIXME: AV: if pipeline is _running but not _streaming for some time then we need to restart
if(!_stop && !_running && !_uri.isEmpty() && _videoSettings->streamEnabled()->rawValue().toBool()) {
if(!_stop && !_running && !_uri.isEmpty() && _streamEnabled) {
start();
}
}
......
......@@ -39,11 +39,62 @@ public:
Q_PROPERTY(bool videoRunning READ videoRunning NOTIFY videoRunningChanged)
Q_PROPERTY(QString imageFile READ imageFile NOTIFY imageFileChanged)
Q_PROPERTY(QString videoFile READ videoFile NOTIFY videoFileChanged)
Q_PROPERTY(QString imagePath READ imagePath NOTIFY imagePathChanged)
Q_PROPERTY(QString videoPath READ videoPath NOTIFY videoPathChanged)
Q_PROPERTY(bool showFullScreen READ showFullScreen WRITE setShowFullScreen NOTIFY showFullScreenChanged)
Q_PROPERTY(bool streamEnabled READ streamEnabled WRITE setStreamEnabled NOTIFY streamEnabledChanged)
Q_PROPERTY(bool streamConfigured READ streamConfigured WRITE setStreamConfigured NOTIFY streamConfiguredChanged)
Q_PROPERTY(bool storageLimit READ storageLimit WRITE setStorageLimit NOTIFY storageLimitChanged)
Q_PROPERTY(bool isTaisync READ isTaisync WRITE setIsTaysinc NOTIFY isTaisyncChanged)
Q_PROPERTY(int maxVideoSize READ maxVideoSize WRITE setMaxVideoSize NOTIFY maxVideoSizeChanged)
Q_PROPERTY(int recordingFormatId READ recordingFormatId WRITE setRecordingFormatId NOTIFY recordingFormatIdChanged)
Q_PROPERTY(int rtspTimeout READ rtspTimeout WRITE setRtspTimeout NOTIFY rtspTimeoutChanged)
explicit VideoReceiver(QObject* parent = nullptr);
~VideoReceiver();
bool streamEnabled() const;
Q_SLOT void setStreamEnabled(bool enabled);
Q_SIGNAL void streamEnabledChanged();
bool streamConfigured() const;
Q_SLOT void setStreamConfigured(bool enabled);
Q_SIGNAL void streamConfiguredChanged();
bool storageLimit() const;
Q_SLOT void setStorageLimit(bool enabled);
Q_SIGNAL void storageLimitChanged();
bool isTaisync() const;
Q_SLOT void setIsTaysinc(bool value);
Q_SIGNAL void isTaisyncChanged();
QString videoPath() const;
Q_SLOT void setVideoPath(const QString& path);
Q_SIGNAL void videoPathChanged();
QString imagePath() const;
Q_SLOT void setImagePath(const QString& path);
Q_SIGNAL void imagePathChanged();
int maxVideoSize() const;
Q_SLOT void setMaxVideoSize(int value);
Q_SIGNAL void maxVideoSizeChanged();
int recordingFormatId() const;
Q_SLOT void setRecordingFormatId(int value);
Q_SIGNAL void recordingFormatIdChanged();
int rtspTimeout() const;
Q_SLOT void setRtspTimeout(int value);
Q_SIGNAL void rtspTimeoutChanged();
Q_SIGNAL void restartTimeout();
Q_SIGNAL void sendMessage(const QString& message);
void setUnittestMode(bool runUnitTests);
#if defined(QGC_GST_STREAMING)
virtual bool recording () { return _recording; }
#endif
......@@ -86,7 +137,6 @@ protected slots:
#if defined(QGC_GST_STREAMING)
GstElement* _makeSource (const QString& uri);
GstElement* _makeFileSink (const QString& videoFile, unsigned format);
virtual void _restart_timeout ();
virtual void _handleError ();
virtual void _handleEOS ();
virtual void _handleStateChanged ();
......@@ -141,8 +191,19 @@ protected:
QString _uri;
QString _imageFile;
QString _videoFile;
QString _videoPath;
QString _imagePath;
bool _videoRunning;
bool _showFullScreen;
VideoSettings* _videoSettings;
bool _streamEnabled;
bool _streamConfigured;
bool _storageLimit;
bool _unittTestMode;
bool _isTaisync;
int _maxVideoSize; // in mbs.
int _recordingFormatId; // 0 - 2, defined in VideoReceiver.cc / kVideoExtensions. TODO: use a better representation.
int _rtspTimeout;
};
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