#![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, &[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);