---
title: TS Analyze Perfect Streamer Toolkit v2.2 — TR 101 290
url: https://doc.pstreamer.tv/en/manual/ts_analyze.html
lang: en
product: Perfect Streamer
version: 1.13.3.445
---

# TS Analyze Perfect Streamer Toolkit v2.2 — TR 101 290

Part of the **Perfect Streamer Toolkit** — [https://pstreamer.tv](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://239.1.1.1:1234` | UDP multicast |
| `udp://eth0@239.1.1.1:1234` | UDP multicast on a specific interface |
| `udp://192.168.1.100:1234` | UDP unicast |
| `udp://lo@127.0.0.1:12655` | UDP unicast on loopback (test source) |
| `/path/to/file.ts` | Local TS file |

RTP-encapsulated UDP is auto-detected and de-encapsulated.

### Options

| Option | Description | Default |
| --- | --- | --- |
| `-t, --time <sec>` | Analysis duration in seconds | `30` |
| `-s, --short` | Short summary report | – |
| `-f, --full` | Full detailed report | yes |
| `-b, --bitrate <Mbps>` | TS bitrate hint for file mode | `38.8` |
| `-p, --pcr-pid <pid>` | Analyse a specific PCR PID only (decimal or `0xHHHH`) | auto |
| `-l, --pcr-limit <ms>` | PCR repetition error limit in ms | `40` |
| `--no-eit` | Skip EIT analysis — P3.7..P3.10 reported as `N/A`, EIT contributions to P2.2 / section-size totals removed | EIT enabled |
| `--no-nit` | Skip NIT analysis — P3.1, P3.2 reported as `N/A`, NIT contributions to P2.2 / section-size totals removed | NIT enabled |
| `--no-color` | Disable ANSI colour output | colours on |
| `--xml` | Emit structured XML on stdout (quiet stderr) | text |
| `-h, --help` | Show usage | – |

### Examples

```bash
# 30-second TR 101 290 check on a multicast stream
ts_analyze -t 30 udp://239.10.10.1:1234

# short summary, save to 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 only a single PCR PID
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 where they are intentionally absent)
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 |
| --- | --- | --- |
| `--no-eit` | 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. |
| `--no-nit` | 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
<?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 with `0x` prefix).
- `result` attribute uses `PASS` / `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"` and `result="N/A"` so that schema consumers see a stable shape.
- `<drift>` carries `verdict_mode="informational"` for `30 s ≤ T < 300 s` and `verdict_mode="hard"` for `T ≥ 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 |
| --- | --- | --- |
| `PASS` / `ok` | green | Test satisfies the standard |
| `WARN` / `WARNING` / `WARN(STB)` | yellow | Soft violation, does not affect OVERALL |
| `FAIL` / `ERROR` | red | Standard violation, affects OVERALL |
| `INFO` / `NOTE` / `N/A` | 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 |
| --- | --- | --- |
| `T < 30 s` | **skipped** (noise dominates the ±30 ppm boundary) | none |
| `30 s ≤ T < 300 s` | **WARN** — informational only | none |
| `T ≥ 300 s` | **FAIL** | OVERALL = FAIL, exit 65 |

`300 s` is the acceptance window (a product value; the **ETSI TR 101 290** standard does not normalize measurement intervals) — 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 `lo`) | **5 min** | 15 min | 30 min |
| Calibration / lab measurement | — | 30 min | 1+ hour |

Examples:

```bash
# 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 |
| --- | --- |
| `0` | Analysis completed and **OVERALL = PASS** |
| `1` | Argument or input error |
| `2` | Stream contains no PCR data |
| `3` | Stream duration below 2 s minimum |
| `65` | Analysis completed but **OVERALL = FAIL** — TR 101 290 / ISO 13818-1 violation |
| `130` | Interrupted by **SIGINT** (Ctrl+C) — analysis aborted, no report produced |
| `143` | 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:

```bash
ts_analyze -s -t 60 udp://239.1.1.1:5000 || {
    case $? in
        65)  echo "stream does not conform — 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.
