Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/build-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@
"app",
"coreelements",
"isomp4",
"jpeg",
"jpegformat",
"libav",
"matroska",
"mpegtsdemux",
"multipart",
"multifile",
"opengl",
"openh264",
Expand All @@ -49,6 +52,7 @@
"rtpmanager",
"rtsp",
"sdpelem",
"soup",
"tcp",
"typefindfunctions",
"udp",
Expand Down
4 changes: 4 additions & 0 deletions cmake/GStreamer/tests/test_plugin_policy.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ file(READ "${CMAKE_CURRENT_LIST_DIR}/../../../.github/build-config.json" QGC_BUI
gstreamer_plugins_for(PLATFORM windows OUT_VAR _plugins_windows_real)
qgc_test_assert_in_list("windows has d3d11" d3d11 _plugins_windows_real)
qgc_test_assert_in_list("windows has d3d12" d3d12 _plugins_windows_real)
qgc_test_assert_in_list("common has native JPEG decoder" jpeg _plugins_windows_real)
qgc_test_assert_in_list("common has HTTP MJPEG jpeg parser" jpegformat _plugins_windows_real)
qgc_test_assert_in_list("common has HTTP MJPEG multipart demuxer" multipart _plugins_windows_real)
qgc_test_assert_in_list("common has HTTP client source" soup _plugins_windows_real)
qgc_test_pass("plugins_for real windows d3d addenda")

set(_req videoconvertscale videoconvert videoscale x264enc)
Expand Down
4 changes: 3 additions & 1 deletion docs/en/qgc-user-guide/settings_view/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,15 @@ The _Video_ section is used to define the source and connection settings for vid

The settings are:

- **Video Source**: Video Stream Disabled | RTSP Video Stream | UDP h.264 Video Stream | UDP h.265 Video Stream | TCP-MPEG2 Video Stream | MPEG-TS Video Stream | Integrated Camera
- **Video Source**: Video Stream Disabled | RTSP Video Stream | HTTP MJPEG Video Stream | UDP h.264 Video Stream | UDP h.265 Video Stream | TCP-MPEG2 Video Stream | MPEG-TS Video Stream | Integrated Camera

::: info
If no video source is specified then no other video or _video recording_ settings will be displayed.
:::

- **URL/Port**: Connection type-specific stream address (may be port or URL).
HTTP MJPEG requires a full `http://` or `https://` URL serving
`multipart/x-mixed-replace` JPEG frames.
- **Aspect Ratio**: Aspect ratio for scaling video in video widget (set to 0.0 to ignore scaling)
- **Disabled When Disarmed**: Disable video feed when vehicle is disarmed.
- **Low Latency Mode**: Enabling low latency mode reduces the video stream latency, but may cause frame loss and choppy video (especially with a poor network connection). <!-- disables the internal jitter buffer -->
Expand Down
8 changes: 7 additions & 1 deletion docs/en/qgc-user-guide/settings_view/video.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,22 @@ Configure video streaming and recording settings.

## Video Source

- **Source** — Video Stream Disabled / RTSP Video Stream / UDP h.264 / UDP h.265 / TCP-MPEG2 / MPEG-TS / Integrated Camera
- **Source** — Video Stream Disabled / RTSP Video Stream / HTTP MJPEG Video Stream / UDP h.264 / UDP h.265 / TCP-MPEG2 / MPEG-TS / Integrated Camera

## Connection

Connection settings vary by source type:

- **RTSP URL** — full RTSP stream address
- **HTTP MJPEG URL** — full `http://` or `https://` address of a multipart MJPEG stream
- **TCP URL** — TCP stream address
- **UDP URL** — UDP stream address and port (default: `0.0.0.0:5600`)

HTTP MJPEG expects a `multipart/x-mixed-replace` response containing JPEG frames.
It does not accept a web page, a single JPEG URL, or an arbitrary HTTP video file.
HTTPS certificate validation remains enabled in GStreamer, redirects are not followed, and URL user information
(`user:password@host`) is rejected.

## Settings

- **Aspect Ratio** — aspect ratio for scaling video in the display widget (default: 16:9; set to 0.0 to disable scaling)
Expand Down
6 changes: 5 additions & 1 deletion src/AppSettings/pages/Video.SettingsUI.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@
},
{
"heading": "Connection",
"keywords": ["rtsp", "tcp", "udp", "mpegts", "video url", "stream url"],
"keywords": ["rtsp", "http", "https", "mjpeg", "jpeg", "tcp", "udp", "mpegts", "video url", "stream url"],
"showWhen": "!sourceDisabled && !autoStreamConfig",
"controls": [
{
"setting": "videoSettings.rtspUrl",
"showWhen": "videoSource === QGroundControl.settingsManager.videoSettings.rtspVideoSource"
},
{
"setting": "videoSettings.httpMjpegUrl",
"showWhen": "videoSource === QGroundControl.settingsManager.videoSettings.httpMjpegVideoSource"
},
{
"setting": "videoSettings.tcpUrl",
"showWhen": "videoSource === QGroundControl.settingsManager.videoSettings.tcpVideoSource"
Expand Down
22 changes: 16 additions & 6 deletions src/Settings/Video.SettingsGroup.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"QGC.MetaData.Facts": [
{
"name": "videoSource",
"shortDesc": "Source for video stream (UDP, TCP, RTSP, or connected USB camera).",
"longDesc": "Source for video. UDP, TCP, RTSP and UVC Cameras may be supported depending on Vehicle and ground station version.",
"shortDesc": "Source for video stream (UDP, TCP, RTSP, HTTP MJPEG, or connected USB camera).",
"longDesc": "Source for video. UDP, TCP, RTSP, HTTP multipart MJPEG and UVC cameras may be supported depending on the ground station build.",
"type": "string",
"default": "",
"label": "Source",
Expand All @@ -29,6 +29,15 @@
"label": "RTSP URL",
"keywords": "rtsp,video url,stream url"
},
{
"name": "httpMjpegUrl",
"shortDesc": "Full URL for an HTTP multipart MJPEG stream.",
"longDesc": "Full http:// or https:// URL for a multipart MJPEG stream (multipart/x-mixed-replace with JPEG frames). User information in the URL is not supported.",
"type": "string",
"default": "",
"label": "HTTP MJPEG URL",
"keywords": "http,https,mjpeg,jpeg,video url,stream url"
},
{
"name": "tcpUrl",
"shortDesc": "Network address and port for TCP video stream (e.g. 192.168.143.200:3001).",
Expand Down Expand Up @@ -117,13 +126,14 @@
},
{
"name": "rtspTimeout",
"shortDesc": "RTSP Video Timeout",
"longDesc": "How long to wait before assuming RTSP link is gone.",
"shortDesc": "Network video timeout.",
"longDesc": "How long to wait before assuming a timeout-based network video source is unavailable.",
"type": "uint32",
"min": 1,
"units": "s",
"default": 8,
"label": "RTSP Video Timeout"
"label": "Network Video Timeout",
"keywords": "rtsp,http,mjpeg,network,video timeout"
},
{
"name": "streamEnabled",
Expand Down Expand Up @@ -170,7 +180,7 @@
"type": "bool",
"default": true,
"label": "Auto-reconnect on stream loss",
"keywords": "rtsp,reconnect,watchdog,recovery,advanced"
"keywords": "rtsp,http,mjpeg,stream,reconnect,watchdog,recovery,advanced"
},
{
"name": "forceVideoDecoder",
Expand Down
17 changes: 17 additions & 0 deletions src/Settings/VideoSettings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ DECLARE_SETTINGGROUP(Video, "Video")
// Setup enum values for videoSource settings into meta data
QVariantList videoSourceList;
videoSourceList.append(videoSourceRTSP);
if (kGstEnabled) {
videoSourceList.append(videoSourceHTTPMJPEG);
}
videoSourceList.append(videoSourceUDPH264);
videoSourceList.append(videoSourceUDPH265);
videoSourceList.append(videoSourceTCP);
Expand Down Expand Up @@ -220,6 +223,15 @@ DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, rtspUrl)
return _rtspUrlFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, httpMjpegUrl)
{
if (!_httpMjpegUrlFact) {
_httpMjpegUrlFact = _createSettingsFact(httpMjpegUrlName);
connect(_httpMjpegUrlFact, &Fact::valueChanged, this, &VideoSettings::_configChanged);
}
return _httpMjpegUrlFact;
}

DECLARE_SETTINGSFACT_NO_FUNC(VideoSettings, tcpUrl)
{
if (!_tcpUrlFact) {
Expand Down Expand Up @@ -251,6 +263,11 @@ bool VideoSettings::streamConfigured(void)
qCDebug(VideoSettingsLog) << "Testing configuration for RTSP Stream:" << rtspUrl()->rawValue().toString();
return !rtspUrl()->rawValue().toString().isEmpty();
}
//-- If HTTP MJPEG, check for URL
if (vSource == videoSourceHTTPMJPEG) {
qCDebug(VideoSettingsLog) << "Testing configuration for HTTP MJPEG Stream";
return !httpMjpegUrl()->rawValue().toString().isEmpty();
}
//-- If TCP, check for URL
if(vSource == videoSourceTCP) {
qCDebug(VideoSettingsLog) << "Testing configuration for TCP Stream:" << tcpUrl()->rawValue().toString();
Expand Down
4 changes: 4 additions & 0 deletions src/Settings/VideoSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class VideoSettings : public SettingsGroup
DEFINE_SETTINGFACT(udpUrl)
DEFINE_SETTINGFACT(tcpUrl)
DEFINE_SETTINGFACT(rtspUrl)
DEFINE_SETTINGFACT(httpMjpegUrl)
DEFINE_SETTINGFACT(aspectRatio)
DEFINE_SETTINGFACT(videoFit)
DEFINE_SETTINGFACT(gridLines)
Expand All @@ -37,6 +38,7 @@ class VideoSettings : public SettingsGroup

Q_PROPERTY(bool streamConfigured READ streamConfigured NOTIFY streamConfiguredChanged)
Q_PROPERTY(QString rtspVideoSource READ rtspVideoSource CONSTANT)
Q_PROPERTY(QString httpMjpegVideoSource READ httpMjpegVideoSource CONSTANT)
Q_PROPERTY(QString udp264VideoSource READ udp264VideoSource CONSTANT)
Q_PROPERTY(QString udp265VideoSource READ udp265VideoSource CONSTANT)
Q_PROPERTY(QString tcpVideoSource READ tcpVideoSource CONSTANT)
Expand All @@ -45,6 +47,7 @@ class VideoSettings : public SettingsGroup

bool streamConfigured ();
QString rtspVideoSource () { return videoSourceRTSP; }
QString httpMjpegVideoSource () { return videoSourceHTTPMJPEG; }
QString udp264VideoSource () { return videoSourceUDPH264; }
QString udp265VideoSource () { return videoSourceUDPH265; }
QString tcpVideoSource () { return videoSourceTCP; }
Expand All @@ -59,6 +62,7 @@ class VideoSettings : public SettingsGroup
static constexpr const char* videoSourceNoVideo = QT_TRANSLATE_NOOP("VideoSettings", "No Video Available");
static constexpr const char* videoDisabled = QT_TRANSLATE_NOOP("VideoSettings", "Video Stream Disabled");
static constexpr const char* videoSourceRTSP = QT_TRANSLATE_NOOP("VideoSettings", "RTSP Video Stream");
static constexpr const char* videoSourceHTTPMJPEG = QT_TRANSLATE_NOOP("VideoSettings", "HTTP MJPEG Video Stream");
static constexpr const char* videoSourceUDPH264 = QT_TRANSLATE_NOOP("VideoSettings", "UDP h.264 Video Stream");
static constexpr const char* videoSourceUDPH265 = QT_TRANSLATE_NOOP("VideoSettings", "UDP h.265 Video Stream");
static constexpr const char* videoSourceTCP = QT_TRANSLATE_NOOP("VideoSettings", "TCP-MPEG2 Video Stream");
Expand Down
9 changes: 8 additions & 1 deletion src/VideoManager/VideoManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ void VideoManager::init(QQuickWindow *mainWindow)
(void) connect(_videoSettings->videoSource(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
(void) connect(_videoSettings->udpUrl(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
(void) connect(_videoSettings->rtspUrl(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
(void) connect(_videoSettings->httpMjpegUrl(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
(void) connect(_videoSettings->tcpUrl(), &Fact::rawValueChanged, this, &VideoManager::_videoSourceChanged);
(void) connect(_videoSettings->aspectRatio(), &Fact::rawValueChanged, this, &VideoManager::aspectRatioChanged);
(void) connect(_videoSettings->lowLatencyMode(), &Fact::rawValueChanged, this, [this](const QVariant &value) { Q_UNUSED(value); _restartAllVideos(); });
Expand Down Expand Up @@ -500,6 +501,7 @@ bool VideoManager::isStreamSource() const
VideoSettings::videoSourceUDPH264,
VideoSettings::videoSourceUDPH265,
VideoSettings::videoSourceRTSP,
VideoSettings::videoSourceHTTPMJPEG,
VideoSettings::videoSourceTCP,
VideoSettings::videoSourceMPEGTS,
VideoSettings::videoSource3DRSolo,
Expand Down Expand Up @@ -701,6 +703,8 @@ bool VideoManager::_updateSettings(VideoReceiver *receiver)
settingsChanged |= _updateVideoUri(receiver, QStringLiteral("mpegts://%1").arg(_videoSettings->udpUrl()->rawValue().toString()));
} else if (source == VideoSettings::videoSourceRTSP) {
settingsChanged |= _updateVideoUri(receiver, _videoSettings->rtspUrl()->rawValue().toString());
} else if (source == VideoSettings::videoSourceHTTPMJPEG) {
settingsChanged |= _updateVideoUri(receiver, _videoSettings->httpMjpegUrl()->rawValue().toString());
} else if (source == VideoSettings::videoSourceTCP) {
settingsChanged |= _updateVideoUri(receiver, QStringLiteral("tcp://%1").arg(_videoSettings->tcpUrl()->rawValue().toString()));
} else if (source == VideoSettings::videoSource3DRSolo) {
Expand Down Expand Up @@ -842,7 +846,10 @@ void VideoManager::_startReceiver(VideoReceiver *receiver)
}

const QString source = _videoSettings->videoSource()->rawValue().toString();
const uint32_t timeout = ((source == VideoSettings::videoSourceRTSP) ? _videoSettings->rtspTimeout()->rawValue().toUInt() : 3);
const bool usesNetworkTimeout =
(source == VideoSettings::videoSourceRTSP) || (source == VideoSettings::videoSourceHTTPMJPEG);
// Keep the existing Fact/persistence key for compatibility while its UI meaning expands to timeout-based sources.
const uint32_t timeout = usesNetworkTimeout ? _videoSettings->rtspTimeout()->rawValue().toUInt() : 3;

receiver->start(timeout);
}
Expand Down
Loading
Loading