Qt6 API Reference¶
Qt6 bindings for MediaX video streaming with GUI integration.
Overview¶
MediaX Qt6 provides thin QObject wrappers around the payloaders, depayloaders and SAP classes, so they can be used
with signals and slots. They are built into the static library libmediaxqt.a (target MediaX::Qt6):
QtRtpPayloaderandQtRtpDepayloader- abstract base classes for every codec wrapper (see the table below)QtSapListener,QtSapAnnouncer,QtSapSessionManager- SAP discovery and announcement with Qt signalsQtRtspDepayloader,QtSrtDepayloader- signal driven network receiversQtCastDiscovery,QtCastSender- detect Chromecasts and cast video to themQtAndroidMulticastLock- Android Wi-Fi multicast lock
Installation¶
Qt6 bindings require:
- Qt6 Core and Widgets
- MediaX core library
# Install dependencies
sudo apt install qt6-base-dev
# Build with Qt6 support
cmake -DBUILD_QT6=ON ..
Payloader and Depayloader Wrappers¶
Every wrapper derives from mediax::qt6::QtRtpPayloader (transmit) or mediax::qt6::QtRtpDepayloader (receive). Which
wrappers are built depends on the same options and detected libraries as the C++ backends.
| Wrapper | Codec and backend | Built when |
|---|---|---|
QtRtpUncompressedPayloader / QtRtpUncompressedDepayloader |
Uncompressed RFC 4421 | Always |
QtRtpOpenH264Payloader / QtRtpOpenH264Depayloader |
H.264, OpenH264 software | BUILD_OPENH264=ON |
QtRtpVaapiH264Payloader / QtRtpVaapiH264Depayloader |
H.264, VAAPI | libva found |
QtRtpVaapiH265Payloader / QtRtpVaapiH265Depayloader |
H.265, VAAPI (classes QtRtpH265Payloader and QtRtpH265Depayloader) |
libva found |
QtRtpNvencH264Payloader / QtRtpNvdecH264Depayloader |
H.264, NVIDIA NVENC / NVDEC | NVENC_SUPPORTED=ON |
QtRtpJetsonAv1Depayloader |
AV1 decode, Jetson Multimedia API | Jetson Multimedia API installed |
QtRtpAndroidPayloader / QtRtpAndroidDepayloader |
H.264, Android AMediaCodec | Android NDK build |
QtRtpJpegPayloader / QtRtpJpegDepayloader |
JPEG, RFC 2435 | BUILD_JPEG=ON and libjpeg found |
QtRtspDepayloader |
RTSP client | BUILD_RTSP=ON |
QtSrtDepayloader |
SRT receiver | BUILD_SRT=ON |
QtCastDiscovery / QtCastSender |
Chromecast discovery and casting (plain QObjects, not payloaders) |
BUILD_CAST=ON and OpenSSL found |
There are no Qt6 wrappers for the Jetson H.264, V4L2 M2M, HLS or AV1 VAAPI backends, use the C++ classes from a worker thread for those.
All payloaders share setStreamInfo(), open(), start(), stop(), close() and transmit(Frame*, bool blocking).
All depayloaders share setStreamInfo(), open(), start(), stop(), close(), receive(QByteArray*, int timeout),
getBuffer(), getState() and the newFrame(Frame) signal.
Receiving¶
#include "qt6/QtRtpVaapiH264Depayloader.h"
mediax::rtp::StreamInformation stream_info;
stream_info.hostname = "239.192.1.1";
stream_info.port = 5004;
stream_info.width = 1920;
stream_info.height = 1080;
stream_info.encoding = mediax::rtp::ColourspaceType::kColourspaceH264Part10;
auto* rx = new mediax::qt6::QtRtpVaapiH264Depayloader(this);
rx->setStreamInfo(stream_info);
connect(rx, &mediax::qt6::QtRtpDepayloader::newFrame, this, [](Frame frame) { /* RGB24 */ });
rx->open();
rx->start();
Transmitting¶
#include "qt6/QtRtpOpenH264Payloader.h"
auto* tx = new mediax::qt6::QtRtpOpenH264Payloader(this);
tx->setStreamInfo(stream_info); // session_name, hostname, port, width, height, framerate, encoding
tx->open();
tx->start();
// per frame:
tx->transmit(&frame); // frame is a Frame (qt6/QtCommon.h) holding RGB24
QtSapListener¶
SAP discovery with Qt signal/slot integration. It is a singleton, obtained with QtSapListener::getInstance().
#include "qt6/QtSapListener.h"
| Member | Description |
|---|---|
start() / stop() |
Start and stop listening for SAP announcements |
getInstance() |
Static, returns the shared listener |
sapData(QString name, SdpMessage message) |
Signal for each announcement received |
auto& listener = mediax::qt6::QtSapListener::getInstance();
QObject::connect(&listener, &mediax::qt6::QtSapListener::sapData,
[](const QString name, const mediax::sap::SdpMessage message) {
qDebug() << "Discovered:" << name;
});
listener.start();
QtSapSessionManager¶
Tracks the sessions discovered by QtSapListener, merges repeated announcements and expires stale sessions.
#include "qt6/QtSapSessionManager.h"
| Member | Description |
|---|---|
start() / stop() / isRunning() |
Control the manager |
sessions() |
All known sessions as QList<SdpMessage> |
sessionByKey(key) |
One session |
sessionAdded(info), sessionUpdated(info), sessionRemoved(key) |
Signals |
QtSapAnnouncer¶
SAP announcement for Qt applications.
#include "qt6/QtSapAnnouncer.h"
| Member | Description |
|---|---|
addSapAnnouncement(info) |
Add a stream to announce |
getSapAnnouncement(sessionName) |
Get the stored StreamInformation |
deleteSapAnnouncement(name, multicastAddress) / undeleteSapAnnouncement(name) |
Withdraw or restore one announcement |
deleteAllSapAnnouncements() |
Withdraw everything |
start() / stop() / restart() |
Control announcing |
setSourceInterface(index) / getInterfaces() |
Choose the network interface |
getActiveStreamCount() and activeStreamCountChanged(count) |
Number of active announcements |
mediax::qt6::QtSapAnnouncer announcer;
mediax::rtp::StreamInformation stream_info;
stream_info.session_name = "qt-announced";
stream_info.hostname = "239.192.1.1";
stream_info.port = 5004;
stream_info.width = 1920;
stream_info.height = 1080;
stream_info.framerate = 30;
stream_info.encoding = mediax::rtp::ColourspaceType::kColourspaceRgb24;
announcer.addSapAnnouncement(stream_info);
announcer.start();
// ... run application ...
announcer.stop();
announcer.deleteAllSapAnnouncements();
QtAndroidMulticastLock¶
Acquires the Android Wi-Fi multicast lock needed to receive RTP and SAP multicast, with acquire() and release().
See Android Support.
CMake Integration¶
find_package(Qt6 REQUIRED COMPONENTS Core Widgets)
find_package(MediaX REQUIRED)
target_link_libraries(your_app PRIVATE
Qt6::Core
Qt6::Widgets
MediaX::Qt6
)
QtRtspDepayloader¶
Receives video from an RTSP server. It is designed for the GUI thread: control is asynchronous, results arrive as signals and the event loop is never blocked. See the RTSP Receiver guide.
#include "qt6/QtRtspDepayloader.h"
using mediax::qt6::QtRtspDepayloader;
auto* rx = new QtRtspDepayloader(this);
rx->setUrl("rtsp://user:password@camera/stream");
rx->setTransport(QtRtspDepayloader::Transport::Tcp);
connect(rx, &QtRtspDepayloader::frameReady, this, [this](const QImage& image) { video->setImage(image); });
connect(rx, &QtRtspDepayloader::stateChanged, this, &Viewer::onState);
connect(rx, &QtRtspDepayloader::errorOccurred, this, [](QtRtspDepayloader::Error error, const QString& text) {
qWarning() << error << text;
});
rx->play(); // returns at once, state goes Connecting -> Playing
// ...
rx->stopPlayback(); // returns at once, state goes Stopping -> Stopped
Properties¶
| Property | Type | Notes |
|---|---|---|
url |
QString |
rtsp://[user[:password]@]host[:port]/path, applied by play() |
transport |
Transport |
Auto, Udp, Multicast, Tcp |
autoReconnect |
bool |
Reconnect when the connection or the media is lost, default true |
state (read only) |
State |
Stopped, Connecting, Playing, Reconnecting, Stopping, Failed |
active (read only) |
bool |
True while Connecting, Playing or Reconnecting |
lastError (read only) |
QString |
Empty if there was no error |
All properties have change signals, enums are registered with Q_ENUM, and the methods marked Q_INVOKABLE can be
called from QML.
Methods¶
| Method | Description |
|---|---|
play() |
Connect and start in the background. Ignored while active. Failure sets Failed and emits errorOccurred |
stopPlayback() |
Tear down in the background. A play() requested while stopping runs when the teardown finishes |
setCredentials(user, password) |
Alternative to credentials in the URL |
probe(url, level, timeoutMs) |
Check in the background whether a stream is live, result in probeFinished |
statistics() |
QVariantMap: packetsReceived, packetsLost, jitter, reconnects, framesDecoded |
isValidUrl(url) |
Static, check a URL before calling play() |
Signals¶
| Signal | Description |
|---|---|
frameReady(const QImage&) |
The decoded frame, preferred. QImage is implicitly shared, so this is cheap |
newFrame(Frame) |
Inherited from QtRtpDepayloader, tightly packed RGB24 |
stateChanged(State) |
The session state changed |
errorOccurred(Error, QString) |
InvalidUrl, ConnectFailed, Timeout, Network, Protocol, AuthRequired, AuthFailed, NotFound, Unsupported, Server |
probeFinished(url, live, detail) |
Result of probe(). The URL never contains credentials |
Frames are delivered latest wins: if the GUI is slower than the stream, older frames are dropped rather than
queued, so the event queue cannot grow without bound. Frames are only converted if frameReady or newFrame has a
receiver.
The blocking open(), start(), stop(), close() and receive() inherited from QtRtpDepayloader still work
for worker threads and console programs. In that polling style call receive() instead of connecting to the frame
signals.
// Is the camera up before offering it to the user?
connect(rx, &QtRtspDepayloader::probeFinished, this, [](const QString& url, bool live, const QString& detail) {
qInfo() << url << (live ? "live" : "dead") << detail;
});
rx->probe("rtsp://camera/stream"); // Media level by default, waits for a real RTP packet
QtSrtDepayloader¶
Receives video sent over SRT. Like QtRtspDepayloader it is signal driven and never blocks the event loop. See the
SRT guide.
#include "qt6/QtSrtDepayloader.h"
using mediax::qt6::QtSrtDepayloader;
auto* rx = new QtSrtDepayloader(this);
rx->setUrl("srt://:9000?mode=listener&latency=250&passphrase=correct-horse-battery");
connect(rx, &QtSrtDepayloader::frameReady, this, [this](const QImage& image) { video->setImage(image); });
connect(rx, &QtSrtDepayloader::stateChanged, this, &Viewer::onState);
connect(rx, &QtSrtDepayloader::errorOccurred, this, [](const QString& text) { qWarning() << text; });
rx->play(); // Returns at once, Connecting -> Connected
// ...
rx->stopPlayback();
| Member | Description |
|---|---|
url |
srt://host:port?mode=...&latency=..., applied by play() |
state |
Stopped, Connecting (waiting for the peer) or Connected |
lastError |
Description of the last error |
play(), stopPlayback() |
Start and stop in the background |
setAutoReconnect(bool) |
Reconnect when the link is lost (default on) |
setWaitForKeyFrameAfterLoss(bool) |
Hold the picture until the next key frame after a loss (default on) |
statistics() |
QVariantMap with rttMs, receiveRateBps, packetsLost, packetsRecovered, packetsDropped, framesDelivered, framesDiscarded, tsContinuityErrors, reconnects |
isValidUrl(url) |
Check an srt:// URL |
QtCastDiscovery and QtCastSender¶
Detect Chromecasts and cast H.264 video to them. Both are signal driven and never block the event loop, and the signals are emitted from the thread the object lives in. See the Chromecast guide.
Devices are QVariantMaps with the keys id, name, model, address, port and capabilities, usable from QML.
#include "qt6/QtCastDiscovery.h"
#include "qt6/QtCastSender.h"
using mediax::qt6::QtCastDiscovery;
using mediax::qt6::QtCastSender;
auto* discovery = new QtCastDiscovery(this);
connect(discovery, &QtCastDiscovery::deviceFound, this,
[this](const QVariantMap& device) { combo->addItem(device["name"].toString(), device); });
discovery->start();
auto* sender = new QtCastSender(this);
sender->setDevice(combo->currentData().toMap());
connect(sender, &QtCastSender::stateChanged, this, &Viewer::onCastState);
connect(sender, &QtCastSender::errorOccurred, this, [](const QString& text) { qWarning() << text; });
sender->start(); // Returns at once, connects in the background
sender->sendAccessUnit(annex_b_bytes, pts, is_idr); // From any thread
// ...
sender->stop();
QtCastDiscovery member |
Description |
|---|---|
devices |
The devices detected now, a list of device maps |
running |
True while discovery runs |
start(), stop(), refresh() |
Begin, end and repeat the search |
setInterfaceAddress(address) |
Search on one network interface only. Before start() |
findDevice(nameOrId) |
A device map by name (any case), id or address, empty if none |
deviceFound(map), deviceLost(map), devicesChanged() |
Signals |
errorOccurred(text) |
The network could not be searched |
QtCastSender member |
Description |
|---|---|
state |
Idle, Connecting, Launching, Loading, Streaming or Error |
lastError, playlistUrl, title |
Properties |
setDevice(map), setDeviceAddress(address, port, name) |
Choose the device. Before start() |
setAutoReconnect(bool), setSegmentDuration(ms) |
Reconnect when the device is lost (default on), segment length (default 2000) |
start(), stop() |
Begin and end casting. stop() also stops the application on the device |
sendAccessUnit(bytes, pts, keyFrame), sendAccessUnit(bytes) |
Give one Annex B access unit |
attachEncoder(RtpPayloader*), detachEncoder() |
Cast a MediaX H.264 encoder |
setKeyFrameRequestHandler(fn) |
Make the encoder produce a key frame, called from the thread giving the video |
statistics() |
QVariantMap with state, framesSent, segments, segmentBytes, httpRequests, httpBytes, reconnects |
stateChanged(State), streaming(), errorOccurred(text), keyFrameRequested() |
Signals |
QtRtpJpegPayloader and QtRtpJpegDepayloader¶
Qt6 wrappers of the RTP JPEG (RFC 2435) classes, built with BUILD_QT6=ON and BUILD_JPEG=ON. See
JPEG Video.
#include "qt6/QtRtpJpegDepayloader.h"
#include "qt6/QtRtpJpegPayloader.h"
| Method | Description |
|---|---|
QtRtpJpegDepayloader::newFrame(Frame) |
Signal with each decoded RGB24 frame, sized from the decoded image |
QtRtpJpegDepayloader::droppedFrames() |
Frames lost to missing packets |
QtRtpJpegPayloader::setQuality(int) |
JPEG quality 1 to 100 (default 85) |
QtRtpJpegPayloader::setSubsampling420(bool) |
4:2:0 instead of the default 4:2:2 |
QtRtpJpegPayloader::setMtu(uint32_t) |
Largest RTP packet, 256 to 65000 (default 1400) |
QtRtpJpegPayloader::transmit(Frame*) / sendFrame(Frame) |
Compress and send an RGB24 frame |
Both classes have the usual setStreamInfo(), open(), start(), stop() and close().
Thread Safety¶
- All Qt6 classes are designed for use from the main thread
- Video frames are processed in background threads
- Signal/slot connections handle cross-thread communication
- Use
Qt::QueuedConnectionfor thread-safe slot invocation
Support¶
- Website: https://astutesys.com/support
- Email: support@astutesys.com