HLS Receiver¶
MediaX can play an HTTP Live Streaming (HLS, RFC 8216) stream. mediax::hls::HlsDepayloader downloads the playlist and
the MPEG-2 transport stream segments, demultiplexes the video, wraps each access unit in RTP (RFC 6184) and hands it to
the H.264 decoder. It is a drop-in mediax::rtp::RtpDepayloader, so frames are received exactly as for the
RTSP and SRT receivers.
Scope
This is a receiver (client) only. Audio is delivered to your application as data and is never played by
MediaX, see Audio. AES-128 encrypted segments (EXT-X-KEY) are decrypted when MediaX is built with
OpenSSL. SAMPLE-AES and DRM key formats, fragmented MP4 segments (EXT-X-MAP) and separate
audio renditions (EXT-X-MEDIA) are not supported. The decoded video codec is H.264.
Requirements¶
BUILD_HLS=ON(the default). Not available on Windows.- libcurl (
libcurl4-openssl-dev), see Installation. - OpenSSL (
libssl-dev) to play AES-128 encrypted streams, such as the ABC TV feed. - An H.264 decoder backend. The OpenH264 software decoder (
BUILD_OPENH264=ON) is used by default. - Optional, to receive audio as PCM:
BUILD_HLS_AUDIO_DECODE=ONand FFmpeglibavcodec-dev libavutil-dev.
Features¶
| Feature | Behaviour |
|---|---|
| Playlists | Master playlists (a variant is chosen) and media playlists |
| Variant choice | preferred_height selects the closest height, max_bandwidth caps the bitrate, 0 selects the highest bandwidth |
| Live streams | The playlist is refreshed, playback starts live_start_segments segments before the end (RFC 8216 6.3.3) |
| Finished streams | Played to the end of the playlist (EXT-X-ENDLIST), then HasEnded() is true |
| Pacing | Played out at the stream rate (realtime_pacing), or as fast as downloaded when false |
| Buffering | At most max_buffer_ms of video is held between download and playout |
| Errors | Redirects followed (max_redirects), the stream is abandoned after max_consecutive_errors failed requests |
| Transport | http:// and https:// playlists and segments |
| Encryption | AES-128 (EXT-X-KEY): the key is fetched once per URL, the IV is the IV attribute or the media sequence number |
Usage¶
#include <iostream>
#include "hls/hls_depayloader.h"
int main() {
mediax::hls::HlsClientConfig config;
config.preferred_height = 576; // Closest variant, 0 selects the highest bandwidth
mediax::hls::HlsDepayloader rx;
rx.SetClientConfig(config);
rx.SetUrl("https://example.com/live/stream.m3u8");
if (!rx.Open()) {
std::cerr << rx.GetLastError() << "\n";
return 1;
}
rx.Start();
mediax::rtp::RtpFrameData frame;
while (rx.Receive(&frame, 5000)) {
std::cout << frame.resolution.width << "x" << frame.resolution.height << "\n";
}
rx.Close();
return 0;
}
Register frame and error callbacks before calling Open(). Errors may be reported from a worker thread.
Audio¶
Audio muxed into the transport stream segments is passed to a callback. MediaX does not play it: the application owns the speaker output and sends the data to its audio device (ALSA, PulseAudio, SDL, Qt Multimedia, ...).
rx.RegisterAudioCallback([](const mediax::hls::HlsAudioFrame& audio) {
if (audio.format == mediax::hls::HlsAudioFormat::kPcmS16) {
// audio.pcm: interleaved 16 bit samples, audio.channels per sample time, at audio.sample_rate Hz
PlayPcm(audio.pcm.data(), audio.SamplesPerChannel(), audio.channels, audio.sample_rate);
} else {
// audio.encoded: AAC (ADTS or LATM), MPEG audio, AC-3 or E-AC-3 exactly as in the stream
DecodeAndPlay(audio.format, audio.encoded);
}
});
rx.Open(); // Register the callback first
| Behaviour | Detail |
|---|---|
| Sources | The first audio stream muxed in the segments: AAC (ADTS 0x0F, LATM 0x11), MPEG audio (0x03, 0x04), AC-3 (0x81), E-AC-3 (0x87) |
| Without a callback | Audio is ignored and costs nothing |
| PCM | Delivered when a decoder is available and decode_audio is true. Otherwise the encoded bytes are delivered |
| Decoder | Built in with BUILD_HLS_AUDIO_DECODE=ON (libavcodec, LGPL), or supply your own with SetAudioDecoderFactory() |
| Timing | pts is the 90 kHz stream timestamp. Blocks are delivered on the playout thread in step with the video |
| Threading | The callback runs on the playout thread. Keep it short and hand the data to the audio device or another thread |
Check HasBuiltInAudioDecoder() to see whether the library has the libavcodec decoder. A custom decoder derives from
mediax::hls::HlsAudioDecoder:
rx.SetAudioDecoderFactory([](mediax::hls::HlsAudioFormat format) -> std::unique_ptr<mediax::hls::HlsAudioDecoder> {
if (format != mediax::hls::HlsAudioFormat::kAacAdts) return nullptr; // nullptr delivers this audio encoded
return std::make_unique<MyAacDecoder>();
});
The factory is called on the download thread when the first audio of a stream arrives.
Configuration¶
mediax::hls::HlsClientConfig:
| Field | Default | Description |
|---|---|---|
connect_timeout_ms |
5000 | TCP connect timeout |
request_timeout_ms |
15000 | Total time allowed for one HTTP request |
max_redirects |
5 | HTTP redirects to follow |
preferred_height |
0 | Preferred variant height in pixels, 0 selects the highest bandwidth |
max_bandwidth |
0 | Ignore variants above this bits per second, 0 for no limit |
live_start_segments |
3 | Segments before the end of a live playlist to start from |
max_consecutive_errors |
5 | Failed requests before the stream is abandoned |
max_buffer_ms |
12000 | Maximum video held between download and playout |
realtime_pacing |
true | Play out at the stream rate |
decode_audio |
true | Deliver audio as PCM when a decoder is available, otherwise encoded |
user_agent |
MediaX HLS Client |
User-Agent request header |
Status and Statistics¶
GetLastStatus() returns an HlsStatus: kOk, kInvalidArgument, kInvalidState, kNetworkError, kHttpError,
kTimeout, kParseError, kUnsupported or kCancelled. Use HlsStatusToString() for text and GetLastError() for
the detail.
GetStatistics() returns playlist requests, segments and bytes downloaded, frames delivered, RTP packets, audio blocks
delivered, errors and the
next segment sequence number. GetVariant() returns the playing variant (URI, bandwidth, size, codecs, frame rate).
Console Example¶
hls-receive --url=https://example.com/live/stream.m3u8 --height=576 --record=out.mkv
hls-receive --url=https://example.com/live/stream.m3u8 --audio_dump=audio.raw # Receive the audio too
hls-player # SDL2 player with sound, plays ABC TV
The Qt6 player examples can also show HLS streams, and check a playlist is live, see RTSP Receiver and Examples.
Related¶
- C++ API: HLS classes
- The transport stream layer is shared with SRT, see C++ API: MPEG-TS classes