use bytes::{Bytes, BytesMut, Buf, BufMut};
use std::any::Any;
use super::traits::PayloadFormat;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Vp8DescriptorType {
Basic,
Extended,
}
pub struct Vp8PayloadFormat {
clock_rate: u32,
payload_type: u8,
use_extended_header: bool,
picture_id_present: bool,
max_frame_rate: u32,
average_bitrate: u32,
}
impl Vp8PayloadFormat {
pub fn new(payload_type: u8) -> Self {
Self {
clock_rate: 90000,
payload_type,
use_extended_header: true,
picture_id_present: true,
max_frame_rate: 30,
average_bitrate: 1_000_000, }
}
pub fn with_extended_header(mut self, use_extended: bool) -> Self {
self.use_extended_header = use_extended;
self
}
pub fn with_picture_id(mut self, picture_id_present: bool) -> Self {
self.picture_id_present = picture_id_present;
self
}
pub fn with_bitrate(mut self, bitrate: u32) -> Self {
self.average_bitrate = bitrate;
self
}
pub fn with_frame_rate(mut self, frame_rate: u32) -> Self {
self.max_frame_rate = frame_rate;
self
}
pub fn descriptor_size(&self) -> usize {
let mut size = 1;
if self.use_extended_header {
size += 1;
if self.picture_id_present {
size += 2; }
}
size
}
fn parse_descriptor(buffer: &[u8]) -> Option<(usize, bool)> {
if buffer.is_empty() {
return None;
}
let x = (buffer[0] & 0x80) != 0; let start_of_frame = (buffer[0] & 0x10) != 0;
let mut offset = 1;
if x && buffer.len() > 1 {
let i = (buffer[1] & 0x80) != 0; let l = (buffer[1] & 0x40) != 0; let t = (buffer[1] & 0x20) != 0; let k = (buffer[1] & 0x10) != 0;
offset += 1;
if i {
if buffer.len() <= offset {
return None;
}
if (buffer[offset] & 0x80) != 0 {
offset += 2;
} else {
offset += 1;
}
}
if l && buffer.len() > offset {
offset += 1; }
if (t || k) && buffer.len() > offset {
offset += 1; }
}
Some((offset, start_of_frame))
}
}
impl PayloadFormat for Vp8PayloadFormat {
fn payload_type(&self) -> u8 {
self.payload_type
}
fn clock_rate(&self) -> u32 {
self.clock_rate
}
fn channels(&self) -> u8 {
1 }
fn preferred_packet_duration(&self) -> u32 {
let frame_duration = 1000 / self.max_frame_rate;
frame_duration
}
fn packet_size_from_duration(&self, duration_ms: u32) -> usize {
let descriptor_size = self.descriptor_size();
let max_bytes = (self.average_bitrate * duration_ms) / (8 * 1000);
(max_bytes as usize) + descriptor_size
}
fn duration_from_packet_size(&self, packet_size: usize) -> u32 {
let descriptor_size = self.descriptor_size();
let payload_size = packet_size.saturating_sub(descriptor_size);
let bits = payload_size as u32 * 8;
(bits * 1000) / self.average_bitrate
}
fn pack(&self, media_data: &[u8], timestamp: u32) -> Bytes {
let descriptor_size = self.descriptor_size();
let mut buffer = BytesMut::with_capacity(descriptor_size + media_data.len());
let mut first_byte = 0u8;
first_byte |= 0x10;
if self.use_extended_header {
first_byte |= 0x80; buffer.put_u8(first_byte);
let mut second_byte = 0u8;
if self.picture_id_present {
second_byte |= 0x80; }
buffer.put_u8(second_byte);
if self.picture_id_present {
let picture_id = (timestamp % 32768) as u16;
buffer.put_u8((picture_id >> 8) as u8 | 0x80); buffer.put_u8(picture_id as u8);
}
} else {
buffer.put_u8(first_byte);
}
buffer.extend_from_slice(media_data);
buffer.freeze()
}
fn unpack(&self, payload: &[u8], _timestamp: u32) -> Bytes {
if payload.is_empty() {
return Bytes::new();
}
if let Some((offset, _start_of_frame)) = Self::parse_descriptor(payload) {
if offset < payload.len() {
return Bytes::copy_from_slice(&payload[offset..]);
}
}
Bytes::copy_from_slice(payload)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vp8_payload_format() {
let format = Vp8PayloadFormat::new(96)
.with_extended_header(true)
.with_picture_id(true)
.with_bitrate(2_000_000) .with_frame_rate(30);
assert_eq!(format.payload_type(), 96);
assert_eq!(format.clock_rate(), 90000);
assert_eq!(format.channels(), 1);
assert_eq!(format.preferred_packet_duration(), 33);
assert_eq!(format.samples_from_duration(33), 2970);
let expected_size = format.packet_size_from_duration(33);
assert_eq!(expected_size, 8254);
let test_data = vec![0u8; 100];
let packed = format.pack(&test_data, 1234);
assert_eq!(packed.len(), 100 + format.descriptor_size());
let unpacked = format.unpack(&packed, 1234);
assert_eq!(unpacked.len(), 100);
}
#[test]
fn test_vp8_descriptor_parsing() {
let basic_desc = vec![0x10, 0x01, 0x02, 0x03];
let (offset, is_start) = Vp8PayloadFormat::parse_descriptor(&basic_desc).unwrap();
assert_eq!(offset, 1);
assert_eq!(is_start, true);
let ext_desc = vec![0x90, 0x80, 0x81, 0x23, 0x01, 0x02, 0x03];
let (offset, is_start) = Vp8PayloadFormat::parse_descriptor(&ext_desc).unwrap();
assert_eq!(offset, 4);
assert_eq!(is_start, true);
}
}