dvb-conformance
ETSI TR 101 290 v1.4.1 transport-stream conformance monitor (DVB measurement guidelines). Feed TS packets with a caller-supplied monotonic clock, drain structured conformance events per indicator.
Quick start
use ;
use Duration;
let mut monitor = new; // default config
let mut t = ZERO;
for packet in ts_packets
Use ConformanceMonitor::with_config(Config { .. }) to tune thresholds (PAT/PMT
max intervals, PCR repetition and discontinuity limits, SI repetition intervals, etc.).
What's implemented
Indicators — 19 implemented, per the Indicator enum in src/lib.rs
| Priority | Clause | Indicator | Notes |
|---|---|---|---|
| 1 | 1.1 | TsSyncLoss |
Hysteresis: 5 consecutive good → in-sync; 2 consecutive bad → sync lost |
| 1 | 1.2 | SyncByteError |
sync_byte != 0x47 on any packet |
| 1 | 1.3.a | PatError2 |
PAT absent > 500 ms (default); wrong table_id or scrambled on PID 0x0000 |
| 1 | 1.4 | ContinuityCountError |
CC wrap + duplicate-packet allowance (one dup per sequence) |
| 1 | 1.5.a | PmtError2 |
PMT absent > 500 ms per program_map_PID; scrambled on PMT PID |
| 1 | 1.6 | PidError |
Referenced ES PID absent > 5 s (default) |
| 2 | 2.1 | TransportError |
transport_error_indicator set |
| 2 | 2.2 | CrcError |
CRC-32 mismatch on completed long-form SI/PSI section |
| 2 | 2.3a | PcrRepetitionError |
PCR interval > 100 ms (default) on any PCR-carrying PID |
| 2 | 2.3b | PcrDiscontinuityError |
PCR delta > 100 ms (default) without discontinuity_indicator |
| 2 | 2.5 | PtsError |
PTS interval > 700 ms (default) on ES PIDs |
| 2 | 2.6 | CatError |
Wrong table_id on PID 0x0001; scrambled packet with no CAT seen |
| 3 | 3.1 | NitError |
Bad table_id on PID 0x0010 (not NIT_actual/NIT_other/ST); NIT_actual absent > 10 s (default) |
| 3 | 3.2 | SiRepetitionError |
Max-interval dimension: NIT_actual (10 s), SDT_actual (2 s), EIT P/F actual (2 s), TDT (30 s) |
| 3 | 3.4 | UnreferencedPid |
A PID persists > 500 ms (default) without being referenced by the PAT/CAT/a PMT or a well-known SI PID |
| 3 | 3.5 | SdtError |
Bad table_id on PID 0x0011 (not SDT_actual/SDT_other/BAT/ST); SDT_actual absent > 2 s (default) |
| 3 | 3.6 | EitError |
Bad table_id on PID 0x0012 (not EIT P/F or schedule range 0x50–0x6F or ST); EIT P/F actual absent > 2 s (default) |
| 3 | 3.7 | RstError |
Bad table_id on PID 0x0013 (not RST/ST) |
| 3 | 3.8 | TdtError |
Bad table_id on PID 0x0014 (not TDT/TOT/ST); TDT absent > 30 s (default) |
New indicators (T-STD, #737)
| Priority | Clause | Indicator | Notes |
|---|---|---|---|
| 2 | 2.4 | PcrAccuracyError |
Not implemented — requires hardware arrival timing with ±500 ns resolution (ISO/IEC 13818-1 §2.4.2.2); the variant exists for documentation completeness only; never emitted |
| 3 | 3.3 | BufferError |
TBsys overflow (512-byte buffer, 1 Mbit/s drain); TBn overflow deferred (needs coded bitrate Rxn from descriptors) |
| 3 | 3.9 | EmptyBufferError |
TBn/TBsys empty at least once per second; MBn check deferred (needs leak-method parameters from descriptors) |
| 3 | 3.10 | DataDelayError |
Data delay through T-STD transport buffers > 1 s; still-picture 60 s threshold NOT implemented — requires PMT stream_type detection from descriptors |
T-STD buffer model (#737)
A partial ISO/IEC 13818-1 T-STD buffer model (see src/tstd.rs) drives
indicators 3.3, 3.9, and 3.10:
- TBn (per-PID, 512 bytes): modelled for empty-interval and data-delay
tracking. Overflow detection is deferred — it requires the coded bitrate
Rxnfrom descriptors (multiplex_buffer_descriptor). - TBsys (global, 512 bytes, 1 Mbit/s drain): fed at PSI section completion. Overflow (firewall), empty-interval, and data-delay checks are implemented.
- MBn / EBn / Bn / Bsys: deferred — these require codec-level buffer sizes from descriptors and are not yet parsed by the monitor.
All buffer sizes and rates are named constants citing the vendored ITU-T
H.222.0 v9 (08/2023) PDF. The full transcription is at
dvb-conformance/docs/h222_0-tstd-buffer-model.md.
| Constant | Value | H.222.0 clause |
|---|---|---|
| TBn / TBsys size | 512 bytes | §2.4.2.4, p.42: "The transport buffer size is fixed at 512 bytes" |
| TBsys drain rate | 1 Mbit/s | §2.4.2.4, p.42: "For systems data: Rxn = 1×10⁶ bits per second" |
| Bsys size | 1536 bytes | §2.4.2.4, p.43: "The main buffer Bsys … size BSsys = 1536 bytes" (deferred) |
| TB leak rate floor | 125 kbit/s | Modelling floor, not a spec value (Rxn ≥ 2×10⁶ bps per §2.4.2.4) |
Note on 2.4 PCR_accuracy_error: this indicator requires hardware arrival
timestamps with ±500 ns accuracy. The monitor is sans-IO with a
caller-supplied clock; a packet-index-derived timing estimate cannot
honestly resolve 500 ns. A false positive here is worse than a gap
(cf. the withdrawn PtsCheck). The indicator exists in the enum for
documentation completeness but is never emitted.
Excluded, split by reason:
Not computable without hardware arrival timing (needs ±500 ns resolution):
| Clause | Indicator | Reason |
|---|---|---|
| 2.4 | PCR_accuracy_error |
Requires ±500 ns PCR accuracy measurement against a hardware reference clock (ISO/IEC 13818-1 §2.4.2.2); a packet-index-derived arrival estimate cannot resolve 500 ns |
Partially implemented — TBn overflow / MBn / EBn / Bn / Bsys deferred (needs codec-dependent buffer-size descriptors not yet parsed by the monitor):
| Clause | Indicator | Deferred sub-checks |
|---|---|---|
| 3.3 | Buffer_error |
TBn overflow (needs Rxn from descriptors); MBn/EBn/Bn underflow/overflow; Bsys overflow |
| 3.9 | Empty_buffer_error |
MBn empty-at-least-once-per-second (leak method) |
| 3.10 | Data_delay_error |
Still-picture video data 60 s threshold differentiation; MBn delay |
Feasible, deferred (reusable with the existing timer machinery, but not yet implemented):
| Clause | Indicator | Reason |
|---|---|---|
| 3.1.a / 3.2 / 3.5.a / 3.6.a / 3.7 / 3.8 | (25 ms min-gap dimension) | Needs per-(table_id, section_number) tracking to avoid false positives on dense multi-section tables |
| 3.1.b / 3.5.b / 3.6.b | NIT_other_error / SDT_other_error / EIT_other_error |
Need TR 101 211 _other repetition interval rules |
| 3.6.c | EIT_PF_error |
EIT P/F section-0/1 pairing check not yet implemented |
Caller-supplied time model
ConformanceMonitor::feed(packet, t) takes a core::time::Duration alongside
each TS packet. The monitor uses this clock for all presence/absence timeout
checks (1.3.a, 1.5.a, 1.6, 2.3a, 2.3b, 2.5, 3.2). The caller must supply
monotonic non-decreasing timestamps; the monitor does not enforce this but
non-monotonic timestamps will produce spurious events. Because there is no
independent hardware clock, PCR accuracy (2.4) and buffer-model indicators are
not computable.
SI_repetition_error (3.2) — implementation notes
- Maximum-interval checks are implemented for NIT_actual (10 s), SDT_actual (2 s), EIT P/F actual (2 s), and TDT (30 s). Each table's timer is lazily armed — checking starts only after the first section of that table is seen; an entirely absent table is not flagged by this indicator (that is the role of the out-of-scope per-table presence indicators).
- EIT P/F is tracked at the table level (any section with table_id
0x4Eresets the timer), not per section_number, to avoid false positives on dense EIT schedules.
PAT-following PMT discovery
The monitor parses each completed PAT section and automatically starts tracking
the program_map_PID entries it finds, enabling indicator 1.5.a (PMT absence)
and ES PID extraction (indicator 1.6).
NIT/SDT/EIT/RST/TDT_error (3.1, 3.5, 3.6, 3.7, 3.8) — implementation notes
- Each indicator validates the
table_idof every completed section on its well-known PID against the allowed set fromdocs/tr_101_290.mdclause 3.x, firing immediately on a disallowed value. - The absence dimension of 3.1/3.5/3.6/3.8 (NIT_actual/SDT_actual/EIT P/F
actual/TDT missing beyond the repetition interval) is raised from the
same lazily-armed timer that drives
SiRepetitionError(3.2) — the two indicators are the same underlying absence event with two spec identities (the old combined indicator vs. the newer split_actualvariant); both fire together. RstError(3.7) has no documented absence threshold in Table 5.0c, so it only has the bad-table_id dimension.
Unreferenced_PID (3.4) — implementation notes
- Tracks the first-seen time of any PID that is not (yet) part of the
referenced set: PAT, CAT, the well-known SI PIDs (NIT/SDT-BAT/EIT/RST/
TDT-TOT), the null PID, the reserved-for-future-use range (0x0002–0x000F),
program_map_PIDs from the PAT, and ES/PCR PIDs from a PMT. A PID that persists past the 500 ms (default) threshold without becoming referenced raisesUnreferencedPid. - Known limitations (documented, not silently swallowed): CAT-referenced
EMM PIDs are not exempted — this monitor validates CAT
table_idbut does not decode CA descriptors to extractCA_PIDs. PIDs "user defined as private data streams" (the spec's own carve-out) are likewise not distinguishable from the wire alone. Either can produce a false positive for a stream using that pattern; the crate does not currently model it.
Feature flags
| Feature | Default | Description |
|---|---|---|
std |
on | Link the standard library. Without it the crate is #![no_std] + alloc. |
serde |
on | Serialize-only (serde::Serialize) on ConformanceEvent, Indicator, Priority, Stats. |
MSRV
Rust 1.86.
References
- ETSI TR 101 290 v1.4.1 (2020-06) — DVB Measurement Guidelines (§5.2.1 Table 5.0a, §5.2.2 Table 5.0b, §5.2.3 Table 5.0c)
- ISO/IEC 13818-1 — MPEG-2 Systems
Examples
Run with cargo run -p dvb-conformance --example <name>:
monitor_stream— run the TR 101 290 monitor over a capture and print the headline stats.priority_breakdown— tally findings by measurement priority (1/2/3) and indicator.
License
Licensed under either of MIT (LICENSE-MIT) or Apache-2.0 (LICENSE-APACHE), at your option.