Skip to main content

Crate dvb_conformance

Crate dvb_conformance 

Source
Expand description

ETSI TR 101 290 v1.4.1 transport-stream conformance monitor.

Implements the first-priority (Table 5.0a, indicators 1.1–1.6), second-priority (Table 5.0b, indicators 2.1–2.3b, 2.5–2.6), and SI-repetition (Table 5.0c, indicator 3.2 — maximum interval) indicator sets. Indicator 2.4 (PCR_accuracy_error) is intentionally excluded — it requires hardware arrival timestamps not available under the caller-supplied- time model. Indicator 3.2’s minimum-gap (25 ms) dimension is deferred — it needs per-(table_id, section_number) tracking to avoid false positives on dense multi-section tables.

§Caller-supplied time

ConformanceMonitor::feed takes a core::time::Duration timestamp alongside each TS packet. All presence/absence timeout checks (1.3.a, 1.5.a, 1.6, 2.3a, 2.3b, 2.5, 3.2) are evaluated against this clock. The caller must ensure that timestamps are monotonic non-decreasing across calls; the monitor does not enforce this but non-monotonic timestamps will produce spurious events.

§References

  • ETSI TR 101 290 v1.4.1 (2023-05), §5.2.1, Table 5.0a
  • ETSI TR 101 290 v1.4.1 (2023-05), §5.2.2, Table 5.0b
  • ETSI TR 101 290 v1.4.1 (2023-05), §5.2.3, Table 5.0c
  • ISO/IEC 13818-1 (MPEG-2 Systems)

§Examples

Two runnable examples ship with this crate (cargo run -p dvb-conformance --example <name>).

§monitor_stream

//! Basic: run the TR 101 290 conformance monitor over a capture and print the
//! headline stats.
//!
//! Run with: `cargo run -p dvb-conformance --example monitor_stream`
//!
//! Reads the committed `m6-single.ts` fixture from the sibling `dvb-si` crate
//! at runtime, so the example compiles even when the fixture is absent.

use core::time::Duration;
use dvb_conformance::ConformanceMonitor;

const PKT: usize = 188;
const INTER_PACKET_US: u64 = 40; // ~nominal spacing for the timing checks

fn main() {
    let path = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../dvb-si/tests/fixtures/m6-single.ts"
    );
    let data = match std::fs::read(path) {
        Ok(b) => b,
        Err(e) => {
            eprintln!("fixture not available ({e}); nothing to do");
            return;
        }
    };

    let mut monitor = ConformanceMonitor::new();
    let mut total_events = 0usize;
    for (i, pkt) in data.chunks(PKT).enumerate() {
        if pkt.len() < PKT {
            break;
        }
        let t = Duration::from_micros(i as u64 * INTER_PACKET_US);
        total_events += monitor.feed(pkt, t).len();
    }

    let stats = monitor.stats();
    println!("packets analysed : {}", stats.packets);
    println!("in sync          : {}", stats.in_sync);
    println!("events raised    : {total_events}");
}

§priority_breakdown

//! Advanced: run the TR 101 290 monitor and break the findings down by
//! measurement priority and indicator — the shape of a real QoS report.
//!
//! Run with: `cargo run -p dvb-conformance --example priority_breakdown`

use core::time::Duration;
use dvb_conformance::{ConformanceEvent, ConformanceMonitor, Priority};
use std::collections::BTreeMap;

const PKT: usize = 188;
const INTER_PACKET_US: u64 = 40;

fn main() {
    let path = concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../dvb-si/tests/fixtures/m6-single.ts"
    );
    let data = match std::fs::read(path) {
        Ok(b) => b,
        Err(e) => {
            eprintln!("fixture not available ({e}); nothing to do");
            return;
        }
    };

    let mut monitor = ConformanceMonitor::new();
    let mut events: Vec<ConformanceEvent> = Vec::new();
    for (i, pkt) in data.chunks(PKT).enumerate() {
        if pkt.len() < PKT {
            break;
        }
        let t = Duration::from_micros(i as u64 * INTER_PACKET_US);
        events.extend_from_slice(monitor.feed(pkt, t));
    }

    let (mut p1, mut p2, mut p3) = (0u32, 0u32, 0u32);
    let mut by_indicator: BTreeMap<String, u32> = BTreeMap::new();
    for ev in &events {
        match ev.priority {
            Priority::First => p1 += 1,
            Priority::Second => p2 += 1,
            Priority::Third => p3 += 1,
            _ => {}
        }
        *by_indicator.entry(ev.indicator.to_string()).or_default() += 1;
    }

    let stats = monitor.stats();
    println!("== TR 101 290 report ({} packets) ==", stats.packets);
    println!("Priority 1 (must decode) : {p1}");
    println!("Priority 2 (recommended) : {p2}");
    println!("Priority 3 (application) : {p3}");
    if by_indicator.is_empty() {
        println!("\nno conformance events — stream is clean ✔");
    } else {
        println!("\nby indicator:");
        for (name, n) in &by_indicator {
            println!("  {name:<24} {n}");
        }
    }
}

Structs§

Config
Configurable hysteresis and timeout parameters.
ConformanceEvent
One raised conformance error.
ConformanceMonitor
ETSI TR 101 290 transport-stream conformance monitor.
Stats
Diagnostic counters.

Enums§

Indicator
A TR 101 290 measurement indicator.
Priority
Severity tier per TR 101 290 §5.2 (Tables 5.0a/5.0b/5.0c).