1 #![cfg(feature = "mp4")]
2 #[macro_use]
3 extern crate criterion;
4
5 use std::{fs::File, io::Read, str::from_utf8};
6
7 use {
8 combine::{
9 parser::{
10 byte::num::be_u32,
11 range::{range, take},
12 },
13 stream::easy::ParseError,
14 *,
15 },
16 criterion::{black_box, Bencher, Criterion},
17 };
18
19 #[derive(Clone, PartialEq, Eq, Debug)]
20 struct FileType<'a> {
21 major_brand: &'a str,
22 major_brand_version: &'a [u8],
23 compatible_brands: Vec<&'a str>,
24 }
25
26 #[derive(Clone, Debug)]
27 enum MP4Box<'a> {
28 Ftyp(FileType<'a>),
29 Moov,
30 Mdat,
31 Free,
32 Skip,
33 Wide,
34 Unknown,
35 }
36
parse_mp4(data: &[u8]) -> Result<(Vec<MP4Box>, &[u8]), ParseError<&[u8]>>37 fn parse_mp4(data: &[u8]) -> Result<(Vec<MP4Box>, &[u8]), ParseError<&[u8]>> {
38 let brand_name = || take(4).and_then(from_utf8);
39 let filetype_box = (
40 range(&b"ftyp"[..]),
41 brand_name(),
42 take(4),
43 many(brand_name()),
44 )
45 .map(|(_, m, v, c)| {
46 MP4Box::Ftyp(FileType {
47 major_brand: m,
48 major_brand_version: v,
49 compatible_brands: c,
50 })
51 });
52
53 let mp4_box = be_u32().then(|offset| take(offset as usize - 4));
54 let mut box_parser = choice((
55 filetype_box,
56 range(&b"moov"[..]).map(|_| MP4Box::Moov),
57 range(&b"mdat"[..]).map(|_| MP4Box::Mdat),
58 range(&b"free"[..]).map(|_| MP4Box::Free),
59 range(&b"skip"[..]).map(|_| MP4Box::Skip),
60 range(&b"wide"[..]).map(|_| MP4Box::Wide),
61 value(MP4Box::Unknown),
62 ));
63 let data_interpreter =
64 mp4_box.flat_map(|box_data| box_parser.easy_parse(box_data).map(|t| t.0));
65
66 many(data_interpreter).easy_parse(data)
67 }
68
run_test(b: &mut Bencher, data: &[u8])69 fn run_test(b: &mut Bencher, data: &[u8]) {
70 b.iter(|| match parse_mp4(data) {
71 Ok(x) => black_box(x),
72 Err(err) => panic!("{}", err.map_range(|bytes| format!("{:?}", bytes))),
73 });
74 }
75
mp4_small_test(c: &mut Criterion)76 fn mp4_small_test(c: &mut Criterion) {
77 let mut mp4_small = Vec::new();
78 File::open("benches/small.mp4")
79 .and_then(|mut f| f.read_to_end(&mut mp4_small))
80 .expect("Unable to read benches/small.mp4");
81
82 c.bench_function("mp4_small", move |b| run_test(b, &mp4_small));
83 }
84
85 criterion_group!(mp4, mp4_small_test);
86 criterion_main!(mp4);
87