Tidy Repacketizer interface and add more tests

The combine() method can be used to avoid manually managing a
RepacketizerState in the simplest use case, and cat_move now simply
calls cat internally, in a way that is easier to verify the safety of.
This commit is contained in:
Tad Hardesty
2016-02-25 18:02:19 -06:00
parent 3c6ce567f6
commit 6b1228288a
2 changed files with 43 additions and 22 deletions

View File

@@ -399,6 +399,15 @@ impl Repacketizer {
}
}
/// Shortcut to combine several smaller packets into one larger one.
pub fn combine(&mut self, input: &[&[u8]], output: &mut [u8]) -> Result<usize> {
let mut state = self.begin();
for &packet in input {
try!(state.cat(packet));
}
state.out(output)
}
/// Begin using the repacketizer.
pub fn begin<'rp, 'buf>(&'rp mut self) -> RepacketizerState<'rp, 'buf> {
unsafe { ffi::opus_repacketizer_init(self.ptr); }
@@ -412,6 +421,12 @@ impl Drop for Repacketizer {
}
}
// To understand why these lifetime bounds are needed, imagine that the
// repacketizer keeps an internal Vec<&'buf [u8]>, which is added to by cat()
// and accessed by get_nb_frames(), out(), and out_range(). To prove that these
// lifetime bounds are correct, a dummy implementation with the same signatures
// but a real Vec<&'buf [u8]> rather than unsafe blocks may be substituted.
/// An in-progress repacketization.
pub struct RepacketizerState<'rp, 'buf> {
rp: &'rp mut Repacketizer,
@@ -421,19 +436,17 @@ pub struct RepacketizerState<'rp, 'buf> {
impl<'rp, 'buf> RepacketizerState<'rp, 'buf> {
/// Add a packet to the current repacketizer state.
pub fn cat(&mut self, packet: &'buf [u8]) -> Result<()> {
unsafe { self.cat_priv(packet) }
let result = unsafe { ffi::opus_repacketizer_cat(self.rp.ptr,
packet.as_ptr(), packet.len() as c_int) };
check("opus_repacketizer_cat", result)
}
/// Add a packet to the current repacketizer state, moving it.
pub fn cat_move<'b2>(mut self, packet: &'b2 [u8]) -> Result<RepacketizerState<'rp, 'b2>> where 'buf: 'b2 {
try!(unsafe { self.cat_priv(packet) });
Ok(self)
}
unsafe fn cat_priv(&mut self, packet: &[u8]) -> Result<()> {
let result = ffi::opus_repacketizer_cat(self.rp.ptr,
packet.as_ptr(), packet.len() as c_int);
check("opus_repacketizer_cat", result)
#[inline]
pub fn cat_move<'b2>(self, packet: &'b2 [u8]) -> Result<RepacketizerState<'rp, 'b2>> where 'buf: 'b2 {
let mut shorter = self;
try!(shorter.cat(packet));
Ok(shorter)
}
/// Get the total number of frames contained in packet data submitted so

View File

@@ -68,30 +68,38 @@ fn encode_bad_buffer() {
#[test]
fn repacketizer() {
let mut rp = opus::Repacketizer::new().unwrap();
let mut out = [0; 256];
for _ in 0..2 {
let packets = &[
&[249, 255, 254, 255, 254][..],
&[248, 255, 254][..],
];
let packet1 = [249, 255, 254, 255, 254];
let packet2 = [248, 255, 254];
let mut state = rp.begin();
for &packet in packets {
state.cat(packet).unwrap();
}
let mut out = [0; 256];
state.cat(&packet1).unwrap();
state.cat(&packet2).unwrap();
let len = state.out(&mut out).unwrap();
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
}
{
for _ in 0..2 {
let packet = [248, 255, 254];
let state = rp.begin().cat_move(&packet).unwrap();
let packet = [249, 255, 254, 255, 254];
let state = state.cat_move(&packet).unwrap();
let mut out = [0; 256];
let len = {state}.out(&mut out).unwrap();
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
}
for _ in 0..2 {
let len = rp.combine(&[
&[249, 255, 254, 255, 254],
&[248, 255, 254],
], &mut out).unwrap();
assert_eq!(&out[..len], &[251, 3, 255, 254, 255, 254, 255, 254]);
}
for _ in 0..2 {
let len = rp.begin()
.cat_move(&[248, 255, 254]).unwrap()
.cat_move(&[248, 71, 71]).unwrap()
.out(&mut out).unwrap();
assert_eq!(&out[..len], &[249, 255, 254, 71, 71]);
}
}