#![cfg(feature = "ts")]
use dvb_si::demux::SiDemux;
use mpeg_ts::mux::SectionPacketizer;
use mpeg_ts::ts::{TS_PACKET_SIZE, TS_SYNC_BYTE};
fn read_fixture(name: &str) -> Vec<u8> {
let path = format!("{}/../fixtures/ts/{}", env!("CARGO_MANIFEST_DIR"), name);
std::fs::read(&path).unwrap_or_else(|e| panic!("read fixture {path}: {e}"))
}
fn collect_sections(data: &[u8]) -> Vec<(u16, Vec<u8>)> {
let mut demux = SiDemux::builder().build();
let mut out = Vec::new();
for chunk in data.chunks(TS_PACKET_SIZE) {
if chunk.len() != TS_PACKET_SIZE || chunk[0] != TS_SYNC_BYTE {
continue;
}
for ev in demux.feed(chunk) {
out.push((u16::from(ev.pid()), ev.bytes().to_vec()));
}
}
out
}
#[test]
fn packetizer_round_trips_real_capture_through_si_demux() {
let data = read_fixture("m6-single.ts");
let original = collect_sections(&data);
assert!(
original.len() >= 3,
"fixture must yield several SI sections, got {}",
original.len()
);
let mut pids: Vec<u16> = Vec::new();
for (pid, _) in &original {
if !pids.contains(pid) {
pids.push(*pid);
}
}
pids.sort_by_key(|&p| if p == 0x0000 { 0 } else { 1 + p as u32 });
let mut regenerated: Vec<[u8; TS_PACKET_SIZE]> = Vec::new();
for &pid in &pids {
let sections: Vec<&[u8]> = original
.iter()
.filter(|(p, _)| *p == pid)
.map(|(_, b)| b.as_slice())
.collect();
let mut packetizer = SectionPacketizer::new(pid);
regenerated.extend(packetizer.packetize(§ions));
}
let mut demux = SiDemux::builder().build();
let mut round = Vec::new();
for pkt in ®enerated {
for ev in demux.feed(pkt) {
round.push((u16::from(ev.pid()), ev.bytes().to_vec()));
}
}
let mut a = original.clone();
let mut b = round.clone();
a.sort();
b.sort();
assert_eq!(
b,
a,
"round-tripped sections must match the originals (got {} vs {})",
round.len(),
original.len()
);
}