webmetro/src/webm.rs

142 lines
4.3 KiB
Rust
Raw Normal View History

2017-07-10 23:36:20 +00:00
use bytes::{BigEndian, ByteOrder};
2017-06-27 06:11:29 +00:00
use ebml::*;
const SEGMENT_ID: u64 = 0x08538067;
const SEEK_HEAD_ID: u64 = 0x014D9B74;
const SEGMENT_INFO_ID: u64 = 0x0549A966;
const CUES_ID: u64 = 0x0C53BB6B;
const TRACKS_ID: u64 = 0x0654AE6B;
const CLUSTER_ID: u64 = 0x0F43B675;
const TIMECODE_ID: u64 = 0x67;
const SIMPLE_BLOCK_ID: u64 = 0x23;
2017-06-27 06:11:29 +00:00
pub struct Webm;
#[derive(Debug, PartialEq)]
pub enum WebmElement<'b> {
EbmlHead,
Void,
Segment,
SeekHead,
Info,
Cues,
Tracks(&'b[u8]),
Cluster,
Timecode(u64),
2017-07-01 05:30:43 +00:00
SimpleBlock {
track: u64,
timecode: i16,
flags: u8,
data: &'b[u8]
},
2017-06-27 06:11:29 +00:00
Unknown(u64)
}
impl<'a> Schema<'a> for Webm {
type Element = WebmElement<'a>;
fn should_unwrap(&self, element_id: u64) -> bool {
match element_id {
// Segment
SEGMENT_ID => true,
CLUSTER_ID => true,
2017-06-27 06:11:29 +00:00
_ => false
}
}
fn decode<'b: 'a>(&self, element_id: u64, bytes: &'b[u8]) -> Result<WebmElement<'b>, Error> {
match element_id {
EBML_HEAD_ID => Ok(WebmElement::EbmlHead),
VOID_ID => Ok(WebmElement::Void),
SEGMENT_ID => Ok(WebmElement::Segment),
SEEK_HEAD_ID => Ok(WebmElement::SeekHead),
SEGMENT_INFO_ID => Ok(WebmElement::Info),
CUES_ID => Ok(WebmElement::Cues),
TRACKS_ID => Ok(WebmElement::Tracks(bytes)),
CLUSTER_ID => Ok(WebmElement::Cluster),
2017-07-01 05:30:43 +00:00
TIMECODE_ID => decode_uint(bytes).map(WebmElement::Timecode),
SIMPLE_BLOCK_ID => decode_simple_block(bytes),
2017-06-27 06:11:29 +00:00
_ => Ok(WebmElement::Unknown(element_id))
}
}
}
2017-06-28 05:54:30 +00:00
2017-07-01 05:30:43 +00:00
fn decode_simple_block(bytes: &[u8]) -> Result<WebmElement, Error> {
if let Ok(Some((Varint::Value(track), track_field_len))) = decode_varint(bytes) {
let header_len = track_field_len + 2 + 1;
if bytes.len() < header_len {
return Err(Error::CorruptPayload);
}
let timecode = BigEndian::read_i16(&bytes[track_field_len..]);
let flags = bytes[track_field_len + 2];
return Ok(WebmElement::SimpleBlock {
track: track,
timecode: timecode,
flags: flags,
data: &bytes[header_len..],
})
} else {
return Err(Error::CorruptPayload);
}
}
2017-06-28 05:54:30 +00:00
#[cfg(test)]
mod tests {
use tests::TEST_FILE;
use webm::*;
#[test]
fn decode_webm_test1() {
let mut iter = Webm.parse(TEST_FILE).into_iter();
// test that we match the structure of the test file
assert_eq!(iter.next(), Some(WebmElement::EbmlHead));
assert_eq!(iter.next(), Some(WebmElement::Segment));
assert_eq!(iter.next(), Some(WebmElement::SeekHead));
assert_eq!(iter.next(), Some(WebmElement::Void));
assert_eq!(iter.next(), Some(WebmElement::Info));
assert_eq!(iter.next(), Some(WebmElement::Tracks(&TEST_FILE[358..421])));
2017-07-01 20:55:24 +00:00
assert_eq!(iter.next(), Some(WebmElement::Cluster));
2017-07-01 20:55:24 +00:00
assert_eq!(iter.next(), Some(WebmElement::Timecode(0)));
assert_eq!(iter.next(), Some(WebmElement::SimpleBlock {
track: 1,
timecode: 0,
flags: 0b10000000,
data: &TEST_FILE[443..3683]
}));
assert_eq!(iter.next(), Some(WebmElement::SimpleBlock {
track: 1,
timecode: 33,
flags: 0b00000000,
data: &TEST_FILE[3690..4735]
}));
assert_eq!(iter.next(), Some(WebmElement::SimpleBlock {
track: 1,
timecode: 67,
flags: 0b00000000,
data: &TEST_FILE[4741..4801]
}));
for _ in 3..30 {
// skip remaining contents for brevity
iter.next();
}
assert_eq!(iter.next(), Some(WebmElement::Cluster));
2017-07-01 20:55:24 +00:00
assert_eq!(iter.next(), Some(WebmElement::Timecode(1000)));
for _ in 0..30 {
// skip contents for brevity
iter.next();
}
assert_eq!(iter.next(), Some(WebmElement::Cluster));
2017-07-01 20:55:24 +00:00
assert_eq!(iter.next(), Some(WebmElement::Timecode(2000)));
for _ in 0..30 {
// skip contents for brevity
iter.next();
}
2017-06-28 05:54:30 +00:00
assert_eq!(iter.next(), Some(WebmElement::Cues));
assert_eq!(iter.next(), None);
}
}