HLS Server - Monibuca Large-Scale Distribution
HLS (HTTP Live Streaming) is an HTTP-based streaming protocol developed by Apple. By segmenting live streams into TS segments and generating M3U8 playlists, HLS offers excellent CDN compatibility and device coverage, making it the preferred protocol for large-scale distribution.
Basic Information
Section titled “Basic Information”| Property | Value |
|---|---|
| Transport Layer | HTTP (shares the engine HTTP port) |
| Publish | ❌ Not supported |
| Subscribe | ✅ Supported |
| Latency | 5-30 seconds (depends on segment duration) |
| Config section | hls |
Configuration
Section titled “Configuration”Enable plugin
Section titled “Enable plugin”The plugin is included in official binaries; configure it in config.yaml:
Configuration File
Section titled “Configuration File”hls: enable: true segment_duration: 6 max_segments: 5 output_dir: "./hls" write_to_disk: true| Option | Type | Default | Description |
|---|---|---|---|
enable | bool | true | Whether to enable the HLS plugin |
segment_duration | u64 | 6 | TS segment duration (seconds) |
max_segments | usize | 5 | Maximum number of segments retained in the playlist |
output_dir | string | "./hls" | Segment file output directory |
write_to_disk | bool | true | Whether to write segments to disk |
dvr_window | u32 | 0 | Duration-based DVR/rewind retention in seconds; 0 = off. Independent of max_segments (live tail) |
DVR / live rewind (opt-in)
Section titled “DVR / live rewind (opt-in)”With the default dvr_window: 0, behavior is unchanged: the live playlist keeps only max_segments segments.
When dvr_window (seconds) is set, completed segments are retained by accumulated duration on this node, without changing the normal live playlist. Clients select the rewind view via query string:
| Query | Behavior |
|---|---|
(absent) or _HLS_rewind=NO | Current live tail (byte-identical to DVR-off when rewind is not requested) |
_HLS_rewind=YES | EXT-X-PLAYLIST-TYPE:EVENT over retained completed segments (correct MEDIA-SEQUENCE / discontinuities; LL-HLS completed PART lines when enabled) |
hls: enable: true write_to_disk: true # required for DVR; otherwise a warning is logged and DVR is treated as off max_segments: 5 # live tail (unchanged) dvr_window: 120 # retain ~2 minutes beyond the live tail# LiveGET /hls/live/show/index.m3u8
# Rewind (EVENT)GET /hls/live/show/index.m3u8?_HLS_rewind=YESABR: _HLS_rewind=YES on the master propagates to each rendition media URI; each rendition remuxer retains independently.
Exporting a DVR Interval as VoD
Section titled “Exporting a DVR Interval as VoD”Retained DVR segments can be atomically exported into a stable HLS VoD asset:
curl -X POST "http://localhost:8180/hls/api/dvr/export" \ -H "Content-Type: application/json" \ -d '{ "stream_path": "live/show", "start": 120, "end": 135, "name": "show-highlight" }'Request fields:
| Field | Description |
|---|---|
stream_path | Source live stream path |
start / end | Inclusive HLS EXT-X-MEDIA-SEQUENCE range; both endpoints must still be retained in this node’s dvr_window |
name | Optional asset name; omitted names are generated automatically |
The response includes playlist_url, for example:
{ "status": "ok", "playlist_url": "/hls/vod/show-highlight/index.m3u8", "segment_count": 16, "duration": 48.0}The exporter hard-links selected .ts segments into the recordings directory first, falling back to copy across filesystems. It writes index.m3u8.tmp and atomically renames it to index.m3u8; once export succeeds, live DVR eviction can no longer break the VoD asset. Playback still goes through HLS auth:
ffplay http://localhost:8180/hls/vod/show-highlight/index.m3u8ABR multi-rendition (opt-in)
Section titled “ABR multi-rendition (opt-in)”With the default empty abr: [] (or omitting abr), behavior stays single-rendition: one media playlist per stream path. When you configure hls.abr, Monibuca serves a multivariant master playlist for a logical master path, pointing at each rung’s media index.m3u8.
The HLS plugin only builds the master. Encode/publish each rendition as a separate child stream via the transcode plugin onpub outputs (or another publisher), then let HLS remux those paths.
Config shape
Section titled “Config shape”hls: enable: true abr: - master: live/show renditions: - path: live/show_720p bandwidth: 2500000 resolution: "1280x720" codecs: "avc1.64001f,mp4a.40.2" # optional - path: live/show_480p bandwidth: 1200000 resolution: "854x480"| Field | Description |
|---|---|
master | Logical master path used in the master URL |
renditions | Ordered ladder (highest bitrate first recommended) |
path | Stream path for that rung’s media playlist |
bandwidth | #EXT-X-STREAM-INF:BANDWIDTH (bps, required, > 0) |
resolution | Optional, e.g. 1280x720 |
codecs | Optional RFC 6381 string |
Master URL
Section titled “Master URL”Canonical:
GET /hls/<master>/master.m3u8Example: http://localhost:8180/hls/live/show/master.m3u8
When ABR is configured for that master, /hls/<master>/index.m3u8 and /hls/<master>.m3u8 also return the same multivariant playlist (compatibility shorthand). Prefer master.m3u8. Each rendition media playlist remains /hls/<rendition>/index.m3u8.
End-to-end example (RTMP → transcode → ABR)
Section titled “End-to-end example (RTMP → transcode → ABR)”- Publish:
ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/show - Transcode
onpubproduceslive/show_720p/live/show_480p(see Transcode) - Configure
hls.abras above - Open the master in a player:
ffplay http://localhost:8180/hls/live/show/master.m3u8Full YAML snippet:
transcode: enable: true onpub: "^live/show$": outputs: - target: "rtmp://127.0.0.1/live/show_720p" options: video_codec: "libx264" resolution: "1280x720" video_bitrate: 2500 audio_codec: "aac" audio_bitrate: 128 - target: "rtmp://127.0.0.1/live/show_480p" options: video_codec: "libx264" resolution: "854x480" video_bitrate: 1200 audio_codec: "aac" audio_bitrate: 96
hls: enable: true abr: - master: live/show renditions: - path: live/show_720p bandwidth: 2500000 resolution: "1280x720" codecs: "avc1.64001f,mp4a.40.2" - path: live/show_480p bandwidth: 1200000 resolution: "854x480"URL Format
Section titled “URL Format”M3U8 Playlist
Section titled “M3U8 Playlist”http://host:port/hls/{streamPath}/index.m3u8ABR master (when configured):
http://host:port/hls/{masterPath}/master.m3u8TS Segments
Section titled “TS Segments”http://host:port/hls/{streamPath}/{sequence}.tsExamples:
http://localhost:8180/hls/live/test/index.m3u8http://localhost:8180/hls/live/test/0.tsPlayback
Section titled “Playback”Using FFplay
Section titled “Using FFplay”ffplay http://localhost:8180/hls/live/test/index.m3u8Using VLC
Section titled “Using VLC”- Open VLC, select Media → Open Network Stream
- Enter URL:
http://localhost:8180/hls/live/test/index.m3u8 - Click Play
Browser Playback
Section titled “Browser Playback”Use hls.js for browser playback:
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script><video id="player" controls></video><script> const video = document.getElementById('player'); if (Hls.isSupported()) { const hls = new Hls(); hls.loadSource('http://localhost:8180/hls/live/test/index.m3u8'); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, () => video.play()); } else if (video.canPlayType('application/vnd.apple.mpegurl')) { // Safari native support video.src = 'http://localhost:8180/hls/live/test/index.m3u8'; video.play(); }</script>HLS Recording
Section titled “HLS Recording”The HLS plugin provides a recording API to record streams in HLS format (M3U8 + TS files):
The recording playlist stays open while capture is active and receives EXT-X-ENDLIST only on stop. Completed recording segments are retained independently of the live max_segments window; plan and monitor disk capacity for long recordings.
# Start recordingcurl -X POST http://localhost:8180/hls/record/start/live/test
# Stop recordingcurl -X POST http://localhost:8180/hls/record/stop/live/test
# List recordingscurl http://localhost:8180/hls/record/list
# Check recording statuscurl http://localhost:8180/hls/record/status/live/test
# Query historical recordingscurl http://localhost:8180/hls/record/recordsHow It Works
Section titled “How It Works”- Stream subscription: When an HLS playlist is first requested, the plugin automatically subscribes to the corresponding stream
- Segment generation: Continuously reads frame data from the stream and splits it into TS segments based on
segment_duration - Playlist update: Automatically updates the M3U8 playlist each time a new segment is generated
- Sliding window: Retains the most recent
max_segmentssegments; older segments are automatically cleaned up - Storage strategy: Segments are stored in both memory and disk (depending on
write_to_diskconfiguration)
Latency Optimization
Section titled “Latency Optimization”HLS latency is primarily determined by the following factors:
Total latency ≈ segment_duration × (max_segments - 1) + player bufferOptimization recommendations:
# Low-latency configurationhls: segment_duration: 2 max_segments: 3With this configuration, the theoretical minimum latency is approximately 4-6 seconds.
Typical Workflow
Section titled “Typical Workflow”# 1. Publish via RTMPffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost:1935/live/test
# 2. Subscribe via HLSffplay http://localhost:8180/hls/live/test/index.m3u8
# 3. You can also subscribe via other protocols simultaneouslyffplay http://localhost:8180/flv/live/test.flv