#[cfg(test)]
mod vp9_test;
use crate::{
error::{Error, Result},
packetizer::{Depacketizer, Payloader},
};
use bytes::{Buf, BufMut, Bytes, BytesMut};
use std::fmt;
use std::sync::Arc;
const VP9HEADER_SIZE: usize = 3;
const MAX_SPATIAL_LAYERS: u8 = 5;
const MAX_VP9REF_PICS: usize = 3;
pub type InitialPictureIDFn = Arc<dyn (Fn() -> u16) + Send + Sync>;
#[derive(Default, Clone)]
pub struct Vp9Payloader {
picture_id: u16,
initialized: bool,
pub initial_picture_id_fn: Option<InitialPictureIDFn>,
}
impl fmt::Debug for Vp9Payloader {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Vp9Payloader")
.field("picture_id", &self.picture_id)
.field("initialized", &self.initialized)
.finish()
}
}
impl Payloader for Vp9Payloader {
fn payload(&mut self, mtu: usize, payload: &Bytes) -> Result<Vec<Bytes>> {
if payload.is_empty() || mtu == 0 {
return Ok(vec![]);
}
if !self.initialized {
if self.initial_picture_id_fn.is_none() {
self.initial_picture_id_fn =
Some(Arc::new(|| -> u16 { rand::random::<u16>() & 0x7FFF }));
}
self.picture_id = if let Some(f) = &self.initial_picture_id_fn {
f()
} else {
0
};
self.initialized = true;
}
let max_fragment_size = mtu as isize - VP9HEADER_SIZE as isize;
let mut payloads = vec![];
let mut payload_data_remaining = payload.len();
let mut payload_data_index = 0;
if std::cmp::min(max_fragment_size, payload_data_remaining as isize) <= 0 {
return Ok(vec![]);
}
while payload_data_remaining > 0 {
let current_fragment_size =
std::cmp::min(max_fragment_size as usize, payload_data_remaining);
let mut out = BytesMut::with_capacity(VP9HEADER_SIZE + current_fragment_size);
let mut buf = vec![0u8; VP9HEADER_SIZE];
buf[0] = 0x90; if payload_data_index == 0 {
buf[0] |= 0x08; }
if payload_data_remaining == current_fragment_size {
buf[0] |= 0x04; }
buf[1] = (self.picture_id >> 8) as u8 | 0x80;
buf[2] = (self.picture_id & 0xFF) as u8;
out.put(&buf[..]);
out.put(
&*payload.slice(payload_data_index..payload_data_index + current_fragment_size),
);
payloads.push(out.freeze());
payload_data_remaining -= current_fragment_size;
payload_data_index += current_fragment_size;
}
self.picture_id += 1;
self.picture_id &= 0x7FFF;
Ok(payloads)
}
fn clone_to(&self) -> Box<dyn Payloader + Send + Sync> {
Box::new(self.clone())
}
}
#[derive(PartialEq, Debug, Default, Clone)]
pub struct Vp9Packet {
pub i: bool,
pub p: bool,
pub l: bool,
pub f: bool,
pub b: bool,
pub e: bool,
pub v: bool,
pub z: bool,
pub picture_id: u16,
pub tid: u8,
pub u: bool,
pub sid: u8,
pub d: bool,
pub pdiff: Vec<u8>,
pub tl0picidx: u8,
pub ns: u8,
pub y: bool,
pub g: bool,
pub ng: u8,
pub width: Vec<u16>,
pub height: Vec<u16>,
pub pgtid: Vec<u8>,
pub pgu: Vec<bool>,
pub pgpdiff: Vec<Vec<u8>>,
}
impl Depacketizer for Vp9Packet {
fn depacketize(&mut self, packet: &Bytes) -> Result<Bytes> {
if packet.is_empty() {
return Err(Error::ErrShortPacket);
}
let reader = &mut packet.clone();
let b = reader.get_u8();
self.i = (b & 0x80) != 0;
self.p = (b & 0x40) != 0;
self.l = (b & 0x20) != 0;
self.f = (b & 0x10) != 0;
self.b = (b & 0x08) != 0;
self.e = (b & 0x04) != 0;
self.v = (b & 0x02) != 0;
self.z = (b & 0x01) != 0;
let mut payload_index = 1;
if self.i {
payload_index = self.parse_picture_id(reader, payload_index)?;
}
if self.l {
payload_index = self.parse_layer_info(reader, payload_index)?;
}
if self.f && self.p {
payload_index = self.parse_ref_indices(reader, payload_index)?;
}
if self.v {
payload_index = self.parse_ssdata(reader, payload_index)?;
}
Ok(packet.slice(payload_index..))
}
fn is_partition_head(&self, payload: &Bytes) -> bool {
if payload.is_empty() {
false
} else {
(payload[0] & 0x08) != 0
}
}
fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
marker
}
}
impl Vp9Packet {
fn parse_picture_id(
&mut self,
reader: &mut dyn Buf,
mut payload_index: usize,
) -> Result<usize> {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
let b = reader.get_u8();
payload_index += 1;
if (b & 0x80) != 0 {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
self.picture_id = (((b & 0x7f) as u16) << 8) | (reader.get_u8() as u16);
payload_index += 1;
} else {
self.picture_id = (b & 0x7F) as u16;
}
Ok(payload_index)
}
fn parse_layer_info(
&mut self,
reader: &mut dyn Buf,
mut payload_index: usize,
) -> Result<usize> {
payload_index = self.parse_layer_info_common(reader, payload_index)?;
if self.f {
Ok(payload_index)
} else {
self.parse_layer_info_non_flexible_mode(reader, payload_index)
}
}
fn parse_layer_info_common(
&mut self,
reader: &mut dyn Buf,
mut payload_index: usize,
) -> Result<usize> {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
let b = reader.get_u8();
payload_index += 1;
self.tid = b >> 5;
self.u = b & 0x10 != 0;
self.sid = (b >> 1) & 0x7;
self.d = b & 0x01 != 0;
if self.sid >= MAX_SPATIAL_LAYERS {
Err(Error::ErrTooManySpatialLayers)
} else {
Ok(payload_index)
}
}
fn parse_layer_info_non_flexible_mode(
&mut self,
reader: &mut dyn Buf,
mut payload_index: usize,
) -> Result<usize> {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
self.tl0picidx = reader.get_u8();
payload_index += 1;
Ok(payload_index)
}
fn parse_ref_indices(
&mut self,
reader: &mut dyn Buf,
mut payload_index: usize,
) -> Result<usize> {
let mut b = 1u8;
while (b & 0x1) != 0 {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
b = reader.get_u8();
payload_index += 1;
self.pdiff.push(b >> 1);
if self.pdiff.len() >= MAX_VP9REF_PICS {
return Err(Error::ErrTooManyPDiff);
}
}
Ok(payload_index)
}
fn parse_ssdata(&mut self, reader: &mut dyn Buf, mut payload_index: usize) -> Result<usize> {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
let b = reader.get_u8();
payload_index += 1;
self.ns = b >> 5;
self.y = b & 0x10 != 0;
self.g = (b >> 1) & 0x7 != 0;
let ns = (self.ns + 1) as usize;
self.ng = 0;
if self.y {
if reader.remaining() < 4 * ns {
return Err(Error::ErrShortPacket);
}
self.width = vec![0u16; ns];
self.height = vec![0u16; ns];
for i in 0..ns {
self.width[i] = reader.get_u16();
self.height[i] = reader.get_u16();
}
payload_index += 4 * ns;
}
if self.g {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
self.ng = reader.get_u8();
payload_index += 1;
}
for i in 0..self.ng as usize {
if reader.remaining() == 0 {
return Err(Error::ErrShortPacket);
}
let b = reader.get_u8();
payload_index += 1;
self.pgtid.push(b >> 5);
self.pgu.push(b & 0x10 != 0);
let r = ((b >> 2) & 0x3) as usize;
if reader.remaining() < r {
return Err(Error::ErrShortPacket);
}
self.pgpdiff.push(vec![]);
for _ in 0..r {
let b = reader.get_u8();
payload_index += 1;
self.pgpdiff[i].push(b);
}
}
Ok(payload_index)
}
}