When compressing and decompressing a byte vector using this library, the round-trip works correctly when bit_depth == 8, but for other bit depths the decompressed output does not match the original input.
My reproducible example is similar to the procedure you can see in graec.c.
Minimal Example
use libaec_sys::*
struct Stream(aec_stream);
impl Stream {
fn new(bits_per_sample: u32, block_size: u32, rsi: u32, flags: u32) -> Self {
let mut raw: aec_stream = unsafe { std::mem::zeroed() };
raw.bits_per_sample = bits_per_sample;
raw.block_size = block_size;
raw.rsi = rsi;
raw.flags = flags;
Self(raw)
}
fn total_in(&self) -> usize {
self.0.total_in
}
fn total_out(&self) -> usize {
self.0.total_out
}
fn encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(), &'static str> {
self.0.next_in = input.as_ptr();
self.0.avail_in = input.len();
self.0.next_out = output.as_mut_ptr();
self.0.avail_out = output.len();
let result = unsafe { aec_encode_init(&mut self.0) };
if result as u32 != AEC_OK {
return Err("aec_encode_init() failed");
}
// Process until all input consumed and output space remains
while self.0.avail_in > 0 || self.0.avail_out == 0 {
let result = unsafe { aec_encode(&mut self.0, AEC_NO_FLUSH as i32) };
if result as u32 != AEC_OK {
return Err("aec_encode() failed");
}
if self.0.avail_out == 0 {
return Err("output buffer too small");
}
}
// Final flush
let result = unsafe { aec_encode(&mut self.0, AEC_FLUSH as i32) };
if result as u32 != AEC_OK {
return Err("aec_encode() flush failed");
}
let result = unsafe { aec_encode_end(&mut self.0) };
if result as u32 != AEC_OK {
return Err("aec_encode_end() failed");
}
Ok(())
}
fn decode(&mut self, input: &[u8], output: &mut [u8]) -> Result<(), &'static str> {
self.0.next_in = input.as_ptr();
self.0.avail_in = input.len();
self.0.next_out = output.as_mut_ptr();
self.0.avail_out = output.len();
let result = unsafe { aec_decode_init(&mut self.0) };
if result as u32 != AEC_OK {
return Err("aec_decode_init() failed");
}
while self.0.avail_in > 0 || self.0.avail_out == 0 {
let result = unsafe { aec_decode(&mut self.0, AEC_NO_FLUSH as i32) };
if result as u32 != AEC_OK {
return Err("aec_decode() failed");
}
if self.0.avail_out == 0 {
// Caller must handle reallocating or extending output buffer
return Err("output buffer too small");
}
}
let result = unsafe { aec_decode_end(&mut self.0) };
if result as u32 != AEC_OK {
return Err("aec_decode_end() failed");
}
Ok(())
}
}
#[test]
fn roundtrip_test() {
let n = 3000 * 4096; // number of bytes
// Generate vector with numbers 1..=100 repeating
let bytes: Vec<u8> = (0..n)
.map(|i| ((i % 100) + 1) as u8)
.collect();
let mut codec = Stream::new(12, 32, 128, 0);
// COMPRESS
let mut encoded = vec![0; bytes.len() * 67 / 64 + 256]; // Maximum output size according to specifications
let result = codec.encode(&bytes, &mut encoded);
assert!(result.is_ok());
let encoded = &encoded[..codec.total_out()];
// DECOMPRESS
let mut decoded = vec![0; bytes.len() * 4];
let result = codec.decode(&encoded, &mut decoded);
assert!(result.is_ok());
let decoded = &decoded[..codec.total_out()];
assert_eq!(bytes, decoded)
}
Environment
- Rust version: 1.89.0
- libaec-sys version: 0.1.2
When compressing and decompressing a byte vector using this library, the round-trip works correctly when
bit_depth == 8, but for other bit depths the decompressed output does not match the original input.My reproducible example is similar to the procedure you can see in graec.c.
Minimal Example
Environment