use crate::error::{Error, Result};
use crate::packetizer::Depacketizer;
use bytes::Bytes;
#[cfg(test)]
mod h265_test;
const H265NALU_HEADER_SIZE: usize = 2;
const H265NALU_AGGREGATION_PACKET_TYPE: u8 = 48;
const H265NALU_FRAGMENTATION_UNIT_TYPE: u8 = 49;
const H265NALU_PACI_PACKET_TYPE: u8 = 50;
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct H265NALUHeader(pub u16);
impl H265NALUHeader {
fn new(high_byte: u8, low_byte: u8) -> Self {
H265NALUHeader(((high_byte as u16) << 8) | low_byte as u16)
}
pub fn f(&self) -> bool {
(self.0 >> 15) != 0
}
pub fn nalu_type(&self) -> u8 {
const MASK: u16 = 0b01111110 << 8;
((self.0 & MASK) >> (8 + 1)) as u8
}
pub fn is_type_vcl_unit(&self) -> bool {
const MSB_MASK: u8 = 0b00100000;
(self.nalu_type() & MSB_MASK) == 0
}
pub fn layer_id(&self) -> u8 {
const MASK: u16 = (0b00000001 << 8) | 0b11111000;
((self.0 & MASK) >> 3) as u8
}
pub fn tid(&self) -> u8 {
const MASK: u16 = 0b00000111;
(self.0 & MASK) as u8
}
pub fn is_aggregation_packet(&self) -> bool {
self.nalu_type() == H265NALU_AGGREGATION_PACKET_TYPE
}
pub fn is_fragmentation_unit(&self) -> bool {
self.nalu_type() == H265NALU_FRAGMENTATION_UNIT_TYPE
}
pub fn is_paci_packet(&self) -> bool {
self.nalu_type() == H265NALU_PACI_PACKET_TYPE
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265SingleNALUnitPacket {
payload_header: H265NALUHeader,
donl: Option<u16>,
payload: Bytes,
might_need_donl: bool,
}
impl H265SingleNALUnitPacket {
pub fn with_donl(&mut self, value: bool) {
self.might_need_donl = value;
}
fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
if payload.len() <= H265NALU_HEADER_SIZE {
return Err(Error::ErrShortPacket);
}
let payload_header = H265NALUHeader::new(payload[0], payload[1]);
if payload_header.f() {
return Err(Error::ErrH265CorruptedPacket);
}
if payload_header.is_fragmentation_unit()
|| payload_header.is_paci_packet()
|| payload_header.is_aggregation_packet()
{
return Err(Error::ErrInvalidH265PacketType);
}
let mut payload = payload.slice(2..);
if self.might_need_donl {
if payload.len() <= 2 {
return Err(Error::ErrShortPacket);
}
let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
self.donl = Some(donl);
payload = payload.slice(2..);
}
self.payload_header = payload_header;
self.payload = payload;
Ok(())
}
pub fn payload_header(&self) -> H265NALUHeader {
self.payload_header
}
pub fn donl(&self) -> Option<u16> {
self.donl
}
pub fn payload(&self) -> Bytes {
self.payload.clone()
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265AggregationUnitFirst {
donl: Option<u16>,
nal_unit_size: u16,
nal_unit: Bytes,
}
impl H265AggregationUnitFirst {
pub fn donl(&self) -> Option<u16> {
self.donl
}
pub fn nalu_size(&self) -> u16 {
self.nal_unit_size
}
pub fn nal_unit(&self) -> Bytes {
self.nal_unit.clone()
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265AggregationUnit {
dond: Option<u8>,
nal_unit_size: u16,
nal_unit: Bytes,
}
impl H265AggregationUnit {
pub fn dond(&self) -> Option<u8> {
self.dond
}
pub fn nalu_size(&self) -> u16 {
self.nal_unit_size
}
pub fn nal_unit(&self) -> Bytes {
self.nal_unit.clone()
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265AggregationPacket {
first_unit: Option<H265AggregationUnitFirst>,
other_units: Vec<H265AggregationUnit>,
might_need_donl: bool,
}
impl H265AggregationPacket {
pub fn with_donl(&mut self, value: bool) {
self.might_need_donl = value;
}
fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
if payload.len() <= H265NALU_HEADER_SIZE {
return Err(Error::ErrShortPacket);
}
let payload_header = H265NALUHeader::new(payload[0], payload[1]);
if payload_header.f() {
return Err(Error::ErrH265CorruptedPacket);
}
if !payload_header.is_aggregation_packet() {
return Err(Error::ErrInvalidH265PacketType);
}
let mut payload = payload.slice(2..);
let mut first_unit = H265AggregationUnitFirst::default();
if self.might_need_donl {
if payload.len() < 2 {
return Err(Error::ErrShortPacket);
}
let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
first_unit.donl = Some(donl);
payload = payload.slice(2..);
}
if payload.len() < 2 {
return Err(Error::ErrShortPacket);
}
first_unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
payload = payload.slice(2..);
if payload.len() < first_unit.nal_unit_size as usize {
return Err(Error::ErrShortPacket);
}
first_unit.nal_unit = payload.slice(..first_unit.nal_unit_size as usize);
payload = payload.slice(first_unit.nal_unit_size as usize..);
let mut units = vec![]; loop {
let mut unit = H265AggregationUnit::default();
if self.might_need_donl {
if payload.is_empty() {
break;
}
let dond = payload[0];
unit.dond = Some(dond);
payload = payload.slice(1..);
}
if payload.len() < 2 {
break;
}
unit.nal_unit_size = ((payload[0] as u16) << 8) | (payload[1] as u16);
payload = payload.slice(2..);
if payload.len() < unit.nal_unit_size as usize {
break;
}
unit.nal_unit = payload.slice(..unit.nal_unit_size as usize);
payload = payload.slice(unit.nal_unit_size as usize..);
units.push(unit);
}
if units.is_empty() {
return Err(Error::ErrShortPacket);
}
self.first_unit = Some(first_unit);
self.other_units = units;
Ok(())
}
pub fn first_unit(&self) -> Option<&H265AggregationUnitFirst> {
self.first_unit.as_ref()
}
pub fn other_units(&self) -> &[H265AggregationUnit] {
self.other_units.as_slice()
}
}
const H265FRAGMENTATION_UNIT_HEADER_SIZE: usize = 1;
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct H265FragmentationUnitHeader(pub u8);
impl H265FragmentationUnitHeader {
pub fn s(&self) -> bool {
const MASK: u8 = 0b10000000;
((self.0 & MASK) >> 7) != 0
}
pub fn e(&self) -> bool {
const MASK: u8 = 0b01000000;
((self.0 & MASK) >> 6) != 0
}
pub fn fu_type(&self) -> u8 {
const MASK: u8 = 0b00111111;
self.0 & MASK
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265FragmentationUnitPacket {
payload_header: H265NALUHeader,
fu_header: H265FragmentationUnitHeader,
donl: Option<u16>,
payload: Bytes,
might_need_donl: bool,
}
impl H265FragmentationUnitPacket {
pub fn with_donl(&mut self, value: bool) {
self.might_need_donl = value;
}
fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + H265FRAGMENTATION_UNIT_HEADER_SIZE;
if payload.len() <= TOTAL_HEADER_SIZE {
return Err(Error::ErrShortPacket);
}
let payload_header = H265NALUHeader::new(payload[0], payload[1]);
if payload_header.f() {
return Err(Error::ErrH265CorruptedPacket);
}
if !payload_header.is_fragmentation_unit() {
return Err(Error::ErrInvalidH265PacketType);
}
let fu_header = H265FragmentationUnitHeader(payload[2]);
let mut payload = payload.slice(3..);
if fu_header.s() && self.might_need_donl {
if payload.len() <= 2 {
return Err(Error::ErrShortPacket);
}
let donl = ((payload[0] as u16) << 8) | (payload[1] as u16);
self.donl = Some(donl);
payload = payload.slice(2..);
}
self.payload_header = payload_header;
self.fu_header = fu_header;
self.payload = payload;
Ok(())
}
pub fn payload_header(&self) -> H265NALUHeader {
self.payload_header
}
pub fn fu_header(&self) -> H265FragmentationUnitHeader {
self.fu_header
}
pub fn donl(&self) -> Option<u16> {
self.donl
}
pub fn payload(&self) -> Bytes {
self.payload.clone()
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265PACIPacket {
payload_header: H265NALUHeader,
paci_header_fields: u16,
phes: Bytes,
payload: Bytes,
}
impl H265PACIPacket {
pub fn payload_header(&self) -> H265NALUHeader {
self.payload_header
}
pub fn a(&self) -> bool {
const MASK: u16 = 0b10000000 << 8;
(self.paci_header_fields & MASK) != 0
}
pub fn ctype(&self) -> u8 {
const MASK: u16 = 0b01111110 << 8;
((self.paci_header_fields & MASK) >> (8 + 1)) as u8
}
pub fn phs_size(&self) -> u8 {
const MASK: u16 = (0b00000001 << 8) | 0b11110000;
((self.paci_header_fields & MASK) >> 4) as u8
}
pub fn f0(&self) -> bool {
const MASK: u16 = 0b00001000;
(self.paci_header_fields & MASK) != 0
}
pub fn f1(&self) -> bool {
const MASK: u16 = 0b00000100;
(self.paci_header_fields & MASK) != 0
}
pub fn f2(&self) -> bool {
const MASK: u16 = 0b00000010;
(self.paci_header_fields & MASK) != 0
}
pub fn y(&self) -> bool {
const MASK: u16 = 0b00000001;
(self.paci_header_fields & MASK) != 0
}
pub fn phes(&self) -> Bytes {
self.phes.clone()
}
pub fn payload(&self) -> Bytes {
self.payload.clone()
}
pub fn tsci(&self) -> Option<H265TSCI> {
if !self.f0() || self.phs_size() < 3 {
return None;
}
Some(H265TSCI(
((self.phes[0] as u32) << 16) | ((self.phes[1] as u32) << 8) | self.phes[0] as u32,
))
}
fn depacketize(&mut self, payload: &Bytes) -> Result<()> {
const TOTAL_HEADER_SIZE: usize = H265NALU_HEADER_SIZE + 2;
if payload.len() <= TOTAL_HEADER_SIZE {
return Err(Error::ErrShortPacket);
}
let payload_header = H265NALUHeader::new(payload[0], payload[1]);
if payload_header.f() {
return Err(Error::ErrH265CorruptedPacket);
}
if !payload_header.is_paci_packet() {
return Err(Error::ErrInvalidH265PacketType);
}
let paci_header_fields = ((payload[2] as u16) << 8) | (payload[3] as u16);
let mut payload = payload.slice(4..);
self.paci_header_fields = paci_header_fields;
let header_extension_size = self.phs_size();
if payload.len() < header_extension_size as usize + 1 {
self.paci_header_fields = 0;
return Err(Error::ErrShortPacket);
}
self.payload_header = payload_header;
if header_extension_size > 0 {
self.phes = payload.slice(..header_extension_size as usize);
}
payload = payload.slice(header_extension_size as usize..);
self.payload = payload;
Ok(())
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq)]
pub struct H265TSCI(pub u32);
impl H265TSCI {
pub fn tl0picidx(&self) -> u8 {
const M1: u32 = 0xFFFF0000;
const M2: u32 = 0xFF00;
((((self.0 & M1) >> 16) & M2) >> 8) as u8
}
pub fn irap_pic_id(&self) -> u8 {
const M1: u32 = 0xFFFF0000;
const M2: u32 = 0x00FF;
(((self.0 & M1) >> 16) & M2) as u8
}
pub fn s(&self) -> bool {
const M1: u32 = 0xFF00;
const M2: u32 = 0b10000000;
(((self.0 & M1) >> 8) & M2) != 0
}
pub fn e(&self) -> bool {
const M1: u32 = 0xFF00;
const M2: u32 = 0b01000000;
(((self.0 & M1) >> 8) & M2) != 0
}
pub fn res(&self) -> u8 {
const M1: u32 = 0xFF00;
const M2: u32 = 0b00111111;
(((self.0 & M1) >> 8) & M2) as u8
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum H265Payload {
H265SingleNALUnitPacket(H265SingleNALUnitPacket),
H265FragmentationUnitPacket(H265FragmentationUnitPacket),
H265AggregationPacket(H265AggregationPacket),
H265PACIPacket(H265PACIPacket),
}
impl Default for H265Payload {
fn default() -> Self {
H265Payload::H265SingleNALUnitPacket(H265SingleNALUnitPacket::default())
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct H265Packet {
payload: H265Payload,
might_need_donl: bool,
}
impl H265Packet {
pub fn with_donl(&mut self, value: bool) {
self.might_need_donl = value;
}
pub fn payload(&self) -> &H265Payload {
&self.payload
}
}
impl Depacketizer for H265Packet {
fn depacketize(&mut self, payload: &Bytes) -> Result<Bytes> {
if payload.len() <= H265NALU_HEADER_SIZE {
return Err(Error::ErrShortPacket);
}
let payload_header = H265NALUHeader::new(payload[0], payload[1]);
if payload_header.f() {
return Err(Error::ErrH265CorruptedPacket);
}
if payload_header.is_paci_packet() {
let mut decoded = H265PACIPacket::default();
decoded.depacketize(payload)?;
self.payload = H265Payload::H265PACIPacket(decoded);
} else if payload_header.is_fragmentation_unit() {
let mut decoded = H265FragmentationUnitPacket::default();
decoded.with_donl(self.might_need_donl);
decoded.depacketize(payload)?;
self.payload = H265Payload::H265FragmentationUnitPacket(decoded);
} else if payload_header.is_aggregation_packet() {
let mut decoded = H265AggregationPacket::default();
decoded.with_donl(self.might_need_donl);
decoded.depacketize(payload)?;
self.payload = H265Payload::H265AggregationPacket(decoded);
} else {
let mut decoded = H265SingleNALUnitPacket::default();
decoded.with_donl(self.might_need_donl);
decoded.depacketize(payload)?;
self.payload = H265Payload::H265SingleNALUnitPacket(decoded);
}
Ok(payload.clone())
}
fn is_partition_head(&self, _payload: &Bytes) -> bool {
true
}
fn is_partition_tail(&self, marker: bool, _payload: &Bytes) -> bool {
marker
}
}