use super::{CodecParser, Frame, PesPacket, pts_to_ns};
use super::h264::{find_start_code, skip_start_code};
const NAL_VPS: u8 = 32;
const NAL_SPS: u8 = 33;
const NAL_PPS: u8 = 34;
const NAL_AUD: u8 = 35;
const NAL_BLA_W_LP: u8 = 16;
const NAL_RSV_IRAP_VCL23: u8 = 23;
pub struct HevcParser {
vps: Option<Vec<u8>>,
sps: Option<Vec<u8>>,
pps: Option<Vec<u8>>,
}
impl HevcParser {
pub fn new() -> Self {
Self { vps: None, sps: None, pps: None }
}
}
impl CodecParser for HevcParser {
fn parse(&mut self, pes: &PesPacket) -> Vec<Frame> {
if pes.data.is_empty() {
return Vec::new();
}
let pts_ns = pes.pts.map(pts_to_ns).unwrap_or(0);
let data = &pes.data;
let mut keyframe = false;
let mut pos = 0;
while let Some(sc_pos) = find_start_code(data, pos) {
if let Some(nal_start) = skip_start_code(data, sc_pos) {
let next = find_start_code(data, nal_start).unwrap_or(data.len());
let mut end = next;
while end > nal_start && data[end - 1] == 0x00 { end -= 1; }
if nal_start < data.len() {
let nal_type = (data[nal_start] >> 1) & 0x3F;
match nal_type {
NAL_VPS => self.vps = Some(data[nal_start..end].to_vec()),
NAL_SPS => self.sps = Some(data[nal_start..end].to_vec()),
NAL_PPS => self.pps = Some(data[nal_start..end].to_vec()),
t if t >= NAL_BLA_W_LP && t <= NAL_RSV_IRAP_VCL23 => {
keyframe = true;
}
_ => {}
}
}
pos = next;
} else {
break;
}
}
let mut frame_data = Vec::new();
let mut pos = 0;
while let Some(sc_pos) = find_start_code(&pes.data, pos) {
if let Some(nal_start) = skip_start_code(&pes.data, sc_pos) {
let next = find_start_code(&pes.data, nal_start).unwrap_or(pes.data.len());
let mut end = next;
while end > nal_start && pes.data[end - 1] == 0x00 { end -= 1; }
if nal_start < pes.data.len() {
let nal_type = (pes.data[nal_start] >> 1) & 0x3F;
if nal_type != NAL_VPS && nal_type != NAL_SPS && nal_type != NAL_PPS && nal_type != NAL_AUD {
let nal = &pes.data[nal_start..end];
let len = nal.len() as u32;
frame_data.extend_from_slice(&len.to_be_bytes());
frame_data.extend_from_slice(nal);
}
}
pos = next;
} else {
break;
}
}
if frame_data.is_empty() {
return Vec::new();
}
vec![Frame {
pts_ns,
keyframe,
data: frame_data,
}]
}
fn codec_private(&self) -> Option<Vec<u8>> {
let vps = self.vps.as_ref()?;
let sps = self.sps.as_ref()?;
let pps = self.pps.as_ref()?;
let mut record = Vec::new();
record.push(1); if sps.len() > 3 {
record.push(sps[1]); } else {
record.push(0);
}
record.extend_from_slice(&[0, 0, 0, 0]);
record.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
record.push(if sps.len() > 12 { sps[12] } else { 0 });
record.extend_from_slice(&[0xF0, 0x00]);
record.push(0xFC);
record.push(0xFC | 1); record.push(0xF8);
record.push(0xF8);
record.extend_from_slice(&[0, 0]);
record.push(0x03); record.push(3);
record.push(0x20 | (NAL_VPS & 0x3F)); record.extend_from_slice(&[0, 1]); record.push((vps.len() >> 8) as u8);
record.push(vps.len() as u8);
record.extend_from_slice(vps);
record.push(0x20 | (NAL_SPS & 0x3F));
record.extend_from_slice(&[0, 1]);
record.push((sps.len() >> 8) as u8);
record.push(sps.len() as u8);
record.extend_from_slice(sps);
record.push(0x20 | (NAL_PPS & 0x3F));
record.extend_from_slice(&[0, 1]);
record.push((pps.len() >> 8) as u8);
record.push(pps.len() as u8);
record.extend_from_slice(pps);
Some(record)
}
}