use nom::{
number::streaming::{be_i24, be_u8},
Err as NomErr, IResult, Needed,
};
#[derive(Clone, Debug, PartialEq)]
pub struct VideoTag<'a> {
pub header: VideoTagHeader, pub body: VideoTagBody<'a>,
}
impl<'a> VideoTag<'a> {
pub fn parse(input: &'a [u8], size: usize) -> IResult<&'a [u8], VideoTag<'a>> {
do_parse!(
input,
header: call!(VideoTagHeader::parse, size) >>
body: call!(VideoTagBody::parse, size - 1) >>
(VideoTag {header, body })
)
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct VideoTagHeader {
pub frame_type: FrameType,
pub codec_id: CodecID,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FrameType {
Key,
Inter,
DisposableInter,
Generated,
Command,
Unknown,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum CodecID {
SorensonH263,
Screen1,
VP6,
VP6Alpha,
Screen2,
AVC,
Unknown,
}
impl VideoTagHeader {
pub fn parse(input: &[u8], size: usize) -> IResult<&[u8], VideoTagHeader> {
if size < 1 {
return Err(NomErr::Incomplete(Needed::new(1)));
}
let (remain, (frame_type, codec_id)) = try_parse!(
input,
bits!(tuple!(
switch!(take_bits!(4u8),
1 => value!(FrameType::Key) |
2 => value!(FrameType::Inter) |
3 => value!(FrameType::DisposableInter) |
4 => value!(FrameType::Generated) |
5 => value!(FrameType::Command) |
_ => value!(FrameType::Unknown)
),
switch!(take_bits!(4u8),
2 => value!(CodecID::SorensonH263) |
3 => value!(CodecID::Screen1) |
4 => value!(CodecID::VP6) |
5 => value!(CodecID::VP6Alpha) |
6 => value!(CodecID::Screen2) |
7 => value!(CodecID::AVC) |
_ => value!(CodecID::Unknown)
)
))
);
Ok((
remain,
VideoTagHeader {
frame_type,
codec_id,
},
))
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct VideoTagBody<'a> {
pub data: &'a [u8],
}
impl<'a> VideoTagBody<'a> {
pub fn parse(input: &'a [u8], size: usize) -> IResult<&'a [u8], VideoTagBody<'a>> {
if input.len() < size {
return Err(NomErr::Incomplete(Needed::new(size)));
}
Ok((
&input[size..],
VideoTagBody {
data: &input[0..size],
},
))
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct AvcVideoPacket<'a> {
pub packet_type: AvcPacketType,
pub composition_time: i32,
pub avc_data: &'a [u8],
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum AvcPacketType {
SequenceHeader,
NALU,
EndOfSequence,
Unknown,
}
pub fn avc_video_packet(input: &[u8], size: usize) -> IResult<&[u8], AvcVideoPacket> {
if input.len() < size {
return Err(NomErr::Incomplete(Needed::new(size)));
}
if size < 4 {
return Err(NomErr::Incomplete(Needed::new(4)));
}
let (_, (packet_type, composition_time)) = try_parse!(
input,
tuple!(
switch!(be_u8,
0 => value!(AvcPacketType::SequenceHeader) |
1 => value!(AvcPacketType::NALU) |
2 => value!(AvcPacketType::EndOfSequence) |
_ => value!(AvcPacketType::Unknown)
),
be_i24
)
);
Ok((
&input[size..],
AvcVideoPacket {
packet_type,
composition_time,
avc_data: &input[4..size],
},
))
}