use bytes::{BufMut, Bytes, BytesMut};
use crate::codec::av1::leb128::read_leb128;
use crate::codec::av1::obu::{
OBU_HAS_SIZE_BIT, OBU_TYPE_MASK, OBU_TYPE_TEMPORAL_DELIMITER, OBU_TYPE_TILE_LIST,
};
use crate::packetizer::Depacketizer;
use shared::error::{Error, Result};
const AV1_Z_MASK: u8 = 0b1000_0000;
const AV1_Y_MASK: u8 = 0b0100_0000;
const AV1_W_MASK: u8 = 0b0011_0000;
const AV1_N_MASK: u8 = 0b0000_1000;
#[derive(Default, Debug, Clone)]
pub struct Av1Depacketizer {
buffer: BytesMut,
pub z: bool,
pub y: bool,
pub n: bool,
}
impl Av1Depacketizer {
pub fn new() -> Self {
Self::default()
}
}
impl Depacketizer for Av1Depacketizer {
fn depacketize(&mut self, payload: &Bytes) -> Result<Bytes> {
if payload.len() <= 1 {
return Err(Error::ErrShortPacket);
}
let obu_z = (payload[0] & AV1_Z_MASK) != 0;
let obu_y = (payload[0] & AV1_Y_MASK) != 0;
let obu_count = (payload[0] & AV1_W_MASK) >> 4;
let obu_n = (payload[0] & AV1_N_MASK) != 0;
self.z = obu_z;
self.y = obu_y;
self.n = obu_n;
if obu_n {
self.buffer.clear();
}
if !obu_z && !self.buffer.is_empty() {
self.buffer.clear();
}
let mut result = BytesMut::new();
let mut offset = 1; let mut obu_offset = 0;
while offset < payload.len() {
let is_first = obu_offset == 0;
let is_last = obu_count != 0 && obu_offset == (obu_count - 1) as usize;
let (length_field, is_last) = if obu_count == 0 || !is_last {
let payload_slice = payload.slice(offset..);
let (len, n) = read_leb128(&payload_slice);
if n == 0 {
return Err(Error::ErrShortPacket);
}
offset += n;
let is_last_w0 = obu_count == 0 && offset + len as usize == payload.len();
(len as usize, is_last || is_last_w0)
} else {
(payload.len() - offset, true)
};
if offset + length_field > payload.len() {
return Err(Error::ErrShortPacket);
}
let obu_buffer = if is_first && obu_z {
if self.buffer.is_empty() {
if is_last {
break;
}
offset += length_field;
obu_offset += 1;
continue;
}
let mut combined = std::mem::take(&mut self.buffer);
combined.extend_from_slice(&payload[offset..offset + length_field]);
combined.freeze()
} else {
payload.slice(offset..offset + length_field)
};
offset += length_field;
if is_last && obu_y {
self.buffer = BytesMut::from(obu_buffer.as_ref());
break;
}
if obu_buffer.is_empty() {
if is_last {
break;
}
obu_offset += 1;
continue;
}
let obu_type = (obu_buffer[0] & OBU_TYPE_MASK) >> 3;
if obu_type == OBU_TYPE_TEMPORAL_DELIMITER || obu_type == OBU_TYPE_TILE_LIST {
if is_last {
break;
}
obu_offset += 1;
continue;
}
let has_size_field = (obu_buffer[0] & OBU_HAS_SIZE_BIT) != 0;
let has_extension = (obu_buffer[0] & 0x04) != 0;
let header_size = if has_extension { 2 } else { 1 };
if has_size_field {
let payload_slice = obu_buffer.slice(header_size..);
let (obu_size, leb_size) = read_leb128(&payload_slice);
let expected_size = header_size + leb_size + obu_size as usize;
if length_field != expected_size {
return Err(Error::ErrShortPacket);
}
result.extend_from_slice(&obu_buffer);
} else {
result.put_u8(obu_buffer[0] | OBU_HAS_SIZE_BIT);
if has_extension && obu_buffer.len() > 1 {
result.put_u8(obu_buffer[1]);
}
let payload_size = obu_buffer.len() - header_size;
write_leb128(&mut result, payload_size as u32);
if header_size < obu_buffer.len() {
result.extend_from_slice(&obu_buffer[header_size..]);
}
}
if is_last {
break;
}
obu_offset += 1;
}
if obu_count != 0 && obu_offset != (obu_count - 1) as usize && !self.y {
return Err(Error::ErrShortPacket);
}
Ok(result.freeze())
}
fn is_partition_head(&self, payload: &Bytes) -> bool {
if payload.is_empty() {
return false;
}
(payload[0] & AV1_Z_MASK) == 0
}
fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
marker
}
}
fn write_leb128(buf: &mut BytesMut, mut value: u32) {
loop {
let mut byte = (value & 0x7f) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
buf.put_u8(byte);
if value == 0 {
break;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_depacketizer_basic() {
let mut depacketizer = Av1Depacketizer::new();
let payload = Bytes::from(vec![
0x10, 0x30, 0x01, 0x02, 0x03, ]);
let result = depacketizer.depacketize(&payload).unwrap();
assert!(!result.is_empty());
assert_eq!(result[0] & OBU_HAS_SIZE_BIT, OBU_HAS_SIZE_BIT);
assert_eq!(result[1], 3);
assert_eq!(&result[2..], &[0x01, 0x02, 0x03]);
}
#[test]
fn test_depacketizer_with_w_zero() {
let mut depacketizer = Av1Depacketizer::new();
let payload = Bytes::from(vec![
0x00, 0x04, 0x30, 0x01, 0x02, 0x03, ]);
let result = depacketizer.depacketize(&payload).unwrap();
assert!(!result.is_empty());
assert_eq!(result[0] & OBU_HAS_SIZE_BIT, OBU_HAS_SIZE_BIT);
}
#[test]
fn test_is_partition_head() {
let depacketizer = Av1Depacketizer::new();
let payload = Bytes::from(vec![0x10, 0x30]);
assert!(depacketizer.is_partition_head(&payload));
let payload = Bytes::from(vec![0x90, 0x30]);
assert!(!depacketizer.is_partition_head(&payload));
}
#[test]
fn test_write_leb128() {
let mut buf = BytesMut::new();
write_leb128(&mut buf, 0);
assert_eq!(buf.as_ref(), &[0x00]);
buf.clear();
write_leb128(&mut buf, 127);
assert_eq!(buf.as_ref(), &[0x7f]);
buf.clear();
write_leb128(&mut buf, 128);
assert_eq!(buf.as_ref(), &[0x80, 0x01]);
buf.clear();
write_leb128(&mut buf, 16383);
assert_eq!(buf.as_ref(), &[0xff, 0x7f]);
}
#[test]
fn test_skip_temporal_delimiter() {
let mut depacketizer = Av1Depacketizer::new();
let payload = Bytes::from(vec![
0x10, 0x12, 0x00, ]);
let result = depacketizer.depacketize(&payload).unwrap();
assert!(result.is_empty());
}
}