Skip to content

HLS

media.ingest.hls

Description

Sapsan follows someone else's HLS playlist in client (pull) mode: it polls the playlist, fetches the segments and feeds frames into the pipeline just like RTSP, SRT or MPEG-TS. That is how almost every aggregator, every third-party CDN and every partner who is not allowed to open UDP or SRT delivers a stream.

Configuration

Configure the stream through the central API. Stream configuration fragment:

streams:
  - name: chan1
    inputs:
    - hls:
        url: https://cdn.example.com/live/index.m3u8

Parameters

Parameter Default Description
url — playlist address exactly as the operator wrote it
headers none headers added to every request to the source: playlist, segments, keys
variant_mode single single — one variant of the master, ladder — the whole ladder
variant_bandwidth none which bitrate to match the variant against (nearest below); without it the highest BANDWIDTH wins
skew_threshold_ms 500 the skew at which the ladder is declared out of sync
skew_policy report what to do on a skewed verdict: report — keep going and show it, fallback_to_single — fall back to a single variant
connect_timeout_ms 5000 connection timeout
read_timeout_ms 15000 body timeout: playlist, segment, key
max_body_bytes 64 MiB size limit of a single response
peer_timeout_ms global how long to wait for frames before the source is considered lost

Authentication

Two ways, and they combine:

  • headers — headers, e.g. Authorization: Bearer <token>; they go with the playlist, variants, init segments, segments and keys of the same origin, and they never follow a redirect to a foreign origin;
  • credentials in the URL itself — plain Basic authentication done by the HTTP client.

Header values never reach the log: only their names are printed. The input address is logged in full and returned as is by the management API — only the operator knows which part of that address is the secret, and guessing would either leave the token in the query or cut away the very part the input is recognized by in the log.

Transport options

HTTP or HTTPS; playlists/manifests and media segments use separate requests.

Supported codecs

Codec support depends on the segment container. MPEG-TS and fMP4 are containers; HLS retrieves playlists and segments.

MPEG-TS segments:

  • H.264
  • HEVC / H.265
  • AV1
  • JPEG 2000
  • MPEG-2 Video
  • AAC (ADTS)
  • AC-3
  • E-AC-3
  • MPEG Audio (Layer II / III)
  • SMPTE ST 302M

MPEG-TS is the container; SRT, RIST, UDP and HTTP are delivery transports. This list describes extracting frames from MPEG-TS, not decoding them or player support.

AV1 requires stream_type 0x06 and the AV01 registration descriptor in the PMT; one PES must contain a complete temporal unit. AV1 in MPEG-TS without this signaling is not supported. AAC parsing uses ADTS; recognizing stream_type 0x11 does not establish LATM support. Opus can be identified in the PMT, but the current PES decoder does not emit its frames.

fMP4 segments:

  • H.264
  • HEVC / H.265
  • AV1
  • MPEG-2 Video
  • JPEG
  • AAC
  • AC-3
  • E-AC-3
  • MPEG Audio (Layer II / III)
  • Opus
  • G.711 A-law / μ-law

These are codecs the input extracts from fMP4, not a decoder capability list. H.264 uses avc1/avc3, HEVC uses hvc1/hev1, and AV1 uses av01 with av1C. MPEG-2 Video requires mp4v with MPEG-2 configuration; this does not imply MPEG-4 Visual support. JPEG is an image track. MPEG Audio is identified through esds or an MP3 sample entry; mp4a alone does not mean AAC. Opus uses Opus/dOps, and G.711 uses alaw/ulaw. Container declarations must match the data; a codec declaration in an MPD does not replace a valid initialization segment.

Packed audio (standalone ADTS or ID3+AAC without MPEG-TS/fMP4) is not accepted by this input.

Error handling

Input state and failure cause are available in stream statistics. Connection loss or missing frames uses the shared retry and failover mechanisms.

Applying changes

Only a change of url, headers or the HTTP settings (connect_timeout_ms, read_timeout_ms, max_body_bytes) restarts the input: a new source has its own track numbering, its own init and its own position in the playlist. Everything else — variant mode, skew threshold and policy, peer_timeout_ms — applies in place, without interrupting the broadcast.

Counters

The tables give exact protocol statistics field names, including event counters and current-value gauges. Zero fields may be omitted. API and Prometheus expose different projections; the full list is not necessarily present in one Admin API response. Detailed statistics depend on the counter license.

