use std::io;
use byteorder::{BigEndian, ReadBytesExt};
use bytes::Bytes;
use nutype_enum::nutype_enum;
use super::{VideoCommand, VideoFrameType};
nutype_enum! {
pub enum VideoCodecId(u8) {
SorensonH263 = 2,
ScreenVideo = 3,
On2VP6 = 4,
On2VP6WithAlphaChannel = 5,
ScreenVideoVersion2 = 6,
Avc = 7,
}
}
nutype_enum! {
pub enum AvcPacketType(u8) {
SeqHdr = 0,
Nalu = 1,
EndOfSequence = 2,
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum LegacyVideoTagHeaderAvcPacket {
SequenceHeader,
Nalu {
composition_time_offset: u32,
},
EndOfSequence,
Unknown {
avc_packet_type: AvcPacketType,
composition_time_offset: u32,
},
}
impl LegacyVideoTagHeaderAvcPacket {
pub fn demux(reader: &mut io::Cursor<Bytes>) -> io::Result<Self> {
let avc_packet_type = AvcPacketType::from(reader.read_u8()?);
let composition_time_offset = reader.read_u24::<BigEndian>()?;
match avc_packet_type {
AvcPacketType::SeqHdr => Ok(Self::SequenceHeader),
AvcPacketType::Nalu => Ok(Self::Nalu { composition_time_offset }),
AvcPacketType::EndOfSequence => Ok(Self::EndOfSequence),
_ => Ok(Self::Unknown {
avc_packet_type,
composition_time_offset,
}),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum LegacyVideoTagHeader {
VideoCommand(VideoCommand),
AvcPacket(LegacyVideoTagHeaderAvcPacket),
Other {
video_codec_id: VideoCodecId,
},
}
impl LegacyVideoTagHeader {
pub fn demux(reader: &mut io::Cursor<Bytes>) -> io::Result<Self> {
let first_byte = reader.read_u8()?;
let frame_type = VideoFrameType::from(first_byte >> 4); let video_codec_id = VideoCodecId::from(first_byte & 0b0000_1111);
if video_codec_id == VideoCodecId::Avc {
let avc_packet = LegacyVideoTagHeaderAvcPacket::demux(reader)?;
return Ok(Self::AvcPacket(avc_packet));
}
if frame_type == VideoFrameType::Command {
return Ok(Self::VideoCommand(VideoCommand::from(reader.read_u8()?)));
}
Ok(Self::Other { video_codec_id })
}
}