use super::super::pat_pmt::parse_pmt_streams;
use super::super::{
AudioCodecKind, DESC_TAG_REGISTRATION, STREAM_TYPE_AAC_ADTS, STREAM_TYPE_AC3,
STREAM_TYPE_EAC3, STREAM_TYPE_MPEG2_VIDEO, STREAM_TYPE_PES_PRIVATE, demux_ts,
};
use super::{build_ts_with_audio, synth_ac3_frame_stereo_48k_128k,
synth_eac3_frame_stereo_48k_192bytes};
#[test]
fn pmt_walker_classifies_aac_ac3_eac3_stream_types() {
let mut pmt = vec![0x02];
let stream_entries = 5 + 5 + 5 + 5; let pmt_section_len: usize = 9 + stream_entries + 4;
pmt.push(0xB0 | ((pmt_section_len >> 8) & 0x0F) as u8);
pmt.push((pmt_section_len & 0xFF) as u8);
pmt.extend_from_slice(&[0x00, 0x01, 0xC1, 0x00, 0x00]);
pmt.extend_from_slice(&[0xE2, 0x00, 0xF0, 0x00]); pmt.extend_from_slice(&[STREAM_TYPE_MPEG2_VIDEO, 0xE2, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[STREAM_TYPE_AAC_ADTS, 0xE3, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[STREAM_TYPE_AC3, 0xE4, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[STREAM_TYPE_EAC3, 0xE5, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[0u8; 4]);
let (video, audio) = parse_pmt_streams(&pmt).expect("parse");
assert_eq!(video.len(), 1);
assert_eq!(video[0].pid, 0x200);
assert_eq!(audio.len(), 3);
assert_eq!(
(audio[0].pid, audio[0].kind),
(0x300, AudioCodecKind::AacAdts)
);
assert_eq!((audio[1].pid, audio[1].kind), (0x400, AudioCodecKind::Ac3));
assert_eq!((audio[2].pid, audio[2].kind), (0x500, AudioCodecKind::Eac3));
}
#[test]
fn pmt_walker_recognises_dvb_ac3_via_registration_descriptor() {
let mut pmt = vec![0x02];
let descriptors: [u8; 6] = [DESC_TAG_REGISTRATION, 4, b'A', b'C', b'-', b'3'];
let stream_entries = 5 + 5 + descriptors.len();
let pmt_section_len: usize = 9 + stream_entries + 4;
pmt.push(0xB0 | ((pmt_section_len >> 8) & 0x0F) as u8);
pmt.push((pmt_section_len & 0xFF) as u8);
pmt.extend_from_slice(&[0x00, 0x01, 0xC1, 0x00, 0x00]);
pmt.extend_from_slice(&[0xE2, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[STREAM_TYPE_MPEG2_VIDEO, 0xE2, 0x00, 0xF0, 0x00]);
pmt.push(STREAM_TYPE_PES_PRIVATE);
pmt.extend_from_slice(&[0xE3, 0x00]);
let esi_len = descriptors.len() as u16;
pmt.push(0xF0 | ((esi_len >> 8) & 0x0F) as u8);
pmt.push((esi_len & 0xFF) as u8);
pmt.extend_from_slice(&descriptors);
pmt.extend_from_slice(&[0u8; 4]);
let (_, audio) = parse_pmt_streams(&pmt).expect("parse");
assert_eq!(audio.len(), 1);
assert_eq!(audio[0].kind, AudioCodecKind::Ac3);
assert_eq!(audio[0].stream_type, STREAM_TYPE_PES_PRIVATE);
}
#[test]
fn pmt_walker_recognises_dvb_eac3_via_registration_descriptor() {
let mut pmt = vec![0x02];
let descriptors: [u8; 6] = [DESC_TAG_REGISTRATION, 4, b'E', b'A', b'C', b'3'];
let stream_entries = 5 + 5 + descriptors.len();
let pmt_section_len: usize = 9 + stream_entries + 4;
pmt.push(0xB0 | ((pmt_section_len >> 8) & 0x0F) as u8);
pmt.push((pmt_section_len & 0xFF) as u8);
pmt.extend_from_slice(&[0x00, 0x01, 0xC1, 0x00, 0x00]);
pmt.extend_from_slice(&[0xE2, 0x00, 0xF0, 0x00]);
pmt.extend_from_slice(&[STREAM_TYPE_MPEG2_VIDEO, 0xE2, 0x00, 0xF0, 0x00]);
pmt.push(STREAM_TYPE_PES_PRIVATE);
pmt.extend_from_slice(&[0xE3, 0x00]);
let esi_len = descriptors.len() as u16;
pmt.push(0xF0 | ((esi_len >> 8) & 0x0F) as u8);
pmt.push((esi_len & 0xFF) as u8);
pmt.extend_from_slice(&descriptors);
pmt.extend_from_slice(&[0u8; 4]);
let (_, audio) = parse_pmt_streams(&pmt).expect("parse");
assert_eq!(audio.len(), 1);
assert_eq!(audio[0].kind, AudioCodecKind::Eac3);
}
#[test]
fn extract_ac3_frames_from_synthetic_ts_yields_passthrough_track() {
let frame = synth_ac3_frame_stereo_48k_128k();
let mut es = frame.clone();
es.extend_from_slice(&frame);
let buf = build_ts_with_audio(STREAM_TYPE_AC3, &[], 0x300, &es);
let d = demux_ts(&buf).expect("demux");
let audio = d.audio.expect("AC-3 audio surfaced");
assert_eq!(audio.codec, "ac3");
assert_eq!(audio.channels, 2);
assert_eq!(audio.sample_rate, 48_000);
assert_eq!(audio.timescale, 48_000);
assert_eq!(audio.codec_private.len(), 3);
assert!(
audio.samples.len() >= 1,
"at least one AC-3 frame extracted"
);
assert_eq!(
&audio.samples[0][..2],
&[0x0B, 0x77],
"AC-3 frame begins with 0x0B77 sync word verbatim"
);
assert!(
audio.durations.iter().all(|&d| d == 1536),
"AC-3 frames are 1536 samples each"
);
}
#[test]
fn extract_eac3_frames_from_synthetic_ts_yields_passthrough_track() {
let frame = synth_eac3_frame_stereo_48k_192bytes();
let mut es = frame.clone();
es.extend_from_slice(&frame);
let buf = build_ts_with_audio(STREAM_TYPE_EAC3, &[], 0x300, &es);
let d = demux_ts(&buf).expect("demux");
let audio = d.audio.expect("E-AC-3 audio surfaced");
assert_eq!(audio.codec, "eac3");
assert_eq!(audio.channels, 2);
assert_eq!(audio.sample_rate, 48_000);
assert_eq!(audio.codec_private.len(), 5);
assert!(!audio.samples.is_empty());
assert_eq!(
&audio.samples[0][..2],
&[0x0B, 0x77],
"E-AC-3 frame begins with 0x0B77 sync word verbatim"
);
assert!(audio.durations.iter().all(|&d| d == 1536));
}
#[test]
fn extract_ac3_via_pes_private_with_dvb_registration() {
let frame = synth_ac3_frame_stereo_48k_128k();
let descriptors: [u8; 6] = [DESC_TAG_REGISTRATION, 4, b'A', b'C', b'-', b'3'];
let buf = build_ts_with_audio(STREAM_TYPE_PES_PRIVATE, &descriptors, 0x300, &frame);
let d = demux_ts(&buf).expect("demux");
let audio = d.audio.expect("AC-3 audio via DVB registration surfaced");
assert_eq!(audio.codec, "ac3");
assert_eq!(&audio.samples[0][..2], &[0x0B, 0x77]);
}
#[test]
fn dac3_body_synthesized_from_first_ts_frame_matches_sync_header() {
let frame = synth_ac3_frame_stereo_48k_128k();
let buf = build_ts_with_audio(STREAM_TYPE_AC3, &[], 0x300, &frame);
let d = demux_ts(&buf).expect("demux");
let audio = d.audio.expect("AC-3 audio");
let parsed = match crate::ac3_sync::parse_sync_info(&frame).unwrap() {
crate::ac3_sync::SyncInfo::Ac3(s) => s,
_ => panic!("expected AC-3"),
};
let expected = crate::mux::dac3_body_from_sync(&parsed);
assert_eq!(
audio.codec_private,
expected.to_vec(),
"TS-extracted dac3 must match the canonical helper"
);
}