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