use broadcast_common::{Package, Parse, Serialize, Unpackage};
use bytes::Bytes;
use transmux::media::{CmafMux, Fmp4Demux};
use transmux::pipeline::CodecConfig;
use transmux::vvc_config::{VvcConfigurationBox, VvcDecoderConfigurationRecord, VvcNalUnitType};
const FIXTURE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../fixtures/mp4/frag/vvc.frag.mp4"
);
fn read_fixture() -> Vec<u8> {
std::fs::read(FIXTURE).expect("read vvc.frag.mp4 fixture")
}
fn find_box_full<'a>(data: &'a [u8], four_cc: &[u8; 4]) -> Option<&'a [u8]> {
const CONTAINERS: &[&[u8; 4]] = &[b"moov", b"trak", b"mdia", b"minf", b"stbl"];
let mut off = 0usize;
while off + 8 <= data.len() {
let size =
u32::from_be_bytes([data[off], data[off + 1], data[off + 2], data[off + 3]]) as usize;
if size < 8 || off + size > data.len() {
break;
}
let ty: &[u8; 4] = data[off + 4..off + 8].try_into().unwrap();
if ty == four_cc {
return Some(&data[off..off + size]);
}
if CONTAINERS.contains(&ty) {
if let Some(found) = find_box_full(&data[off + 8..off + size], four_cc) {
return Some(found);
}
} else if ty == b"stsd" {
if let Some(found) = find_box_full(&data[off + 16..off + size], four_cc) {
return Some(found);
}
} else if ty == b"vvc1" || ty == b"vvi1" {
if let Some(found) = find_box_full(&data[off + 8 + 78..off + size], four_cc) {
return Some(found);
}
}
off += size;
}
None
}
fn oracle_vvcc_body(mp4: &[u8]) -> Vec<u8> {
let vvcc = find_box_full(mp4, b"vvcC").expect("vvcC box in fixture");
vvcc[8..].to_vec()
}
#[test]
fn vvc_demux_yields_vvc_config_byte_exact() {
let mp4 = read_fixture();
let oracle = oracle_vvcc_body(&mp4);
let mut demux = Fmp4Demux::new();
let media = demux.unpackage(&mp4).expect("demux vvc fixture");
assert!(!media.tracks.is_empty(), "expected at least one track");
let CodecConfig::Vvc { config, .. } = media.tracks[0].config() else {
panic!(
"track 0 is not CodecConfig::Vvc: {:?}",
media.tracks[0].config()
);
};
let full = config.to_bytes();
assert_eq!(&full[4..8], b"vvcC");
assert_eq!(
&full[8..],
&oracle[..],
"reconstructed vvcC body must be byte-identical to the source"
);
}
#[test]
fn vvc_dimensions_from_sps() {
let mp4 = read_fixture();
let mut demux = Fmp4Demux::new();
let media = demux.unpackage(&mp4).expect("demux");
let track = &media.tracks[0];
let CodecConfig::Vvc {
config,
width,
height,
} = track.config()
else {
panic!("expected Vvc");
};
assert_eq!((*width, *height), (320, 240));
let dims = config
.config
.dimensions()
.expect("SPS present + decodable in the vvcC array");
assert_eq!(dims, (320, 240));
}
#[test]
fn vvc_sample_round_trip_through_cmaf() {
let mp4 = read_fixture();
let mut demux = Fmp4Demux::new();
let media = demux.unpackage(&mp4).expect("demux");
let orig_samples: Vec<Bytes> = media.tracks[0]
.samples
.iter()
.map(|s| s.data.clone())
.collect();
assert!(!orig_samples.is_empty(), "expected coded samples");
let mut mux = CmafMux::default();
let remuxed = mux.package(&media).expect("mux back to CMAF");
let mut demux2 = Fmp4Demux::new();
let media2 = demux2.unpackage(&remuxed).expect("re-demux");
let round_samples: Vec<Bytes> = media2.tracks[0]
.samples
.iter()
.map(|s| s.data.clone())
.collect();
assert_eq!(
round_samples.len(),
orig_samples.len(),
"sample count must match"
);
assert_eq!(
round_samples, orig_samples,
"VVC coded sample bytes must be byte-identical"
);
}
#[test]
fn vvc_output_init_segment_carries_vvc1_vvcc() {
let mp4 = read_fixture();
let oracle = oracle_vvcc_body(&mp4);
let mut demux = Fmp4Demux::new();
let media = demux.unpackage(&mp4).expect("demux");
let mut mux = CmafMux::default();
let remuxed = mux.package(&media).expect("mux");
let vvc1 = find_box_full(&remuxed, b"vvc1").expect("vvc1 in muxed init segment");
assert_eq!(&vvc1[4..8], b"vvc1");
let vvcc = find_box_full(&remuxed, b"vvcC").expect("vvcC in muxed init segment");
assert_eq!(
&vvcc[8..],
&oracle[..],
"muxed vvcC must equal the source vvcC"
);
}
#[test]
fn vvc_record_round_trip_and_mutation() {
let mp4 = read_fixture();
let oracle = oracle_vvcc_body(&mp4);
let boxed = VvcConfigurationBox::parse_body(&oracle).expect("parse vvcC body");
let full = boxed.to_bytes();
assert_eq!(&full[8..], &oracle[..], "vvcC box body round-trip");
let record = VvcDecoderConfigurationRecord::parse(&oracle[4..]).expect("parse record");
let reser = record.to_bytes();
assert_eq!(&reser[..], &oracle[4..], "record round-trip byte-identical");
assert!(
record
.arrays
.iter()
.any(|a| a.kind() == VvcNalUnitType::Sps)
);
assert!(
record
.arrays
.iter()
.any(|a| a.kind() == VvcNalUnitType::Pps)
);
let mut mutated = record.clone();
mutated.max_picture_width = 1920;
let mutated_bytes = mutated.to_bytes();
assert_ne!(
mutated_bytes, reser,
"mutating a decoded field must change the serialized record"
);
let reparsed = VvcDecoderConfigurationRecord::parse(&mutated_bytes).expect("reparse mutated");
assert_eq!(reparsed.max_picture_width, 1920);
assert_eq!(reparsed.arrays.len(), record.arrays.len());
}
#[test]
fn vvc_rfc6381_smoke() {
let mp4 = read_fixture();
let oracle = oracle_vvcc_body(&mp4);
let record = VvcDecoderConfigurationRecord::parse(&oracle[4..]).unwrap();
let s = record.rfc6381();
eprintln!("RFC6381 = {s}");
assert!(s.starts_with("vvc1."), "got {s}");
}