pub mod avcvideo;
pub mod iso_639_language;
pub mod max_bitrate;
pub mod registration;
use self::avcvideo::AvcVideoDescriptor;
use self::iso_639_language::Iso639LanguageDescriptor;
use self::max_bitrate::MaximumBitrateDescriptor;
use self::registration::RegistrationDescriptor;
use std::fmt;
use std::marker;
pub trait Descriptor<'buf>: Sized {
fn from_bytes(buf: &'buf [u8]) -> Result<Self, DescriptorError>;
}
#[macro_export]
macro_rules! descriptor_enum {
(
$(#[$outer:meta])*
$name:ident {
$(
$(#[$inner:ident $($args:tt)*])*
$case_name:ident $($tags:pat_param)|* => $t:ident
),*,
}
) => {
$(#[$outer])*
pub enum $name<'buf> {
$(
$(#[$inner $($args)*])*
$case_name($t<'buf>),
)*
}
impl<'buf> $crate::descriptor::Descriptor<'buf> for $name<'buf> {
fn from_bytes(buf: &'buf[u8]) -> Result<Self, $crate::descriptor::DescriptorError> {
if buf.len() < 2 {
return Err($crate::descriptor::DescriptorError::BufferTooShort{ buflen: buf.len() })
}
let tag = buf[0];
let len = buf[1] as usize;
let tag_end = len + 2;
if tag_end > buf.len() {
return Err($crate::descriptor::DescriptorError::TagTooLongForBuffer{ taglen: len, buflen: buf.len() })
}
let payload = &buf[2..tag_end];
match tag {
$( $( $tags )|* => Ok($name::$case_name($t::new(tag, payload)?)), )*
}
}
}
}
}
pub struct UnknownDescriptor<'buf> {
pub tag: u8,
pub payload: &'buf [u8],
}
impl<'buf> UnknownDescriptor<'buf> {
pub fn new(tag: u8, payload: &'buf [u8]) -> Result<UnknownDescriptor<'buf>, DescriptorError> {
Ok(UnknownDescriptor { tag, payload })
}
}
impl<'buf> fmt::Debug for UnknownDescriptor<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("UnknownDescriptor")
.field("tag", &self.tag)
.field("len", &self.payload.len())
.finish()
}
}
descriptor_enum! {
#[derive(Debug)]
CoreDescriptors {
Reserved 0|1|57..=62 => UnknownDescriptor,
VideoStream 2 => UnknownDescriptor,
AudioStream 3 => UnknownDescriptor,
Hierarchy 4 => UnknownDescriptor,
Registration 5 => RegistrationDescriptor,
DataStreamAlignment 6 => UnknownDescriptor,
TargetBackgroundGrid 7 => UnknownDescriptor,
VideoWindow 8 => UnknownDescriptor,
CA 9 => UnknownDescriptor,
ISO639Language 10 => Iso639LanguageDescriptor,
SystemClock 11 => UnknownDescriptor,
MultiplexBufferUtilization 12 => UnknownDescriptor,
Copyright 13 => UnknownDescriptor,
MaximumBitrate 14 => MaximumBitrateDescriptor,
PrivateDataIndicator 15 => UnknownDescriptor,
SmoothingBuffer 16 => UnknownDescriptor,
STD 17 => UnknownDescriptor,
IBP 18 => UnknownDescriptor,
IsoIec13818dash6 19..=26 => UnknownDescriptor,
MPEG4Video 27 => UnknownDescriptor,
MPEG4Audio 28 => UnknownDescriptor,
IOD 29 => UnknownDescriptor,
SL 30 => UnknownDescriptor,
FMC 31 => UnknownDescriptor,
ExternalESID 32 => UnknownDescriptor,
MuxCode 33 => UnknownDescriptor,
FmxBufferSize 34 => UnknownDescriptor,
MultiplexBuffer 35 => UnknownDescriptor,
MontentLabeling 36 => UnknownDescriptor,
MetadataPointer 37 => UnknownDescriptor,
Metadata 38 => UnknownDescriptor,
MetadataStd 39 => UnknownDescriptor,
AvcVideo 40 => AvcVideoDescriptor,
IPMP 41 => UnknownDescriptor,
AvcTimingAndHrd 42 => UnknownDescriptor,
Mpeg2AacAudio 43 => UnknownDescriptor,
FlexMuxTiming 44 => UnknownDescriptor,
Mpeg4Text 45 => UnknownDescriptor,
Mpeg4AudioExtension 46 => UnknownDescriptor,
AuxiliaryVideoStream 47 => UnknownDescriptor,
SvcExtension 48 => UnknownDescriptor,
MvcExtension 49 => UnknownDescriptor,
J2kVideo 50 => UnknownDescriptor,
MvcOperationPoint 51 => UnknownDescriptor,
Mpeg2StereoscopicVideoFormat 52 => UnknownDescriptor,
StereoscopicProgramInfo 53 => UnknownDescriptor,
StereoscopicVideoInfo 54 => UnknownDescriptor,
TransportProfile 55 => UnknownDescriptor,
HevcVideo 56 => UnknownDescriptor,
Extension 63 => UnknownDescriptor,
UserPrivate 64..=255 => UnknownDescriptor,
}
}
pub struct DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>,
{
buf: &'buf [u8],
phantom: marker::PhantomData<Desc>,
}
impl<'buf, Desc> DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>,
{
pub fn new(buf: &'buf [u8]) -> DescriptorIter<'buf, Desc> {
DescriptorIter {
buf,
phantom: marker::PhantomData,
}
}
}
impl<'buf, Desc> Iterator for DescriptorIter<'buf, Desc>
where
Desc: Descriptor<'buf>,
{
type Item = Result<Desc, DescriptorError>;
fn next(&mut self) -> Option<Self::Item> {
if self.buf.is_empty() {
return None;
}
if self.buf.len() < 2 {
let buflen = self.buf.len();
self.buf = &self.buf[0..0];
Some(Err(DescriptorError::BufferTooShort { buflen }))
} else {
let tag = self.buf[0];
let len = self.buf[1] as usize;
let remaining_size = self.buf.len() - 2;
if len > remaining_size {
self.buf = &self.buf[0..0];
Some(Err(DescriptorError::NotEnoughData {
tag,
actual: remaining_size,
expected: len,
}))
} else {
let (desc, rest) = self.buf.split_at(len + 2);
self.buf = rest;
Some(Descriptor::from_bytes(desc))
}
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum DescriptorError {
NotEnoughData {
tag: u8,
actual: usize,
expected: usize,
},
TagTooLongForBuffer {
taglen: usize,
buflen: usize,
},
BufferTooShort {
buflen: usize,
},
UnhandledTagValue(u8),
}
pub(crate) fn descriptor_len(buf: &[u8], tag: u8, len: usize) -> Result<(), DescriptorError> {
if buf.len() < len {
Err(DescriptorError::NotEnoughData {
tag,
actual: buf.len(),
expected: len,
})
} else {
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::descriptor::{descriptor_len, CoreDescriptors, DescriptorError, DescriptorIter};
use assert_matches::assert_matches;
use hex_literal::*;
#[test]
fn core() {
let data = hex!("000100");
let mut iter = DescriptorIter::<CoreDescriptors<'_>>::new(&data);
let desc = iter.next().unwrap();
assert!(!format!("{:?}", desc).is_empty());
assert_matches!(desc, Ok(CoreDescriptors::Reserved(d)) => {
assert_eq!(d.tag, 0);
assert_eq!(d.payload, &[0]);
});
}
#[test]
fn not_enough_data() {
assert_matches!(
descriptor_len(b"", 0, 1),
Err(DescriptorError::NotEnoughData {
tag: 0,
actual: 0,
expected: 1,
})
);
}
}