blob: f7d0c212fc573585c989dbd5997c4b68f81af29b [file] [log] [blame] [edit]
#![cfg(feature = "mp4")]
#[macro_use]
extern crate criterion;
use std::{fs::File, io::Read, str::from_utf8};
use {
combine::{
parser::{
byte::num::be_u32,
range::{range, take},
},
stream::easy::ParseError,
*,
},
criterion::{black_box, Bencher, Criterion},
};
#[derive(Clone, PartialEq, Eq, Debug)]
struct FileType<'a> {
major_brand: &'a str,
major_brand_version: &'a [u8],
compatible_brands: Vec<&'a str>,
}
#[derive(Clone, Debug)]
enum MP4Box<'a> {
Ftyp(FileType<'a>),
Moov,
Mdat,
Free,
Skip,
Wide,
Unknown,
}
fn parse_mp4(data: &[u8]) -> Result<(Vec<MP4Box>, &[u8]), ParseError<&[u8]>> {
let brand_name = || take(4).and_then(from_utf8);
let filetype_box = (
range(&b"ftyp"[..]),
brand_name(),
take(4),
many(brand_name()),
)
.map(|(_, m, v, c)| {
MP4Box::Ftyp(FileType {
major_brand: m,
major_brand_version: v,
compatible_brands: c,
})
});
let mp4_box = be_u32().then(|offset| take(offset as usize - 4));
let mut box_parser = choice((
filetype_box,
range(&b"moov"[..]).map(|_| MP4Box::Moov),
range(&b"mdat"[..]).map(|_| MP4Box::Mdat),
range(&b"free"[..]).map(|_| MP4Box::Free),
range(&b"skip"[..]).map(|_| MP4Box::Skip),
range(&b"wide"[..]).map(|_| MP4Box::Wide),
value(MP4Box::Unknown),
));
let data_interpreter =
mp4_box.flat_map(|box_data| box_parser.easy_parse(box_data).map(|t| t.0));
many(data_interpreter).easy_parse(data)
}
fn run_test(b: &mut Bencher, data: &[u8]) {
b.iter(|| match parse_mp4(data) {
Ok(x) => black_box(x),
Err(err) => panic!("{}", err.map_range(|bytes| format!("{:?}", bytes))),
});
}
fn mp4_small_test(c: &mut Criterion) {
let mut mp4_small = Vec::new();
File::open("benches/small.mp4")
.and_then(|mut f| f.read_to_end(&mut mp4_small))
.expect("Unable to read benches/small.mp4");
c.bench_function("mp4_small", move |b| run_test(b, &mp4_small));
}
criterion_group!(mp4, mp4_small_test);
criterion_main!(mp4);