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):

  • QtRtpPayloader and QtRtpDepayloader - abstract base classes for every codec wrapper (see the table below)
  • QtSapListener, QtSapAnnouncer, QtSapSessionManager - SAP discovery and announcement with Qt signals
  • QtRtspDepayloader, QtSrtDepayloader - signal driven network receivers
  • QtCastDiscovery, QtCastSender - detect Chromecasts and cast video to them
  • QtAndroidMulticastLock - 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::QueuedConnection for thread-safe slot invocation

Support