1 #![allow(dead_code)]
2 
3 use nom::{
4   branch::alt,
5   bytes::streaming::{tag, take},
6   combinator::{map, map_res},
7   error::ErrorKind,
8   multi::many0,
9   number::streaming::{be_f32, be_u16, be_u32, be_u64},
10   Err, IResult, Needed,
11 };
12 
13 use std::str;
14 
mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]>15 fn mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]> {
16   match be_u32(input) {
17     Ok((i, offset)) => {
18       let sz: usize = offset as usize;
19       if i.len() >= sz - 4 {
20         Ok((&i[(sz - 4)..], &i[0..(sz - 4)]))
21       } else {
22         Err(Err::Incomplete(Needed::new(offset as usize + 4)))
23       }
24     }
25     Err(e) => Err(e),
26   }
27 }
28 
29 #[cfg_attr(rustfmt, rustfmt_skip)]
30 #[derive(PartialEq,Eq,Debug)]
31 struct FileType<'a> {
32   major_brand:         &'a str,
33   major_brand_version: &'a [u8],
34   compatible_brands:   Vec<&'a str>
35 }
36 
37 #[cfg_attr(rustfmt, rustfmt_skip)]
38 #[allow(non_snake_case)]
39 #[derive(Debug,Clone)]
40 pub struct Mvhd32 {
41   version_flags: u32, // actually:
42   // version: u8,
43   // flags: u24       // 3 bytes
44   created_date:  u32,
45   modified_date: u32,
46   scale:         u32,
47   duration:      u32,
48   speed:         f32,
49   volume:        u16, // actually a 2 bytes decimal
50   /* 10 bytes reserved */
51   scaleA:        f32,
52   rotateB:       f32,
53   angleU:        f32,
54   rotateC:       f32,
55   scaleD:        f32,
56   angleV:        f32,
57   positionX:     f32,
58   positionY:     f32,
59   scaleW:        f32,
60   preview:       u64,
61   poster:        u32,
62   selection:     u64,
63   current_time:  u32,
64   track_id:      u32
65 }
66 
67 #[cfg_attr(rustfmt, rustfmt_skip)]
68 #[allow(non_snake_case)]
69 #[derive(Debug,Clone)]
70 pub struct Mvhd64 {
71   version_flags: u32, // actually:
72   // version: u8,
73   // flags: u24       // 3 bytes
74   created_date:  u64,
75   modified_date: u64,
76   scale:         u32,
77   duration:      u64,
78   speed:         f32,
79   volume:        u16, // actually a 2 bytes decimal
80   /* 10 bytes reserved */
81   scaleA:        f32,
82   rotateB:       f32,
83   angleU:        f32,
84   rotateC:       f32,
85   scaleD:        f32,
86   angleV:        f32,
87   positionX:     f32,
88   positionY:     f32,
89   scaleW:        f32,
90   preview:       u64,
91   poster:        u32,
92   selection:     u64,
93   current_time:  u32,
94   track_id:      u32
95 }
96 
97 #[cfg_attr(rustfmt, rustfmt_skip)]
mvhd32(i: &[u8]) -> IResult<&[u8], MvhdBox>98 fn mvhd32(i: &[u8]) -> IResult<&[u8], MvhdBox> {
99   let (i, version_flags) = be_u32(i)?;
100   let (i, created_date) =  be_u32(i)?;
101   let (i, modified_date) = be_u32(i)?;
102   let (i, scale) =         be_u32(i)?;
103   let (i, duration) =      be_u32(i)?;
104   let (i, speed) =         be_f32(i)?;
105   let (i, volume) =        be_u16(i)?; // actually a 2 bytes decimal
106   let (i, _) =             take(10_usize)(i)?;
107   let (i, scale_a) =       be_f32(i)?;
108   let (i, rotate_b) =      be_f32(i)?;
109   let (i, angle_u) =       be_f32(i)?;
110   let (i, rotate_c) =      be_f32(i)?;
111   let (i, scale_d) =       be_f32(i)?;
112   let (i, angle_v) =       be_f32(i)?;
113   let (i, position_x) =    be_f32(i)?;
114   let (i, position_y) =    be_f32(i)?;
115   let (i, scale_w) =       be_f32(i)?;
116   let (i, preview) =       be_u64(i)?;
117   let (i, poster) =        be_u32(i)?;
118   let (i, selection) =     be_u64(i)?;
119   let (i, current_time) =  be_u32(i)?;
120   let (i, track_id) =      be_u32(i)?;
121 
122   let mvhd_box = MvhdBox::M32(Mvhd32 {
123     version_flags,
124     created_date,
125     modified_date,
126     scale,
127     duration,
128     speed,
129     volume,
130     scaleA:    scale_a,
131     rotateB:   rotate_b,
132     angleU:    angle_u,
133     rotateC:   rotate_c,
134     scaleD:    scale_d,
135     angleV:    angle_v,
136     positionX: position_x,
137     positionY: position_y,
138     scaleW:    scale_w,
139     preview,
140     poster,
141     selection,
142     current_time,
143     track_id,
144   });
145 
146   Ok((i, mvhd_box))
147 }
148 
149 #[cfg_attr(rustfmt, rustfmt_skip)]
mvhd64(i: &[u8]) -> IResult<&[u8], MvhdBox>150 fn mvhd64(i: &[u8]) -> IResult<&[u8], MvhdBox> {
151   let (i, version_flags) = be_u32(i)?;
152   let (i, created_date) =  be_u64(i)?;
153   let (i, modified_date) = be_u64(i)?;
154   let (i, scale) =         be_u32(i)?;
155   let (i, duration) =      be_u64(i)?;
156   let (i, speed) =         be_f32(i)?;
157   let (i, volume) =        be_u16(i)?; // actually a 2 bytes decimal
158   let (i, _) =             take(10_usize)(i)?;
159   let (i, scale_a) =       be_f32(i)?;
160   let (i, rotate_b) =      be_f32(i)?;
161   let (i, angle_u) =       be_f32(i)?;
162   let (i, rotate_c) =      be_f32(i)?;
163   let (i, scale_d) =       be_f32(i)?;
164   let (i, angle_v) =       be_f32(i)?;
165   let (i, position_x) =    be_f32(i)?;
166   let (i, position_y) =    be_f32(i)?;
167   let (i, scale_w) =       be_f32(i)?;
168   let (i, preview) =       be_u64(i)?;
169   let (i, poster) =        be_u32(i)?;
170   let (i, selection) =     be_u64(i)?;
171   let (i, current_time) =  be_u32(i)?;
172   let (i, track_id) =      be_u32(i)?;
173 
174   let mvhd_box = MvhdBox::M64(Mvhd64 {
175     version_flags,
176     created_date,
177     modified_date,
178     scale,
179     duration,
180     speed,
181     volume,
182     scaleA:    scale_a,
183     rotateB:   rotate_b,
184     angleU:    angle_u,
185     rotateC:   rotate_c,
186     scaleD:    scale_d,
187     angleV:    angle_v,
188     positionX: position_x,
189     positionY: position_y,
190     scaleW:    scale_w,
191     preview,
192     poster,
193     selection,
194     current_time,
195     track_id,
196   });
197 
198   Ok((i, mvhd_box))
199 }
200 
201 #[derive(Debug, Clone)]
202 pub enum MvhdBox {
203   M32(Mvhd32),
204   M64(Mvhd64),
205 }
206 
207 #[derive(Debug, Clone)]
208 pub enum MoovBox {
209   Mdra,
210   Dref,
211   Cmov,
212   Rmra,
213   Iods,
214   Mvhd(MvhdBox),
215   Clip,
216   Trak,
217   Udta,
218 }
219 
220 #[derive(Debug)]
221 enum MP4BoxType {
222   Ftyp,
223   Moov,
224   Mdat,
225   Free,
226   Skip,
227   Wide,
228   Mdra,
229   Dref,
230   Cmov,
231   Rmra,
232   Iods,
233   Mvhd,
234   Clip,
235   Trak,
236   Udta,
237   Unknown,
238 }
239 
240 #[derive(Debug)]
241 struct MP4BoxHeader {
242   length: u32,
243   tag: MP4BoxType,
244 }
245 
brand_name(input: &[u8]) -> IResult<&[u8], &str>246 fn brand_name(input: &[u8]) -> IResult<&[u8], &str> {
247   map_res(take(4_usize), str::from_utf8)(input)
248 }
249 
filetype_parser(input: &[u8]) -> IResult<&[u8], FileType<'_>>250 fn filetype_parser(input: &[u8]) -> IResult<&[u8], FileType<'_>> {
251   let (i, name) = brand_name(input)?;
252   let (i, version) = take(4_usize)(i)?;
253   let (i, brands) = many0(brand_name)(i)?;
254 
255   let ft = FileType {
256     major_brand: name,
257     major_brand_version: version,
258     compatible_brands: brands,
259   };
260   Ok((i, ft))
261 }
262 
mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox>263 fn mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> {
264   let res = if input.len() < 100 {
265     Err(Err::Incomplete(Needed::new(100)))
266   } else if input.len() == 100 {
267     mvhd32(input)
268   } else if input.len() == 112 {
269     mvhd64(input)
270   } else {
271     Err(Err::Error(nom::error_position!(input, ErrorKind::TooLarge)))
272   };
273   println!("res: {:?}", res);
274   res
275 }
276 
unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType>277 fn unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
278   Ok((input, MP4BoxType::Unknown))
279 }
280 
box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType>281 fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
282   alt((
283     map(tag("ftyp"), |_| MP4BoxType::Ftyp),
284     map(tag("moov"), |_| MP4BoxType::Moov),
285     map(tag("mdat"), |_| MP4BoxType::Mdat),
286     map(tag("free"), |_| MP4BoxType::Free),
287     map(tag("skip"), |_| MP4BoxType::Skip),
288     map(tag("wide"), |_| MP4BoxType::Wide),
289     unknown_box_type,
290   ))(input)
291 }
292 
293 // warning, an alt combinator with 9 branches containing a tag combinator
294 // can make the compilation very slow. Use functions as sub parsers,
295 // or split into multiple alt parsers if it gets slow
moov_type(input: &[u8]) -> IResult<&[u8], MP4BoxType>296 fn moov_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
297   alt((
298     map(tag("mdra"), |_| MP4BoxType::Mdra),
299     map(tag("dref"), |_| MP4BoxType::Dref),
300     map(tag("cmov"), |_| MP4BoxType::Cmov),
301     map(tag("rmra"), |_| MP4BoxType::Rmra),
302     map(tag("iods"), |_| MP4BoxType::Iods),
303     map(tag("mvhd"), |_| MP4BoxType::Mvhd),
304     map(tag("clip"), |_| MP4BoxType::Clip),
305     map(tag("trak"), |_| MP4BoxType::Trak),
306     map(tag("udta"), |_| MP4BoxType::Udta),
307   ))(input)
308 }
309 
box_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader>310 fn box_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader> {
311   let (i, length) = be_u32(input)?;
312   let (i, tag) = box_type(i)?;
313   Ok((i, MP4BoxHeader { length, tag }))
314 }
315 
moov_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader>316 fn moov_header(input: &[u8]) -> IResult<&[u8], MP4BoxHeader> {
317   let (i, length) = be_u32(input)?;
318   let (i, tag) = moov_type(i)?;
319   Ok((i, MP4BoxHeader { length, tag }))
320 }
321