RTSP Receiver¶
MediaX can receive video from an RTSP server such as an IP camera. RTSP (RFC 2326) only negotiates and controls the session. The video itself travels as ordinary RTP, so the existing codec depayloaders do the depacketising and decoding.
Scope
This is a receiver (client) only. RTSPS (TLS), audio tracks, SRTP and an RTSP server are not implemented. The Qt6 player example can additionally show HLS, MJPEG and JPEG snapshot web streams, see Examples. Decoding currently uses the OpenH264 software decoder (H.264). H.265 and AV1 sessions are parsed, but need a decoder backend that supports external transport (see Decoder backends).
Quick start¶
#include "rtsp/rtsp_depayloader.h"
mediax::rtsp::RtspDepayloader rx;
rx.SetUrl("rtsp://192.168.1.10:554/stream1");
rx.SetCredentials("user", "password");
if (!rx.Open()) {
std::cerr << rx.GetLastError() << "\n";
return 1;
}
rx.Start();
mediax::rtp::RtpFrameData frame;
while (rx.Receive(&frame, 1000)) {
// frame.cpu_buffer holds RGB24 pixels, frame.resolution the size
}
rx.Close();
RtspDepayloader derives from mediax::rtp::RtpDepayloader, so it can be used wherever another depayloader is used:
Receive(), RegisterCallback() (register before Open()), SetOutputMode() and SetRecordingFilename() for
recording to Matroska all work the same way.
Transports¶
| Mode | RtspTransportMode |
Notes |
|---|---|---|
| Automatic | kAuto (default) |
UDP unicast first, TCP interleaved if the server rejects UDP or no media arrives |
| UDP | kUdp |
RTP/RTCP on an even/odd port pair, optionally restricted with rtp_port_min/rtp_port_max |
| Multicast | kMulticast |
IPv4 only |
| TCP | kTcp |
RTP interleaved on the RTSP connection, the best choice through firewalls and NAT |
mediax::rtsp::RtspClientConfig config;
config.transport = mediax::rtsp::RtspTransportMode::kTcp;
config.media_timeout_ms = 5000;
rx.SetClientConfig(config);
Authentication¶
Basic and Digest (MD5) authentication are supported. Credentials can be given with SetCredentials() or in the URL.
Credentials are only sent to the host in the URL and are never logged. Basic sends the password unprotected, so
prefer Digest or a trusted network.
Reliability¶
- RTCP receiver reports are sent every
rtcp_interval_ms(default 5 s). - A keep-alive (
GET_PARAMETERorOPTIONS) is sent at half the session timeout. - If the connection drops, or no media arrives for
media_timeout_ms, the client reconnects with exponential backoff (reconnect_initial_delay_msup toreconnect_max_delay_ms, at mostmax_reconnect_attemptstries). Register a state callback to followkReconnecting,kPlayingandkError. GetStatistics()returns packets received and lost, jitter and the number of reconnects.
Checking whether a stream is live¶
mediax::rtsp::ProbeRtspStream() answers "is this stream up?" without opening a decoder or delivering frames:
#include "rtsp/rtsp_probe.h"
mediax::rtsp::RtspProbeOptions options;
options.level = mediax::rtsp::RtspProbeLevel::kMedia; // or kDescribe, the default
options.timeout_ms = 5000;
auto result = mediax::rtsp::ProbeRtspStream("rtsp://camera/stream", options);
if (result.IsLive()) {
// result.tracks, result.first_packet_ms, result.transport
} else {
std::cerr << result.error << "\n"; // never contains credentials
}
| Level | What it does | Proves |
|---|---|---|
kDescribe (default) |
Connect, OPTIONS, DESCRIBE | Server reachable, credentials accepted, stream exists. Never touches the stream |
kMedia |
Also SETUP and PLAY the first video track, wait for one RTP packet, TEARDOWN | Media is actually flowing |
The result also reports reachable, described, media_flowing, the track list and timings, so a stream that is
described but silent can be told apart from one that is missing. kAuto transport probes over TCP interleaved
first (it works through firewalls) and falls back to UDP if the server refuses TCP.
The Qt6 player has the same check on the command line, for RTSP and also for HLS, MJPEG and JPEG snapshot URLs.
It prints one LIVE or DEAD line per URL and exits with status 0 only if all are live:
./build/bin/qt6-rtsp-player --probe rtsp://camera/stream https://host/live/playlist.m3u8
For HLS it checks that the playlist is not a finished recording and that the newest segment can be downloaded.
Encoded access units¶
To receive the compressed access units as well (for example to forward or store them), register an encoded frame
callback before Open():
rx.RegisterEncodedFrameCallback([](const mediax::rtp::EncodedFrameData& au) {
// au.data / au.size, au.is_keyframe, au.pts_us
});
Lower level API¶
mediax::rtsp::RtspClient is the control plane on its own. It negotiates the session and hands each RTP packet to
a handler, without decoding:
mediax::rtsp::RtspClient client;
client.SetUrl("rtsp://camera/stream");
client.RegisterRtpHandler(0, [](const uint8_t* rtp, size_t size) { /* one RTP packet */ });
client.Open([](const mediax::rtsp::RtspTrackInfo& t) { return t.media_type == "video"; });
client.Play();
RtspTrackInfo carries the codec, payload type, clock rate and the sprop-parameter-sets from the SDP.
Decoder backends¶
mediax::rtp::DepayloaderFactory selects the decoder for a track. A depayloader can be driven by RTSP when
SupportsExternalTransport() returns true; it then receives packets through PushRtpPacket() instead of opening its
own socket. Currently implemented by RtpH264OpenH264Depayloader (requires -DBUILD_OPENH264=ON).
Use RtspDepayloader::SetDecoderFactory() to supply your own.
Qt6 and Python¶
- Qt6:
mediax::qt6::QtRtspDepayloader(-DBUILD_QT6=ON) is signal driven and never blocks the GUI thread:play()/stopPlayback(), properties (url,transport,state),frameReady(QImage),errorOccurredand an asynchronousprobe(). See the Qt6 API reference. - Python:
rtsp_depayloadermodule (-DBUILD_PYTHON=ON). UseReceive()to poll frames.
Examples¶
Qt6 player¶
qt6-rtsp-player (built with -DEXAMPLES=ON when Qt6 Widgets is installed) plays RTSP and web streams. Paste a URL
(credentials may be included) into the bar at the top and press Play or Enter. Ctrl+F toggles full screen
(Esc or double click also leave it), Ctrl+L focuses the URL bar. The RTSP transport can be chosen in the bar.
| URL | How it plays |
|---|---|
rtsp:// |
MediaX RTSP receiver, H.264 (needs -DBUILD_OPENH264=ON) |
http(s):// MJPEG stream |
Decoded in the player (needs Qt6 Network), Basic authentication supported in the URL |
http(s):// single JPEG |
Snapshot camera, reloaded every 5 seconds (--refresh) |
http(s)://...m3u8 |
HLS, decoded by ffmpeg, which must be installed. Only http(s) playlists and segments are allowed |
./build/bin/qt6-rtsp-player # paste the URL in the window
./build/bin/qt6-rtsp-player --transport=tcp rtsp://192.168.1.10/stream1
./build/bin/qt6-rtsp-player http://192.168.1.20/video.mjpg
./build/bin/qt6-rtsp-player --fullscreen --show-seconds 30 https://host/live/playlist.m3u8
./build/bin/qt6-rtsp-player --probe rtsp://192.168.1.10/stream1 # is it live? no window
| Option | Description |
|---|---|
[url] |
rtsp:// or http(s):// URL to play immediately |
-f, --fullscreen |
Start in full screen |
-n, --seconds <s> |
Exit after this many seconds from launch |
--show-seconds <s> |
Exit this many seconds after the first video frame is shown. Slow streams (HLS can take 2 to 15 s to start) still get their full time. Gives up after 30 more seconds without video |
-r, --refresh <s> |
Reload interval for snapshot cameras, default 5, 0 disables |
-t, --transport <t> |
RTSP transport: auto, udp or tcp |
--probe |
Check whether the URL(s) are live without playing them, print LIVE/DEAD lines, exit 0 only if all are live |
--probe-timeout <s> |
Seconds to wait for each probe, default 8 |
Playlist script¶
example/scripts/rtsp-playlist.sh shows a list of streams one after another in full screen:
./example/scripts/rtsp-playlist.sh # 12 built-in camera snapshots
./example/scripts/rtsp-playlist.sh -c -s 10 example/scripts/hls-playlist.txt # live HLS feeds
./example/scripts/rtsp-playlist.sh -l my-cameras.txt # loop your own list
| Option | Description |
|---|---|
-s <seconds> |
How long each stream is shown once its first frame appears, default 5 |
-c |
Probe every stream first and skip those that are not live |
-l |
Loop forever |
-p <path> |
Path to qt6-rtsp-player |
FILE |
One URL per line, blank lines and # comments ignored |
Console receiver¶
rtsp-receive is a console version (built with -DEXAMPLES=ON). The password is read from RTSP_PASSWORD so it does
not appear in the process list:
RTSP_PASSWORD=secret ./build/bin/rtsp-receive --url=rtsp://192.168.1.10/stream1 --user=admin \
--transport=tcp --record=capture.mkv --duration=30
Build option¶
RTSP support is built by default and can be disabled with -DBUILD_RTSP=OFF. It is not available on Windows.