Common input totals: bytes, frames, errors, warnings. They aggregate protocol data and must not be added to protocol counters again.

Hls

Field Type
segments counter
bytes counter
frames counter
playlist_reloads counter
discontinuities counter
segments_skipped counter
segments_gone counter
segments_cancelled counter
segments_gap counter
errors_playlist counter
errors_segment_network counter
errors_segment_status counter
errors_segment_decode counter
errors_decrypt counter
fragment_gaps counter
fragment_overlaps counter
fragment_seam_error_ms counter
edge_distance_ms counter
playlist_updated_at gauge
frames_emitted_at gauge
memory_bytes gauge
ad_marks counter
errors_ad_marks_dropped counter
warning_ad_mark_descriptors_dropped counter

Other details

Start rule

Whatever was already in the playlist at connect time is history. Capture starts from the first segment that appears after the connection, and it behaves the same way on a reconnect.

There is deliberately no start-depth setting: otherwise every dropped connection would make the stream flush the accumulated window into the pipeline in seconds instead of broadcasting.

Ladder and rendition skew

With variant_mode: ladder every variant of the master is captured. The highest BANDWIDTH variant becomes the reference, and the rest are compared against it segment by segment, by media sequence number. The verdict is exposed in the input statistics, field hls_ladder:

  • synced — the renditions run together, switching between them is safe;
  • skewed — the skew exceeded the threshold or the structure is broken: switching will jerk or desynchronize;
  • unmeasurable — nothing to compare, no segment pairs share a number.

Skew is measured two ways at once. Declared is the difference of EXT-X-PROGRAM-DATE-TIME in the markup, actual is the difference of the media time of the first frames. When the two disagree, it is the markup that is ill, not the stream, and it is the source owner who fixes it.

Note

Sapsan does not bring ladder variants onto a common timescale, and it does not repair bad content at all: a silent fix does not make a ladder switchable, it only hides the defect. So the skew is shown as a number and the operator decides.

The fallback_to_single policy drops the capture to a single variant on a skewed verdict — for some sources that is the only workable mode. The fallback lasts until the input is restarted.

Encryption

AES-128 (whole segment) and SAMPLE-AES (per frame, for H.264 and AAC) are supported. The key is fetched by the same client with the same headers as everything else and cached by address, so key rotation in the middle of a playlist works by itself — a new key has a new address.

A silent key server is an input error naming the key address and the response code; the segment body is not downloaded at all, since there would be nothing to decrypt it with.

CENC/DRM (Widevine, PlayReady, FairPlay) is not supported and is rejected by the KEYFORMAT name.

What is supported

Feature State
Media playlist: EXT-X-MEDIA-SEQUENCE, EXTINF, EXT-X-ENDLIST yes
Master playlist: variant selection, EXT-X-MEDIA renditions yes
fMP4 (EXT-X-MAP) and MPEG-TS segments yes
EXT-X-BYTERANGE yes
EXT-X-DISCONTINUITY, playlist recreation, falling behind the window yes
EXT-X-GAP yes, skipped without an error
EXT-X-PROGRAM-DATE-TIME — media time anchored to UTC yes
AES-128 and SAMPLE-AES (H.264, AAC) encryption yes
Ladder: capture of every variant, skew measurement yes
LL-HLS: EXT-X-PART, blocking reload no, parts are ignored
CENC/DRM no
Packed audio: bare ADTS or ID3+AAC instead of a container no, the format is named in the error
TTML subtitles and WebVTT segments no, the track is recognized and skipped
MPEG-DASH ingest no

Verification

Open http://server/streaming/v/chan1/index.m3u8 in a player or request a screenshot at http://server/streaming/live-preview-jpeg/chan1.

Look beyond "frames are flowing" at three things:

  • how far the output lags behind the playlist edge — without it a "the stream is behind" complaint is indistinguishable from "the source is behind", and the two are fixed in different places;
  • skipped segments and their breakdown: washed out of the window, cancelled in flight, declared with EXT-X-GAP. The last one is not a source error but its honest statement;
  • the seam between neighbouring fragments — a silent defect: every segment was downloaded, no parse errors, yet the media inside them does not join up, and the archive keeps the hole.

Next steps