TS Analyze Perfect Streamer Toolkit v2.2 — TR 101 290¶
Part of the Perfect Streamer Toolkit — https://pstreamer.tv
Command-line MPEG-TS transport stream analyzer with ETSI TR 101 290 V1.4.1 compliance checking and ISO/IEC 13818-1 T-STD buffer-model validation.
Reads UDP multicast/unicast or TS files, auto-discovers PCR PIDs via PAT/PMT, and prints a detailed or summary report to stdout.
What it checks¶
The analyzer walks every TS packet and reports violations of:
Priority 1 (TS decodability): TS sync, sync loss, PAT/PMT presence and CRC, continuity counter, PID presence
Priority 2 (recommended monitoring): transport error indicator, CRC errors, PCR repetition / accuracy / discontinuity, PTS interval, CAT presence
Priority 3 (extended monitoring): NIT/SDT/EIT/TDT intervals, unreferenced PIDs, T-STD buffer overflow / underflow
In addition, it produces:
PCR accuracy to ±500 ns precision via byte-position regression
PCR drift in ppm (live mode)
T-STD buffer model per elementary stream (live mode)
SI section size validation against ISO/EN limits, with EIT-on-STB compatibility warnings (>1024 B)
UDP IAT (inter-arrival time) statistics — datagram-level network jitter (live mode only)
Usage¶
ts_analyze [options] <input>
Inputs¶
Form |
Description |
|---|---|
|
UDP multicast |
|
UDP multicast on a specific interface |
|
UDP unicast |
|
UDP unicast on loopback (test source) |
|
Local TS file |
RTP-encapsulated UDP is auto-detected and de-encapsulated.
Options¶
Option |
Description |
Default |
|---|---|---|
|
Analysis duration in seconds |
|
|
Short summary report |
– |
|
Full detailed report |
yes |
|
TS bitrate hint for file mode |
|
|
Analyse a specific PCR PID only (decimal or |
auto |
|
PCR repetition error limit in ms |
|
|
Skip EIT analysis — P3.7..P3.10 reported as |
EIT enabled |
|
Skip NIT analysis — P3.1, P3.2 reported as |
NIT enabled |
|
Disable ANSI colour output |
colours on |
|
Emit structured XML on stdout (quiet stderr) |
text |
|
Show usage |
– |
Examples¶
# 30-second TR 101 290 check on a multicast stream
ts_analyze -t 30 udp://239.10.10.1:1234
# brief summary, saved to a log (no color)
ts_analyze -s --no-color -t 60 udp://239.10.10.1:1234 > report.txt
# analyze a TS file
ts_analyze -t 30 recording.ts
# analyze a single PCR PID only
ts_analyze -p 0x0100 -t 30 udp://239.10.10.1:1234
# machine-readable XML for CI / monitoring
ts_analyze --xml -t 30 udp://239.10.10.1:1234 > result.xml
# skip EIT/NIT analysis (e.g. for streams that intentionally have none)
ts_analyze --no-eit --no-nit -t 30 udp://239.10.10.1:1234
Disabling EIT or NIT analysis¶
Some streams intentionally omit EIT or NIT (closed networks, lab feeds, OTT-only contribution, etc.). In that case the corresponding TR 101 290 P3 checks would always FAIL the OVERALL gate, which is just noise.
Use --no-eit and/or --no-nit to drop those checks:
Flag |
Skipped checks |
Side effects |
|---|---|---|
|
P3.7 (EIT actual P/F), P3.8 (EIT other P/F), P3.9 (EIT actual schedule), P3.10 (EIT other schedule) |
EIT sections are not assembled, so they contribute zero to P2.2 (CRC) and to the SI section-size summary. EIT-on-STB compatibility warning is suppressed. |
|
P3.1 (NIT actual), P3.2 (NIT other) |
NIT sections are not assembled, so they contribute zero to P2.2 (CRC) and to the SI section-size summary. |
Skipped checks appear in the report as N/A with a disabled (--no-eit) / disabled (--no-nit) note, and in the XML as applicable="false" result="N/A". The short report shows NIT=off / EIT=off instead of an error count.
The flags affect only EIT (PID 0x0012) and NIT (PID 0x0010) processing — every other TR 101 290 check (P1.x, P2.x, SDT, TDT, CAT, T-STD, PCR drift, IAT) runs normally.
XML output mode (--xml)¶
--xml makes the analyzer emit a single self-contained UTF-8 XML document on stdout. All informational chatter (banner, “Stream locked”, “PCR PIDs discovered”, per-second progress, capture summary, short-duration warnings) is suppressed; stderr stays empty unless something genuinely fails (input cannot be opened, no PCR data, stream too short, interrupted by signal). ANSI colours are forced off.
The exit code is the same as in text mode: 0 for OVERALL=PASS, 65 for OVERALL=FAIL, plus the standard error / signal codes (1, 2, 3, 130, 143).
Top-level XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<ts_analyze version="2.2">
<source>udp://239.1.1.1:5000</source>
<timestamp>2026-04-30T12:00:00+0300</timestamp>
<duration_s>30.00</duration_s>
<packets total="..." null="..."/>
<ts_bitrate_mbps>20.012</ts_bitrate_mbps>
<programs>
<program number="1" pmt_pid="0x0100" pcr_pid="0x0101">
<es pid="0x0101" stream_type="0x1b" name="H.264/AVC"/>
<es pid="0x0102" stream_type="0x03" name="MPEG-2 Audio"/>
</program>
</programs>
<tr101290>
<check id="1.1" name="TS Sync Byte Error" applicable="true" errors="0" result="PASS"/>
...
<check id="2.3" name="PCR Repetition Error"
applicable="true" errors="0" result="PASS" soft_violations="3"/>
...
<check id="3.4" name="Unreferenced PIDs" applicable="true" count="2" result="INFO"/>
...
</tr101290>
<si_section_size oversize_total="0" eit_stb_warn_total="12">
<table name="EIT_actual_pf" max_bytes="1380" std_limit="4096"
oversize="0" eit_stb_warn="12" result="WARN_STB"/>
...
</si_section_size>
<iat datagrams="33252" intervals="33251" min_ms="0.002" max_ms="5.009"
avg_ms="0.150" stddev_ms="0.295" p95_ms="0.872" p99_ms="1.076"
max_jitter_ms="4.272" gap_threshold_ms="100.0" gaps_over_threshold="0"/>
<pcr_pids>
<pcr_pid value="0x0101" sid="1" pcr_count="1500" discontinuities="0"
estimated_bitrate_mbps="18.750">
<interval samples="1499" min_ms="19.812" max_ms="20.195"
avg_ms="20.001" p95_ms="20.102"
iso_hard_violations="0" tr_soft_violations="0"
rec_violations="0" result="PASS"/>
<accuracy samples="1499" min_ns="-148.3" max_ns="201.7" abs_max_ns="201.7"
avg_ns="2.1" stddev_ns="45.6" p95_ns="102.3"
violations="0" result="PASS"/>
<drift measured="true" ppm="0.618" limit_ppm="30"
verdict_mode="informational" result="PASS"/>
<tstd overflows="0" underflows="0" max_fill_bytes="34218" result="PASS">
<es_buffer es_pid="0x0101" stream_type="0x1b"
capacity_bytes="3000000" measuring="true"
es_bitrate_mbps="15.200" max_fill_bytes="34218"
overflows="0" underflows="0"/>
</tstd>
</pcr_pid>
</pcr_pids>
<unreferenced_pids count="2">
<pid value="0x01ff"/>
<pid value="0x0200"/>
</unreferenced_pids>
<overall result="PASS"/>
</ts_analyze>
Key conventions:
All PIDs are formatted as
0xHHHH(4-digit hex with0xprefix).resultattribute usesPASS/FAIL/WARN/N/A/INFO/SKIP/ok/WARN_STB.For checks that are not applicable (file mode, scrambling absent, etc.) the element still appears with
applicable="false"andresult="N/A"so that schema consumers see a stable shape.<drift>carriesverdict_mode="informational"for30 s ≤ T < 300 sandverdict_mode="hard"forT ≥ 300 s;result="SKIP"for runs shorter than 30 s.<iat>is omitted for file-mode runs.<overall>reflects the same gate as the text report’s OVERALL line and matches the process exit code.
Output is well-formed XML (validated with xmllint --noout); pipe directly into XSLT, Python lxml, etc., without parsing tweaks.
Reading the report¶
Status colours¶
Status |
Colour |
Meaning |
|---|---|---|
|
green |
Test satisfies the standard |
|
yellow |
Soft violation, does not affect OVERALL |
|
red |
Standard violation, affects OVERALL |
|
default |
Informational only |
Use --no-color when piping into log files or non-ANSI terminals.
Minimum analysis duration¶
Duration |
Coverage |
Exit code |
|---|---|---|
< 2 s |
Insufficient — analysis refused |
3 (error) |
2–10 s |
P1 + P2 reliable; some P3 checks may lack data |
0 + WARN |
10–30 s |
P1 + P2 + most P3; TDT (30 s) may lack data |
0 + NOTE |
≥ 30 s |
Full coverage of all TR 101 290 checks |
0 |
The default duration is 30 seconds — sufficient for full TR 101 290 coverage. Use -t <sec> to extend (e.g. for PCR-drift acceptance) or shorten (e.g. for quick smoke tests).
While the analyzer is running, a one-line progress indicator updates every second on stderr:
Progress: 47.3% (14.2s / 30.0s, 330614 packets)
The line uses carriage-return (\r) so it stays on a single line in a terminal; redirect stderr to suppress (2>/dev/null).
PCR drift verdict — two-tier window¶
PCR clock tolerance per ISO/IEC 13818-1 §2.4.2.1 and ETSI TR 101 290 is ±30 ppm. The drift figure printed in the report comes from a linear regression of cumulative PCR seconds against wall-clock arrival time; its statistical error decreases as 1 / T^(3/2), so the analysis window must be long enough that measurement noise is well below the ±30 ppm boundary.
The analyzer therefore gates the drift verdict by the analysis duration:
Window |
Verdict on out-of-spec drift |
OVERALL impact |
|---|---|---|
|
skipped (noise dominates the ±30 ppm boundary) |
none |
|
WARN — informational only |
none |
|
FAIL |
OVERALL = FAIL, exit 65 |
300 s is the DVB TR 101 297 acceptance-test window — long enough that even a bursty/loopback delivery path averages below 1 ppm of measurement noise, so an out-of-spec result reflects the encoder clock, not the network. The full report shows the current tier on the Verdict mode line of the PCR DRIFT block.
To get a hard PASS/FAIL drift verdict, run with -t 300 or longer.
Source-quality guideline (informational; does not change verdict tiers):
Source |
Min window for ±5 ppm confidence |
For ±2 ppm |
Acceptance test |
|---|---|---|---|
Broadcast multicast (CBR network, jitter < 100 µs) |
30 s |
60 s |
5 min |
Stable IP network (jitter < 200 µs) |
30 s |
2 min |
5–10 min |
Loopback / bursty sender (UDP unicast on |
5 min |
15 min |
30 min |
Calibration / lab measurement |
— |
30 min |
1+ hour |
Examples:
# Quick PCR drift check on a real broadcast multicast (30 s)
ts_analyze -t 30 -s udp://239.1.1.1:5000
# Reliable check on a loopback source (5 min)
ts_analyze -t 300 -s udp://lo@127.0.0.1:12655
# Lab acceptance (30 min, full report to file)
ts_analyze -t 1800 -f --no-color udp://239.1.1.1:5000 > acceptance.txt
If the same stream is analysed in several short windows and the drift value varies by more than a few ppm between windows, the bottleneck is delivery jitter (sender pacing or network), not the encoder clock — extend the window.
Exit codes¶
Code |
Meaning |
|---|---|
|
Analysis completed and OVERALL = PASS |
|
Argument or input error |
|
Stream contains no PCR data |
|
Stream duration below 2 s minimum |
|
Analysis completed but OVERALL = FAIL — TR 101 290 / ISO 13818-1 violation |
|
Interrupted by SIGINT (Ctrl+C) — analysis aborted, no report produced |
|
Interrupted by SIGTERM — analysis aborted, no report produced |
65 is EX_DATAERR from POSIX <sysexits.h> — “input data was incorrect”. Use it in CI / monitoring scripts to gate on stream conformance:
ts_analyze -s -t 60 udp://239.1.1.1:5000 || {
case $? in
65) echo "stream non-compliant — see report" >&2 ;;
130) echo "interrupted by user" >&2 ;;
*) echo "tool error" >&2 ;;
esac
}
Codes 130/143 follow the POSIX shell convention 128 + signal_number so that $? after Ctrl+C matches what bash reports for any process killed by SIGINT/SIGTERM. On interruption the analyzer prints a single line to stderr (Analysis interrupted by signal N — no report produced.) and skips report generation entirely.
Sample output¶
Full report (excerpt)¶
========================================================================
MPEG-TS ANALYZER v2.2 — TR 101 290 FULL REPORT
========================================================================
Source : udp://239.1.1.1:5000
Duration : 30.00 s
Packets : 398936 total, 12045 null
TS bitrate : 20.012 Mbit/s
------------------------------------------------------------------------
========================================================================
TR 101 290 — PRIORITY 1 (TS decodability)
========================================================================
| 1.1 TS Sync Byte Error : 0 errors PASS
| 1.4 Continuity Count Error : 0 errors PASS
| 1.6 PID Error (5s absence) : 0 errors PASS
...
========================================================================
TR 101 290 — PRIORITY 2 (recommended monitoring)
========================================================================
| 2.3 PCR Repetition Error : 0 errors PASS
| 2.5 PCR Accuracy Error : 0 errors PASS
...
========================================================================
OVERALL COMPLIANCE: PASS — stream is TR 101 290 compliant
========================================================================
Short report¶
MPEG-TS Analyzer v2.2
TR 101 290 Summary | udp://239.1.1.1:5000 | 30.0s
----------------------------------------------------------------------------------------------------
P1: sync=0 CC=0 PAT=0 PMT=0 PID=0 P2: TEI=0 CRC=0 PTS=0 P3: NIT=0 SDT=0 EIT=0 TDT=0 unref=2
IAT: dgrams=33252 avg=0.150 ms max=5.009 ms p99=1.076 ms gaps>100ms=0
----------------------------------------------------------------------------------------------------
PCR PID SID Count Intv max Jitter max Drift Interval Accuracy T-STD
----------------------------------------------------------------------------------------------------
0x0101 1 1500 20.195 ms 76.4 ns 0ppm PASS PASS PASS
----------------------------------------------------------------------------------------------------
OVERALL: PASS
Notes¶
File mode: PCR drift, T-STD buffer model and UDP IAT are not measured — they require a real-time reference. All other checks work in both modes.
Single transport stream: one MPTS or SPTS analysed at a time.