streamtop
streamtop is a Rust CLI and terminal UI for monitoring live video streams. Point it at an HLS playlist (.m3u8), an MPEG-DASH manifest (.mpd), an IPTV channel list (.m3u, .json, .yaml), or a WHEP HTTP endpoint. It shows segment timing, codec data read from the wire, ad markers, and health scores in the terminal, without a browser or GUI player.
Typical uses:
- Debug CDN and origin issues on a live channel (TTFB, HTTP status, cache HIT/MISS, stalls).
- Check encoder output against the manifest (resolution, FPS, GOP, audio).
- See SCTE-35 ad markers in HLS tags and DASH
emsgboxes. - Check which channels in an IPTV playlist are working.
- Gate CI on a stream with PASS/FAIL JSON, SARIF, or budget thresholds.
- Scrape Prometheus metrics or send OTLP traces from a live probe.
cargo install streamtop
streamtop "https://example.com/master.m3u8"
Source code, issues, and releases: github.com/Jorji49/streamtop. License: MIT.
Install
Prebuilt binaries for Linux (x86_64 and arm64, glibc and musl), macOS (Apple Silicon and Intel), and Windows x86_64 are on GitHub Releases. Each release includes SHA256SUMS.
# Linux x86_64 (static musl build); use the -gnu archive for glibc
curl -LO https://github.com/Jorji49/streamtop/releases/latest/download/streamtop-x86_64-unknown-linux-musl.tar.gz
curl -LO https://github.com/Jorji49/streamtop/releases/latest/download/SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS
tar xzf streamtop-x86_64-unknown-linux-musl.tar.gz
cargo
cargo install streamtop
# or, to download a prebuilt binary:
cargo install cargo-binstall && cargo binstall streamtop
The minimum supported Rust version is listed in Cargo.toml (rust-version).
Homebrew (macOS and Linux)
brew tap Jorji49/tap
brew install streamtop
Recent Homebrew versions may ask you to trust third-party taps first: brew trust jorji49/tap.
Scoop (Windows)
scoop bucket add streamtop https://github.com/Jorji49/streamtop
scoop install streamtop
winget (Windows)
Manifests are in dist/winget/ in the repository. The package is not in the winget community index yet, so winget install does not work yet.
Arch Linux
streamtop-bin is not on the AUR yet. dist/aur/PKGBUILD builds the same package locally from the Linux release tarball:
git clone https://github.com/Jorji49/streamtop.git
cd streamtop/dist/aur
makepkg -si
Docker
Images for linux/amd64 and linux/arm64 are on GitHub Container Registry:
docker run -it --rm ghcr.io/jorji49/streamtop:latest <URL>
Release tags are also published, for example ghcr.io/jorji49/streamtop:v1.7.1.
Prometheus metrics on a non-loopback bind require a token:
docker run --rm -p 9184:9184 \
-e STREAMTOP_METRICS_TOKEN=change-me \
ghcr.io/jorji49/streamtop:latest \
<URL> --prometheus --metrics-bind 0.0.0.0 \
--metrics-token "$STREAMTOP_METRICS_TOKEN"
Quick Play (p) is not available in the container because there is no mpv or ffplay inside it.
From source
git clone https://github.com/Jorji49/streamtop.git
cd streamtop
cargo install --path .
Shell completions and man page
streamtop completions <SHELL> prints a completion script for bash, zsh, fish, elvish, or powershell. It covers the main flags and the check, scte35, completions, and man subcommands.
# bash
streamtop completions bash > ~/.local/share/bash-completion/completions/streamtop
# zsh (a directory in your fpath)
streamtop completions zsh > ~/.zfunc/_streamtop
# fish
streamtop completions fish > ~/.config/fish/completions/streamtop.fish
# PowerShell
streamtop completions powershell >> $PROFILE
streamtop man prints the streamtop(1) man page as roff. streamtop man check prints the page for one subcommand.
mkdir -p ~/.local/share/man/man1
streamtop man > ~/.local/share/man/man1/streamtop.1
streamtop man check > ~/.local/share/man/man1/streamtop-check.1
man streamtop
Quick start
# HLS live stream
streamtop "https://example.com/master.m3u8"
# MPEG-DASH
streamtop "https://example.com/manifest.mpd"
# IPTV channel list: opens a channel picker
streamtop ./channels.m3u
# MPEG-TS TR 101 290 checks and SEI metadata
streamtop "https://example.com/live.m3u8" --tr101290 --probe-sei
# Headless PASS/FAIL for CI
streamtop "https://example.com/master.m3u8" --summary --summary-format json --timeout 10
Segment fetches are range probes by default: streamtop requests only the first bytes of each segment, which is enough for header, container, and timing checks. Pass --full-segment to download whole segments (up to 32 MB) instead.
Common options
| Option | Meaning |
|---|---|
-H "Key: Value" | Extra HTTP header, repeatable |
-A <UA> | User-Agent |
-i <MS> | Manifest poll interval in milliseconds |
--profile <NAME> | Load a named profile from ~/.config/streamtop/config.toml (see config.example.toml) |
--full-segment | Download full segments instead of range probes |
--tr101290 | ETSI TR 101 290 P1/P2 checks on the MPEG-TS probe window |
--probe-sei | H.264/H.265 SEI: captions (CEA-608/708) and HDR metadata |
--probe-drm | License server / EXT-X-KEY / DASH LA_URL TTFB |
--clearkey KID:KEY | Staging ClearKey for encrypted probe checks |
--doh-provider cloudflare|google|<URL> | DNS-over-HTTPS timing |
Run streamtop --help for the full list.
Dashboard and keys
Layout
| Area | Contents |
|---|---|
| Status | URL, LIVE / ESTIMATED, linter score, FPS, GOP and audio badges, latency, CDN, buffer, G2G, LL-HLS |
| Last segment | Sequence, sizes, DNS / TCP / TLS / DoH / TTFB, container, GOP interval, audio |
| ABR ladder | Bitrate, resolution, FPS, codecs. [wire] values come from the bitstream; red means manifest and wire disagree |
| Charts | Latency or TTFB; download rate or transfer time |
| Log | Warnings, SCTE-35 ad markers, stalls, HTTP errors |
FPS comes from the playlist FRAME-RATE or @frameRate when present, otherwise from the bitstream. GOP interval comes from keyframe PTS across segments (fixed or variable). Audio codec, rate, and channels come from ADTS, fMP4, or the MPEG-TS PMT in the probe window.
What is probed
- HLS: live and VOD media playlists, LL-HLS
#EXT-X-PARTandPRELOAD-HINTwith per-part TTFB and download-to-duration ratio,#EXT-X-PROGRAM-DATE-TIME. - MPEG-DASH: live and VOD, ServiceDescription latency, UTCTiming, ContentProtection and PSSH.
- Containers: fMP4, MPEG-TS, ADTS, and H.264/H.265 elementary streams, read from the probe window without a decoder.
- AES-128:
#EXT-X-KEYfetch and in-memory decrypt so encrypted TS/fMP4 can be inspected. - SCTE-35: HLS tags (
EXT-X-DATERANGE,EXT-X-CUE-OUT,EXT-OATCLS-SCTE35,EXT-X-SCTE35), DASH inbandemsg, and mismatches between the two. - CDN edge: HIT/MISS from edge headers for Cloudflare, CloudFront, Akamai, Fastly, BunnyCDN, Azure CDN, Google Cloud CDN, JOCDN, Medianova, Edgio, Lumen, and Gcore.
- Glass-to-glass estimate: from PRFT, HLS PDT, or the DASH segment availability time (MPD publish time as a fallback). This is an estimate, not player end-to-end latency.
- Buffer model: rebuffer probability from observed download-to-duration ratios.
Keys
| Key | Action |
|---|---|
q / Esc / Ctrl+C | Quit (Esc leaves the channel list when it is open) |
Space | Write diagnostics/<channel>_<time>.json (URLs and secrets redacted) |
c | Copy a curl command for the last segment (redacted) |
p | Play with mpv or ffplay using the active headers |
r | Reset metrics |
Tab | Channel overlay |
? | Help |
/ | Regex log filter (Enter to lock, Esc to clear) |
f / F | Cycle preset log filter / clear it |
t | TR 101 290 overlay |
s | SEI / HDR / caption overlay |
j / k | Scroll the log or channel list |
Compare mode: Space pause/resume, d detail, l log focus, c curl, h or e HAR, Tab switch pane.
IPTV playlist checking
streamtop reads IPTV channel lists in M3U (#EXTINF with tvg-name, tvg-id, tvg-logo, group-title), JSON, and YAML. A list can be a local file or a URL.
Browse channels
streamtop ./channels.m3u
streamtop "https://example.com/playlist.m3u"
This opens a channel picker with search. Selecting a channel opens the normal dashboard for it.
Check every channel
streamtop ./channels.m3u --audit
--audit probes every channel concurrently (25 workers) and prints a table:
# Channel Group HTTP PDT TTFB CDN Verdict
1 News HD News 200 yes 182ms Cloudflare HIT LIVE
2 Sports 2 Sports 404 no - - ERROR
404 Not Found
For each channel it fetches the playlist (following a master playlist to its highest-bandwidth variant), then range-requests the last segment. For DASH it probes a segment URL taken from the MPD.
Verdicts:
| Verdict | Meaning |
|---|---|
LIVE | Playlist and segment returned 2xx/3xx and the segment TTFB was under 2500 ms |
VOD | Same as LIVE, but the playlist is on-demand (HLS #EXT-X-ENDLIST or a static MPD). Counted as working |
STALL | Segment TTFB was 2500 ms or more, or the media playlist had no segments |
ERROR | HTTP 401, 403, 404, 5xx, a network error, a timeout, or a playlist that could not be parsed |
Each request has a 3 second connect timeout and a 5 second total timeout. Results are also written to audit_report.json and audit_report.csv in the current directory, with URLs and tokens redacted. The exit code is non-zero when any channel is ERROR or STALL.
Headers and User-Agent apply to every channel:
streamtop ./channels.m3u --audit -H "Referer: https://example.com" -A "Mozilla/5.0"
streamtop check
streamtop check is the scriptable version of --audit. It takes a playlist file or URL (M3U, JSON, YAML, or a single HLS/DASH URL), probes every entry concurrently with a per-entry time limit, and prints a table, JSON, or CSV. It writes no files unless you ask for them.
streamtop check ./channels.m3u
streamtop check "https://example.com/playlist.m3u" --timeout 5 --concurrency 50
streamtop check ./channels.m3u --format json > report.json
streamtop check ./channels.m3u --format csv --output report.csv
streamtop check ./channels.m3u --alive-out working.m3u
streamtop check ./channels.m3u --fail-on-dead # exit 1 if any entry is dead
| Option | Default | Meaning |
|---|---|---|
-t, --timeout SECS | 10 | Time limit for one entry (playlist, variant, and segment probe together). An entry that runs over is ERROR with timeout after Ns |
-j, --concurrency N | 25 | Entries probed at the same time |
-f, --format | table | table, json, or csv |
-o, --output FILE | stdout | Write the report to a file. With table, writes JSON |
--alive-out FILE | Write an M3U with the entries that are not dead (LIVE, VOD, and STALL unless --strict), keeping tvg-id, tvg-logo, and group-title | |
--fail-on-dead | off | Exit 1 when any entry is ERROR |
--strict | off | Treat STALL as dead for --fail-on-dead and --alive-out |
-H, --header | Extra HTTP header, repeatable | |
-A, --user-agent | User-Agent override |
JSON and CSV reports redact URLs and tokens, like the --audit files. The --alive-out playlist keeps the original URLs, because it is meant to be played.
Without --fail-on-dead, check exits 0 even when entries are dead, so it can be used for reporting. --audit always exits 1 on any ERROR or STALL.
Notes
- A
LIVEverdict means the playlist and one segment were reachable. It does not decode video, so a channel that serves a black frame still counts as live. - Some IPTV servers block unknown User-Agents or require a Referer. Pass them with
-Aand-H. --auditalways uses 25 workers and a 5 second limit per HTTP request, so on large lists with many unreachable hosts the run time is set mostly by those timeouts.checklets you set the worker count with-jand a limit per entry with--timeout.
SCTE-35 decoding
While monitoring, streamtop decodes SCTE-35 cues from HLS tags (#EXT-OATCLS-SCTE35, #EXT-X-SCTE35, #EXT-X-DATERANGE with SCTE35-OUT, SCTE35-IN, SCTE35-CMD, and #EXT-X-CUE-OUT / CUE-IN) and from DASH emsg boxes. They appear in the event log and in the summary JSON.
streamtop scte35
To decode a single cue without a stream, pass it to streamtop scte35:
streamtop scte35 "/DAvAAAAAAAA///wFAVIAACPf+/+c2nALv4AUsz1AAAAAAAKAAhDVUVJAAABNWLbowo="
table_id 0xfc
protocol_version 0
splice_command Splice Insert (0x05)
splice_event_id 1207959695 (0x4800008f)
out_of_network yes
pts_time 1936310318 (21514.559089s)
break_duration 60.293567s
break_auto_return yes
Accepted input:
- Base64 (standard or URL-safe alphabet)
- Hex, with or without
0x. A string made only of hex digits is always read as hex - An HLS tag line:
#EXT-OATCLS-SCTE35:...,#EXT-X-SCTE35:CUE="...", or#EXT-X-DATERANGEwithSCTE35-OUT,SCTE35-IN, orSCTE35-CMD -to read the payload from stdin
streamtop scte35 0xFC302F000000000000FFFFF014054800008F7FEFFE7369C02EFE0052CCF500000000000A0008435545490000013562DBA30A
grep -m1 OATCLS playlist.m3u8 | streamtop scte35 -
streamtop scte35 --json "/DA0AAAAAAAA///wBQb+cr0AUAAeAhxDVUVJSAAAjn/PAAGlmbAICAAAAAAsoKGKNAIAmsnRfg=="
The text output covers splice_insert, time_signal, splice_schedule, splice_null, and bandwidth_reservation, and each segmentation descriptor (event id, type, duration, UPID, segment numbers, delivery flags). --json prints the same fields as the summary JSON. The command exits 1 when the bytes are not a valid splice_info_section.
It does not verify the CRC, decrypt encrypted sections, or encode new cues. For encoding and injection, see threefive or TSDuck.
Headless and CI
PASS/FAIL summary
streamtop <URL> --summary --summary-format json --timeout 10
--summary listens for --timeout seconds (default 8) and prints a verdict. It returns PASS only when:
- the status is LIVE, or VOD for a playlist with
#EXT-X-ENDLIST, - the linter score is at least 85,
- no critical RFC errors or origin stalls were seen,
- the last HTTP status was 200 or 206,
- at least one segment was fetched.
Any failed condition returns FAIL and a non-zero exit code. On FAIL the text output adds a last_error: line and the JSON adds last_error when a fetch or parse failed. If no segment was fetched, the score is 0 with the label No data.
The JSON contract is streamtop.summary.v1; the schema is schemas/summary.v1.json and schema_version is currently 7. Version 7 added the VOD status and the last_error field.
Colors are used only when stdout is a terminal and NO_COLOR is not set.
Formats: text (default), json, sarif.
SARIF for GitHub Code Scanning
streamtop <URL> --summary --summary-format sarif --timeout 10 > streamtop.sarif
# or
streamtop <URL> --export sarif:streamtop.sarif --timeout 10
GitHub Actions step summary
streamtop <URL> --summary --github-step-summary "$GITHUB_STEP_SUMMARY" --timeout 10
When GITHUB_STEP_SUMMARY is set, --summary and budget mode write it automatically. The summary includes the linter score, download-to-duration ratio, TR 101 290 counts, the ABR ladder, and the budget table.
Stream budgets
Budgets are threshold assertions. streamtop prints a JSON verdict and exits non-zero on a breach.
streamtop "$STREAM_URL" \
--budget-max-rtf 1.0 \
--budget-max-ttfb 500ms \
--budget-max-cc-errors 0 \
--budget-max-drift 2000ms \
--budget-duration 30
| Flag | Fails when |
|---|---|
--budget-max-rtf | download time divided by segment duration exceeds the ratio |
--budget-max-ttfb | segment TTFB exceeds the value (250ms, 2s) |
--budget-max-cc-errors | TR 101 290 continuity counter errors exceed N |
--budget-max-drift | A/V or subtitle drift exceeds the value |
--budget-duration | probe window in seconds (default 30) |
VOD crawl
streamtop --vod <URL> --summary
Crawls the playlist or MPD tree once without live polling.
WHEP smoke test
streamtop "https://webrtc.example/live/whep" --timeout 5
Sends an SDP offer and parses the answer (TTFB, codecs, ICE candidates). Signaling only; no media path.
Example workflow step
- name: Stream check
run: |
cargo install streamtop
streamtop "$STREAM_URL" --summary --summary-format json --timeout 15
Hermetic end-to-end tests for streamtop itself are in tests/e2e_verify.sh and tests/e2e_verify.ps1.
Exports
--export FORMAT[:FILE] is repeatable.
| Format | Output |
|---|---|
report-html[:PATH] | Compliance report as HTML (default report.html) |
report-json[:PATH] | Compliance report as JSON (default report.json) |
curl | curl command for the last segment, printed to stdout |
har[:PATH] | HAR file (default incident.har) |
incident[:PATH] | Opens the dashboard. Press e to write a redacted bundle (curl, HAR, timeline, findings) to PATH. Needs a terminal. |
sarif[:PATH] | SARIF 2.1.0 findings (default streamtop.sarif) |
grafana | Grafana dashboard JSON for the Prometheus metrics, written to streamtop-grafana.json |
streamtop <URL> --export report-html:report.html --timeout 10
streamtop <URL> --export curl --timeout 10
streamtop <URL> --export har:incident.har --export sarif --timeout 10
streamtop --export grafana
All formats except incident run headless and work in CI. In the dashboard, Space writes diagnostics/<channel>_<time>.json and c copies a curl command. URLs, tokens, and secrets are redacted in all exports.
Metrics, agent, and alerts
Prometheus
streamtop <URL> --prometheus # 127.0.0.1:9184/metrics
streamtop <URL> --prometheus 9184 --metrics-bind 0.0.0.0 \
--metrics-token "$STREAMTOP_METRICS_TOKEN"
curl -H "Authorization: Bearer $STREAMTOP_METRICS_TOKEN" http://host:9184/metrics
A non-loopback --metrics-bind requires a non-empty --metrics-token or STREAMTOP_METRICS_TOKEN. Only the Authorization: Bearer header is accepted; a ?token= query is rejected.
--prometheus runs until Ctrl+C. It does not open the dashboard, and it cannot be combined with --summary, --audit, --export, --multi-cdn, --compare, or --vod.
streamtop --export grafana writes a dashboard JSON for these metrics.
Multi-stream agent
streamtop --agent agent.example.toml
The agent polls every [[streams]] entry in the TOML file without a TUI and serves aggregated /metrics. See agent.example.toml in the repository.
OpenTelemetry
streamtop <URL> --otel-endpoint http://127.0.0.1:4318
Sends OTLP traces and metric batches to /v1/traces and /v1/metrics. Private, link-local, and cloud metadata hosts are blocked unless --allow-insecure-otel is set.
Webhooks
streamtop <URL> --webhook https://hooks.example/x --alert-on stall,shi_below_70,http_5xx
Slack, Discord, and generic HTTP targets are supported. --alert-on values: stall, shi_below_70, http_5xx, mismatch, ad_start, ad_mismatch. Private and metadata hosts are blocked unless --allow-insecure-webhooks is set (meant for tests).
Profiles
--profile NAME loads headers, User-Agent, interval, and other options from ~/.config/streamtop/config.toml. See config.example.toml.
Compare and multi-CDN
Side by side
streamtop --compare <URL_1> <URL_2>
Two streams in one TUI, for example origin and edge, or two encoder outputs. Keys: Space pause/resume, d detail, l log focus, c curl, h or e HAR, Tab switch pane.
Multi-CDN skew
streamtop --multi-cdn akamai=https://a.example/live.m3u8,cloudflare=https://b.example/live.m3u8
streamtop --multi-cdn https://a.example/live.m3u8,https://b.example/live.m3u8 --summary --timeout 15
Polls every edge concurrently and builds a live-edge skew matrix from media sequence numbers and PDT. When the skew passes --max-cdn-skew-ms (default 3000) it reports ERR_CDN_SYNC_SKEW. With --summary it prints JSON and exits non-zero when the threshold is exceeded.
Comparison with other tools
streamtop overlaps with several established tools. None of them is a replacement for the others; they answer different questions. This page tries to be factual about where each one fits. Corrections are welcome as issues or pull requests.
Summary
| streamtop | TSDuck | ffprobe | threefive | iptv-checker | |
|---|---|---|---|---|---|
| Main job | Live HLS/DASH monitoring over time | MPEG-TS analysis and processing | Container and codec inspection | SCTE-35 decode and encode | Check links in IPTV playlists |
| Language | Rust | C++ | C (FFmpeg) | Python | Node.js |
| Interface | TUI and CLI | CLI (tsp plugins and utilities) | CLI | CLI and library | CLI and library |
| HLS / DASH playlists | Polls live playlists continuously | HLS input plugin | Reads them as inputs | Parses SCTE-35 in HLS; DASH SCTE-214 support | Uses ffprobe per link |
| MPEG-TS depth | Probe window only (TR 101 290 P1/P2) | Whole-stream analysis, PSI/SI tables, PCR and continuity checks, many plugins | Demux and decode | SCTE-35 sections in TS | None |
| UDP / multicast / SRT | No | Yes | Yes (via FFmpeg protocols) | UDP and multicast for TS | No |
| Media decode | No | No (transport level) | Yes | No | Via ffprobe |
| SCTE-35 | Decodes HLS tags and DASH emsg live, flags mismatches; streamtop scte35 decodes one cue | Splice monitoring and injection plugins | Exposes data streams, no SCTE-35 semantics | Full decode and encode, the main purpose | No |
| CDN / HTTP timing | DNS, TCP, TLS, TTFB, CDN HIT/MISS per segment | No | No | No | No |
| Prometheus / OTLP | Yes | No | No | No | No |
| CI verdicts | PASS/FAIL JSON, SARIF, budgets | Exit codes from scripts | Exit codes from scripts | No | Results written to an output directory |
When to use which
Use TSDuck when the problem is inside the transport stream: PSI/SI tables, PID mapping, PCR and continuity analysis over the whole stream, multicast or DVB input, remultiplexing, or SCTE-35 injection. TSDuck works at the MPEG-TS level and is far deeper there than streamtop. streamtop only inspects the first bytes of each segment.
Use ffprobe when you need exact codec and container parameters from one file or URL, or anything that needs decoding. ffprobe reads a snapshot; it does not track a live playlist over time, and it does not report HTTP timing or CDN behavior.
Use threefive when the job is SCTE-35 itself: decoding cues from TS, HLS, base64, hex, or XML, encoding new cues, or injecting them. streamtop decodes the cues it finds while monitoring, and streamtop scte35 decodes a single Base64 or hex cue, but it does not encode, inject, or verify the CRC.
Use iptv-checker when you want per-channel status plus ffprobe stream metadata (codecs, resolution) for a playlist, with retries, delays, and proxy support. streamtop check probes reachability and segment TTFB without ffprobe, prints a table, JSON, or CSV, and can write the working entries to a new M3U with --alive-out.
Use streamtop when you are watching a live HLS or DASH channel over minutes or hours and want to see segment timing, CDN edge behavior, stalls, ABR ladder versus bitstream mismatches, and ad markers in one terminal view, or when you want that as Prometheus metrics or a CI gate.
Other tools
- Eyevinn hls-monitor: HTTP service that monitors HLS streams for errors.
- DASH-IF Conformance: the reference conformance validator for MPEG-DASH. Use it for spec conformance; streamtop does not validate full DASH conformance.
- Apple
mediastreamvalidator: the reference HLS validator, macOS only.
Limits
streamtop is a wire and container probe. It is not a decoder or a full transport stream analyzer.
- No media decode. Probes read headers and the first bytes of segments (the probe window). A stream that sends black frames or silent audio can still look healthy.
- TR 101 290 covers P1 and P2 checks on the MPEG-TS probe window only (the first 64 KB of each probed segment), not an analysis of the whole multiplex. Windows are not contiguous, so continuity counter, PCR, and PTS checks restart at each segment and errors at segment boundaries are not seen. PAT and PMT repetition is measured on the PCR clock inside the window. CRC-32 and SI tables (SDT, NIT, EIT) are not checked. Use TSDuck for deep transport stream work.
- Glass-to-glass is an estimate from HLS PDT, DASH segment availability time (or MPD publish time), and PRFT when present. DASH timestamps more than one hour from the local clock are ignored. It is not player end-to-end latency.
- WHEP is signaling only (SDP offer and answer). There is no WebRTC media path.
- No SRT, RTMP, UDP, or multicast input.
srt://andrtmp://URLs are rejected at startup. - DASH live edge. For a dynamic MPD with a SegmentTemplate, streamtop probes the newest media segment: the last
Sof a SegmentTimeline, or fordurationtemplates one segment behind the last complete one by the local clock. If the local clock is off by more than a segment, those probes can return 404. Without a SegmentTemplate it probes the first Representation URL when MPD@publishTime changes. - DASH conformance is not validated against the full specification. Use the DASH-IF Conformance tool for that.
- Linter score (TUI) uses four flags: RFC -15, origin stall -20, CDN MISS -5, high TTFB -10. The summary JSON keeps the older SHI field names (
schema_version7). - Quick Play needs
mpvorffplayon the PATH and does not work in the Docker image.
FAQ
How is streamtop different from ffprobe or VLC? ffprobe inspects a single file or URL snapshot, and VLC plays the stream. streamtop polls live playlists, tracks segment health over time, shows SCTE-35 markers and linter score trends, and exports Prometheus metrics and CI summary JSON. See Comparison.
Does it work headless in CI?
Yes. Use --summary --summary-format json --timeout N for PASS/FAIL output, --summary-format sarif or --export sarif:FILE for Code Scanning, and --budget-max-* for threshold gates. See Headless and CI.
Which protocols are supported? HLS (including LL-HLS parts), MPEG-DASH, IPTV channel lists (M3U, JSON, YAML), and WHEP HTTP endpoints. Wire probes cover fMP4, MPEG-TS, ADTS, and H.264/H.265 elementary streams without a decoder.
Can it check which channels in my IPTV playlist work?
Yes. streamtop check playlist.m3u prints LIVE, STALL, or ERROR for every entry, with JSON/CSV output, --alive-out for a cleaned playlist, and --fail-on-dead for scripts. See IPTV playlist checking.
Is it safe to expose Prometheus metrics?
The default bind is loopback. A non-loopback bind requires --metrics-token or STREAMTOP_METRICS_TOKEN, and requests must send Authorization: Bearer.
Are tokens in my URLs written to disk? Exports and diagnostics redact URLs, query tokens, and secrets.
Does it need FFmpeg?
No. Only Quick Play (p) uses mpv or ffplay if they are installed.
Where do I report a bug? GitHub issues. Questions and ideas can go to Discussions.