#![allow(dead_code)]
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct VectorSpec {
pub bit: String,
pub sample_rate: u32,
pub channels: usize,
}
pub fn vectors_dir() -> PathBuf {
if let Ok(path) = std::env::var("OPUS_TESTVECTORS_DIR") {
return PathBuf::from(path);
}
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../testdata/opus_testvectors")
.canonicalize()
.unwrap_or_else(|_| PathBuf::from("testdata/opus_testvectors"))
}
pub fn load_vector_spec(vector_name: &str) -> io::Result<VectorSpec> {
let manifest = fs::read_to_string(vectors_dir().join("vectors.txt"))?;
for line in manifest.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let mut fields = line.split_whitespace();
let name = fields.next().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidData,
"missing vector name in manifest",
)
})?;
if name != vector_name {
continue;
}
let bit = fields
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing .bit path"))?
.to_string();
let _dec = fields
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing .dec path"))?;
let sample_rate = fields
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing sample rate"))?
.parse::<u32>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
let channels = fields
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "missing channel count"))?
.parse::<usize>()
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
return Ok(VectorSpec {
bit,
sample_rate,
channels,
});
}
Err(io::Error::new(
io::ErrorKind::NotFound,
format!("vector not found in manifest: {vector_name}"),
))
}
pub fn load_packets(vector_name: &str) -> io::Result<Vec<Vec<u8>>> {
let spec = load_vector_spec(vector_name)?;
let packets = read_opus_demo_stream(&vectors_dir().join(spec.bit))?;
Ok(packets.into_iter().flatten().collect())
}
pub fn read_opus_demo_stream(path: &Path) -> io::Result<Vec<Option<Vec<u8>>>> {
let mut file = fs::File::open(path)?;
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
let mut packets = Vec::new();
let mut index = 0usize;
while index < bytes.len() {
if index + 4 > bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"truncated packet_len",
));
}
let packet_len = u32::from_be_bytes([
bytes[index],
bytes[index + 1],
bytes[index + 2],
bytes[index + 3],
]) as usize;
index += 4;
if index + 4 > bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"truncated final_range",
));
}
let _expected_final_range = u32::from_be_bytes([
bytes[index],
bytes[index + 1],
bytes[index + 2],
bytes[index + 3],
]);
index += 4;
if index + packet_len > bytes.len() {
return Err(io::Error::new(
io::ErrorKind::UnexpectedEof,
"truncated packet",
));
}
let packet = if packet_len == 0 {
None
} else {
Some(bytes[index..index + packet_len].to_vec())
};
index += packet_len;
packets.push(packet);
}
Ok(packets)
}
pub fn build_multistream_packet(sub_packets: &[&[u8]]) -> Vec<u8> {
let mut packet = Vec::new();
for (stream_idx, sub_packet) in sub_packets.iter().enumerate() {
if stream_idx + 1 != sub_packets.len() {
packet.extend(encode_self_delimited_size(sub_packet.len()));
}
packet.extend_from_slice(sub_packet);
}
packet
}
fn encode_self_delimited_size(len: usize) -> Vec<u8> {
if len < 252 {
vec![u8::try_from(len).expect("short self-delimited size fits in u8")]
} else {
let remainder = len - 252;
vec![
u8::try_from(252 + (remainder & 0x03))
.expect("self-delimited prefix first byte fits in u8"),
u8::try_from(remainder >> 2).expect("self-delimited prefix second byte fits in u8"),
]
}
}