use crate::Error;
pub fn samples_per_frame(toc: u8, fs: i32) -> i32 {
if toc & 0x80 != 0 {
let a = ((toc >> 3) & 0x3) as i32;
(fs << a) / 400
} else if toc & 0x60 == 0x60 {
if toc & 0x08 != 0 { fs / 50 } else { fs / 100 }
} else {
let a = ((toc >> 3) & 0x3) as i32;
if a == 3 {
fs * 60 / 1000
} else {
(fs << a) / 100
}
}
}
pub fn nb_frames(packet: &[u8]) -> Result<i32, Error> {
if packet.is_empty() {
return Err(Error::BadArg("bad arg"));
}
match packet[0] & 0x3 {
0 => Ok(1),
3 => {
if packet.len() < 2 {
Err(Error::InvalidPacket("invalid packet"))
} else {
Ok((packet[1] & 0x3f) as i32)
}
}
_ => Ok(2),
}
}
fn parse_size(data: &[u8]) -> (i32, i32) {
if data.is_empty() {
(-1, -1)
} else if data[0] < 252 {
(1, data[0] as i32)
} else if data.len() < 2 {
(-1, -1)
} else {
(2, data[1] as i32 * 4 + data[0] as i32)
}
}
#[cfg(test)]
fn encode_size(size: i32, out: &mut Vec<u8>) {
if size < 252 {
out.push(size as u8);
} else {
let b0 = 252 + (size & 0x3);
out.push(b0 as u8);
out.push(((size - b0) >> 2) as u8);
}
}
const MAX_FRAMES: usize = 48;
const TOO_SMALL: Error = Error::BufferTooSmall("output buffer too small for packet");
struct Cursor<'a> {
buf: &'a mut [u8],
pos: usize,
}
impl Cursor<'_> {
fn put(&mut self, b: u8) -> Result<(), Error> {
*self.buf.get_mut(self.pos).ok_or(TOO_SMALL)? = b;
self.pos += 1;
Ok(())
}
fn put_all(&mut self, src: &[u8]) -> Result<(), Error> {
let end = self.pos + src.len();
self.buf
.get_mut(self.pos..end)
.ok_or(TOO_SMALL)?
.copy_from_slice(src);
self.pos = end;
Ok(())
}
fn put_size(&mut self, size: usize) -> Result<(), Error> {
if size < 252 {
self.put(size as u8)
} else {
let b0 = 252 + (size & 0x3);
self.put(b0 as u8)?;
self.put(((size - b0) >> 2) as u8)
}
}
}
#[derive(Clone, Copy)]
struct SizeList {
v: [i32; MAX_FRAMES],
n: usize,
}
impl SizeList {
const fn new() -> Self {
Self {
v: [0; MAX_FRAMES],
n: 0,
}
}
fn push(&mut self, size: i32) -> Result<(), Error> {
*self
.v
.get_mut(self.n)
.ok_or(Error::InvalidPacket("invalid packet"))? = size;
self.n += 1;
Ok(())
}
fn clear(&mut self) {
self.n = 0;
}
fn as_slice(&self) -> &[i32] {
&self.v[..self.n]
}
}
pub(crate) struct Frames {
pub(crate) toc: u8,
pub(crate) count: usize,
pub(crate) ranges: [(usize, usize); MAX_FRAMES],
pub(crate) end: usize,
}
impl Frames {
pub(crate) fn ranges(&self) -> &[(usize, usize)] {
&self.ranges[..self.count]
}
}
#[allow(clippy::type_complexity)]
pub fn parse_packet(
data: &[u8],
self_delimited: bool,
) -> Result<(u8, Vec<(usize, usize)>, usize), Error> {
let f = parse_frames(data, self_delimited)?;
Ok((f.toc, f.ranges().to_vec(), f.end))
}
pub(crate) fn parse_frames(data: &[u8], self_delimited: bool) -> Result<Frames, Error> {
if data.is_empty() {
return Err(Error::InvalidPacket("invalid packet"));
}
let framesize = samples_per_frame(data[0], 48000);
let toc = data[0];
let mut pos = 1usize; let mut len = data.len() as i32 - 1;
let mut cbr = false;
let mut last_size = len;
let mut sizes = SizeList::new();
let count: usize = match toc & 0x3 {
0 => 1,
1 => {
cbr = true;
if !self_delimited {
if len & 1 != 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
last_size = len / 2;
sizes.push(last_size)?;
}
2
}
2 => {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
sizes.push(sz)?;
last_size = len - sz;
2
}
_ => {
if len < 1 {
return Err(Error::InvalidPacket("invalid packet"));
}
let ch = data[pos];
pos += 1;
len -= 1;
let count = (ch & 0x3f) as usize;
if count == 0 || framesize * count as i32 > 5760 {
return Err(Error::InvalidPacket("invalid packet"));
}
if ch & 0x40 != 0 {
loop {
if len <= 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
let p = data[pos];
pos += 1;
len -= 1;
let tmp = if p == 255 { 254 } else { p as i32 };
len -= tmp;
if p != 255 {
break;
}
}
}
if len < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
cbr = ch & 0x80 == 0;
if !cbr {
last_size = len;
for _ in 0..count - 1 {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
sizes.push(sz)?;
last_size -= bytes + sz;
}
if last_size < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
} else if !self_delimited {
last_size = len / count as i32;
if last_size * count as i32 != len {
return Err(Error::InvalidPacket("invalid packet"));
}
for _ in 0..count - 1 {
sizes.push(last_size)?;
}
}
count
}
};
if self_delimited {
let (bytes, sz) = parse_size(&data[pos..]);
if bytes < 0 {
return Err(Error::InvalidPacket("invalid packet"));
}
len -= bytes;
if sz < 0 || sz > len {
return Err(Error::InvalidPacket("invalid packet"));
}
pos += bytes as usize;
if cbr {
if sz * count as i32 > len {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.clear();
for _ in 0..count - 1 {
sizes.push(sz)?;
}
sizes.push(sz)?;
} else {
if bytes + sz > last_size {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.push(sz)?;
}
} else {
if last_size > 1275 {
return Err(Error::InvalidPacket("invalid packet"));
}
sizes.push(last_size)?;
}
let mut ranges = [(0usize, 0usize); MAX_FRAMES];
let mut off = pos;
for (slot, &s) in ranges.iter_mut().zip(sizes.as_slice()) {
if off + s as usize > data.len() {
return Err(Error::InvalidPacket("invalid packet"));
}
*slot = (off, s as usize);
off += s as usize;
}
Ok(Frames {
toc,
count: sizes.as_slice().len(),
ranges,
end: off,
})
}
#[derive(Default)]
pub struct Repacketizer {
toc: u8,
framesize: i32,
data: Vec<u8>,
frames: Vec<(usize, usize)>,
}
impl Repacketizer {
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.data.clear();
self.frames.clear();
}
pub fn nb_frames(&self) -> usize {
self.frames.len()
}
fn frame(&self, i: usize) -> &[u8] {
let (start, len) = self.frames[i];
&self.data[start..start + len]
}
pub fn cat(&mut self, data: &[u8]) -> Result<(), Error> {
self.cat_impl(data, false)
}
fn cat_impl(&mut self, data: &[u8], self_delimited: bool) -> Result<(), Error> {
if data.is_empty() {
return Err(Error::InvalidPacket("invalid packet"));
}
if self.frames.is_empty() {
self.toc = data[0];
self.framesize = samples_per_frame(data[0], 8000);
} else if self.toc & 0xfc != data[0] & 0xfc {
return Err(Error::InvalidPacket("toc mismatch"));
}
let curr = nb_frames(data)?;
if curr < 1 {
return Err(Error::InvalidPacket("invalid packet"));
}
if (curr as usize + self.frames.len()) as i32 * self.framesize > 960 {
return Err(Error::InvalidPacket("packet exceeds 120 ms"));
}
let parsed = parse_frames(data, self_delimited)?;
for &(o, l) in parsed.ranges() {
self.frames.push((self.data.len(), l));
self.data.extend_from_slice(&data[o..o + l]);
}
Ok(())
}
pub fn out_range(&self, begin: usize, end: usize) -> Result<Vec<u8>, Error> {
self.out_vec(begin, end, None, false)
}
pub fn out(&self) -> Result<Vec<u8>, Error> {
self.out_vec(0, self.frames.len(), None, false)
}
pub fn out_into(&self, out: &mut [u8]) -> Result<usize, Error> {
self.write_range(0, self.frames.len(), None, false, out)
}
pub fn out_range_into(&self, begin: usize, end: usize, out: &mut [u8]) -> Result<usize, Error> {
self.write_range(begin, end, None, false, out)
}
pub(crate) fn out_padded_into(&self, pad_to: usize, out: &mut [u8]) -> Result<usize, Error> {
self.write_range(0, self.frames.len(), Some(pad_to), false, out)
}
pub fn out_self_delimited(&self) -> Result<Vec<u8>, Error> {
self.out_vec(0, self.frames.len(), None, true)
}
fn out_vec(
&self,
begin: usize,
end: usize,
pad_to: Option<usize>,
self_delimited: bool,
) -> Result<Vec<u8>, Error> {
if begin >= end || end > self.frames.len() {
return Err(Error::BadArg("bad arg"));
}
let payload: usize = self.frames[begin..end].iter().map(|&(_, l)| l).sum();
let bound = 2 + 2 * (end - begin + 1) + payload + pad_to.map_or(0, |n| n + n / 255 + 1);
let mut out = vec![0u8; bound];
let n = self.write_range(begin, end, pad_to, self_delimited, &mut out)?;
out.truncate(n);
Ok(out)
}
fn write_range(
&self,
begin: usize,
end: usize,
pad_to: Option<usize>,
self_delimited: bool,
out: &mut [u8],
) -> Result<usize, Error> {
if begin >= end || end > self.frames.len() {
return Err(Error::BadArg("bad arg"));
}
let count = end - begin;
let lens = &self.frames[begin..end];
let len = |i: usize| lens[i].1;
let mut w = Cursor { buf: out, pos: 0 };
if count > 2 || pad_to.is_some() {
let vbr = lens.iter().any(|&(_, l)| l != len(0));
w.put((self.toc & 0xfc) | 0x3)?;
w.put(count as u8 | if vbr { 0x80 } else { 0 })?;
let mut tot = 2usize;
if vbr {
for &(_, l) in &lens[..count - 1] {
tot += 1 + usize::from(l >= 252) + l;
}
tot += len(count - 1);
} else {
tot += count * len(0);
}
let pad_amount = pad_to.map_or(0, |n| n.saturating_sub(tot));
if pad_amount != 0 {
w.buf[1] |= 0x40; let nb_255s = (pad_amount - 1) / 255;
for _ in 0..nb_255s {
w.put(255)?;
}
w.put((pad_amount - 255 * nb_255s - 1) as u8)?;
}
if vbr {
for &(_, l) in &lens[..count - 1] {
w.put_size(l)?;
}
}
} else if count == 1 {
w.put(self.toc & 0xfc)?; } else if len(0) == len(1) {
w.put((self.toc & 0xfc) | 0x1)?; } else {
w.put((self.toc & 0xfc) | 0x2)?; w.put_size(len(0))?;
}
if self_delimited {
w.put_size(len(count - 1))?;
}
for i in begin..end {
w.put_all(self.frame(i))?;
}
if let Some(n) = pad_to {
while w.pos < n {
w.put(0)?;
}
}
Ok(w.pos)
}
}
pub fn pad_packet(packet: &mut Vec<u8>, new_len: usize) -> Result<(), Error> {
if packet.is_empty() {
return Err(Error::BadArg("bad arg"));
}
if packet.len() == new_len {
return Ok(());
}
if packet.len() > new_len {
return Err(Error::BadArg("bad arg"));
}
let mut rp = Repacketizer::new();
rp.cat(packet)?;
let padded = rp.out_vec(0, rp.nb_frames(), Some(new_len), false)?;
*packet = padded;
Ok(())
}
pub fn unpad_packet(packet: &[u8]) -> Result<Vec<u8>, Error> {
if packet.is_empty() {
return Err(Error::BadArg("bad arg"));
}
let mut rp = Repacketizer::new();
rp.cat(packet)?;
rp.out()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn split_merge_roundtrip() {
let toc = 12u8 << 3;
let mut pkt = vec![toc | 0x3, 3 | 0x80]; let f0 = vec![0xAAu8; 3];
let f1 = vec![0xBBu8; 5];
let f2 = vec![0xCCu8; 4];
encode_size(3, &mut pkt);
encode_size(5, &mut pkt);
pkt.extend_from_slice(&f0);
pkt.extend_from_slice(&f1);
pkt.extend_from_slice(&f2);
let mut rp = Repacketizer::new();
rp.cat(&pkt).unwrap();
assert_eq!(rp.nb_frames(), 3);
assert_eq!(rp.out().unwrap(), pkt);
let s0 = rp.out_range(0, 1).unwrap();
assert_eq!(s0[0] & 0x3, 0);
assert_eq!(&s0[1..], &f0[..]);
let s1 = rp.out_range(1, 2).unwrap();
assert_eq!(&s1[1..], &f1[..]);
}
#[test]
fn pad_unpad_identity() {
let toc = 8u8 << 3; let mut pkt = vec![toc];
pkt.extend_from_slice(&[1, 2, 3, 4, 5]);
let orig = pkt.clone();
pad_packet(&mut pkt, orig.len() + 10).unwrap();
assert_eq!(pkt.len(), orig.len() + 10);
let back = unpad_packet(&pkt).unwrap();
let (_t, f, _) = parse_packet(&back, false).unwrap();
assert_eq!(&back[f[0].0..f[0].0 + f[0].1], &orig[1..]);
}
#[test]
fn cbr_merge_code1() {
let toc = 8u8 << 3;
let p = vec![toc, 9, 9, 9]; let mut rp = Repacketizer::new();
rp.cat(&p).unwrap();
rp.cat(&p).unwrap();
let out = rp.out().unwrap();
assert_eq!(out[0] & 0x3, 1); assert_eq!(rp.nb_frames(), 2);
}
}
#[cfg(test)]
mod sd_tests {
use super::*;
#[test]
fn self_delimited_roundtrip() {
let toc = 12u8 << 3;
let mut rp = Repacketizer::new();
let mut p = vec![toc | 0x3, 3 | 0x80];
encode_size(3, &mut p);
encode_size(5, &mut p);
p.extend_from_slice(&[1u8; 3]);
p.extend_from_slice(&[2u8; 5]);
p.extend_from_slice(&[3u8; 4]);
rp.cat(&p).unwrap();
let sd = rp.out_self_delimited().unwrap();
let mut stream = sd.clone();
stream.extend_from_slice(&[0xEE; 7]);
let (t, frames, off) = parse_packet(&stream, true).unwrap();
assert_eq!(t, toc | 0x3);
assert_eq!(frames.len(), 3);
assert_eq!(&stream[frames[0].0..frames[0].0 + frames[0].1], &[1, 1, 1]);
assert_eq!(
&stream[frames[2].0..frames[2].0 + frames[2].1],
&[3, 3, 3, 3]
);
assert_eq!(off, sd.len()); }
}