libmpegts 0.3.2

MPEG-TS Library
Documentation
use std::{
    collections::HashMap,
    env,
    fs::File,
    io::Read,
};

use libmpegts::{
    slicer::TsSlicer,
    ts::{
        PACKET_SIZE,
        PID_NULL,
    },
};

struct PidStats {
    count: u64,
    cc_errors: u64,
    last_cc: Option<u8>,
}

fn main() -> std::io::Result<()> {
    let path = env::args().nth(1).expect("Usage: ts_check <file.ts>");
    let mut file = File::open(&path)?;
    let mut buffer = [0u8; PACKET_SIZE * 1024];
    let mut stats: HashMap<u16, PidStats> = HashMap::new();
    let mut slicer = TsSlicer::new();

    loop {
        let n = file.read(&mut buffer)?;
        if n == 0 {
            break;
        }

        for packet in slicer.slice(&buffer[.. n]) {
            let pid = packet.pid();
            let entry = stats.entry(pid).or_insert(PidStats {
                count: 0,
                cc_errors: 0,
                last_cc: None,
            });
            entry.count += 1;

            if pid != PID_NULL {
                if packet.payload().is_some() {
                    let mut discontinuity_indicator = false;
                    if let Some(af) = packet.adaptation_field() {
                        discontinuity_indicator = af.discontinuity_indicator();
                    }

                    let cc = packet.cc();
                    if let Some(last) = entry.last_cc {
                        let expected = (last + 1) & 0x0F;
                        if cc != expected && !discontinuity_indicator {
                            entry.cc_errors += 1;
                        }
                    }
                    entry.last_cc = Some(cc);
                }
            }
        }
    }

    let mut pids: Vec<_> = stats.into_iter().collect();
    pids.sort_by_key(|(pid, _)| *pid);

    println!("{:>5}  {:>10}  {:>10}", "PID", "Packets", "CC Errors");
    for (pid, s) in pids {
        println!("{:>5}  {:>10}  {:>10}", pid, s.count, s.cc_errors);
    }

    Ok(())
}