1 #![cfg(feature = "stream")]
2 #![allow(dead_code)]
3
4 #[macro_use]
5 extern crate nom;
6
7 use nom::{IResult, Needed, be_f32, be_u16, be_u32, be_u64};
8 //use nom::{Consumer,ConsumerState,Move,Input,Producer,FileProducer,FileProducerState};
9 //use nom::IResult;
10 use nom::{Err, ErrorKind};
11
12 use std::str;
13
mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]>14 fn mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]> {
15 match be_u32(input) {
16 Ok((i, offset)) => {
17 let sz: usize = offset as usize;
18 if i.len() >= sz - 4 {
19 Ok((&i[(sz - 4)..], &i[0..(sz - 4)]))
20 } else {
21 Err(Err::Incomplete(Needed::Size(offset as usize + 4)))
22 }
23 }
24 Err(e) => Err(e),
25 }
26 }
27
28 #[cfg_attr(rustfmt, rustfmt_skip)]
29 #[derive(PartialEq,Eq,Debug)]
30 struct FileType<'a> {
31 major_brand: &'a str,
32 major_brand_version: &'a [u8],
33 compatible_brands: Vec<&'a str>
34 }
35
36 #[cfg_attr(rustfmt, rustfmt_skip)]
37 #[allow(non_snake_case)]
38 #[derive(Debug,Clone)]
39 pub struct Mvhd32 {
40 version_flags: u32, // actually:
41 // version: u8,
42 // flags: u24 // 3 bytes
43 created_date: u32,
44 modified_date: u32,
45 scale: u32,
46 duration: u32,
47 speed: f32,
48 volume: u16, // actually a 2 bytes decimal
49 /* 10 bytes reserved */
50 scaleA: f32,
51 rotateB: f32,
52 angleU: f32,
53 rotateC: f32,
54 scaleD: f32,
55 angleV: f32,
56 positionX: f32,
57 positionY: f32,
58 scaleW: f32,
59 preview: u64,
60 poster: u32,
61 selection: u64,
62 current_time: u32,
63 track_id: u32
64 }
65
66 #[cfg_attr(rustfmt, rustfmt_skip)]
67 #[allow(non_snake_case)]
68 #[derive(Debug,Clone)]
69 pub struct Mvhd64 {
70 version_flags: u32, // actually:
71 // version: u8,
72 // flags: u24 // 3 bytes
73 created_date: u64,
74 modified_date: u64,
75 scale: u32,
76 duration: u64,
77 speed: f32,
78 volume: u16, // actually a 2 bytes decimal
79 /* 10 bytes reserved */
80 scaleA: f32,
81 rotateB: f32,
82 angleU: f32,
83 rotateC: f32,
84 scaleD: f32,
85 angleV: f32,
86 positionX: f32,
87 positionY: f32,
88 scaleW: f32,
89 preview: u64,
90 poster: u32,
91 selection: u64,
92 current_time: u32,
93 track_id: u32
94 }
95
96 #[allow(non_snake_case)]
97 named!(mvhd32 <&[u8], MvhdBox>,
98 do_parse!(
99 version_flags: be_u32 >>
100 created_date: be_u32 >>
101 modified_date: be_u32 >>
102 scale: be_u32 >>
103 duration: be_u32 >>
104 speed: be_f32 >>
105 volume: be_u16 >> // actually a 2 bytes decimal
106 take!(10) >>
107 scale_a: be_f32 >>
108 rotate_b: be_f32 >>
109 angle_u: be_f32 >>
110 rotate_c: be_f32 >>
111 scale_d: be_f32 >>
112 angle_v: be_f32 >>
113 position_x: be_f32 >>
114 position_y: be_f32 >>
115 scale_w: be_f32 >>
116 preview: be_u64 >>
117 poster: be_u32 >>
118 selection: be_u64 >>
119 current_time: be_u32 >>
120 track_id: be_u32 >>
121 (
122 MvhdBox::M32(Mvhd32 {
123 version_flags: version_flags,
124 created_date: created_date,
125 modified_date: modified_date,
126 scale: scale,
127 duration: duration,
128 speed: speed,
129 volume: 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: preview,
140 poster: poster,
141 selection: selection,
142 current_time: current_time,
143 track_id: track_id
144 })
145 ))
146 );
147
148 #[allow(non_snake_case)]
149 named!(mvhd64 <&[u8], MvhdBox>,
150 do_parse!(
151 version_flags: be_u32 >>
152 created_date: be_u64 >>
153 modified_date: be_u64 >>
154 scale: be_u32 >>
155 duration: be_u64 >>
156 speed: be_f32 >>
157 volume: be_u16 >> // actually a 2 bytes decimal
158 take!(10) >>
159 scale_a: be_f32 >>
160 rotate_b: be_f32 >>
161 angle_u: be_f32 >>
162 rotate_c: be_f32 >>
163 scale_d: be_f32 >>
164 angle_v: be_f32 >>
165 position_x: be_f32 >>
166 position_y: be_f32 >>
167 scale_w: be_f32 >>
168 preview: be_u64 >>
169 poster: be_u32 >>
170 selection: be_u64 >>
171 current_time: be_u32 >>
172 track_id: be_u32 >>
173 (
174 MvhdBox::M64(Mvhd64 {
175 version_flags: version_flags,
176 created_date: created_date,
177 modified_date: modified_date,
178 scale: scale,
179 duration: duration,
180 speed: speed,
181 volume: 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: preview,
192 poster: poster,
193 selection: selection,
194 current_time: current_time,
195 track_id: track_id
196 })
197 ))
198 );
199
200 #[derive(Debug, Clone)]
201 pub enum MvhdBox {
202 M32(Mvhd32),
203 M64(Mvhd64),
204 }
205
206 #[derive(Debug, Clone)]
207 pub enum MoovBox {
208 Mdra,
209 Dref,
210 Cmov,
211 Rmra,
212 Iods,
213 Mvhd(MvhdBox),
214 Clip,
215 Trak,
216 Udta,
217 }
218
219 #[derive(Debug)]
220 enum MP4BoxType {
221 Ftyp,
222 Moov,
223 Mdat,
224 Free,
225 Skip,
226 Wide,
227 Mdra,
228 Dref,
229 Cmov,
230 Rmra,
231 Iods,
232 Mvhd,
233 Clip,
234 Trak,
235 Udta,
236 Unknown,
237 }
238
239 #[derive(Debug)]
240 struct MP4BoxHeader {
241 length: u32,
242 tag: MP4BoxType,
243 }
244
245 named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8));
246
247 named!(filetype_parser<&[u8], FileType>,
248 do_parse!(
249 m: brand_name >>
250 v: take!(4) >>
251 c: many0!(brand_name) >>
252 (FileType{ major_brand: m, major_brand_version:v, compatible_brands: c })
253 )
254 );
255
mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox>256 fn mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> {
257 let res = if input.len() < 100 {
258 Err(Err::Incomplete(Needed::Size(100)))
259 } else if input.len() == 100 {
260 mvhd32(input)
261 } else if input.len() == 112 {
262 mvhd64(input)
263 } else {
264 Err(Err::Error(error_position!(input, ErrorKind::Custom(32u32))))
265 };
266 println!("res: {:?}", res);
267 res
268 }
269
unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType>270 fn unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
271 Ok((input, MP4BoxType::Unknown))
272 }
273
274 //named!(box_type<&[u8], MP4BoxType>,
box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType, u32>275 fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType, u32> {
276 alt!(input,
277 tag!("ftyp") => { |_| MP4BoxType::Ftyp } |
278 tag!("moov") => { |_| MP4BoxType::Moov } |
279 tag!("mdat") => { |_| MP4BoxType::Mdat } |
280 tag!("free") => { |_| MP4BoxType::Free } |
281 tag!("skip") => { |_| MP4BoxType::Skip } |
282 tag!("wide") => { |_| MP4BoxType::Wide } |
283 unknown_box_type
284 )
285 }
286
287 // warning, an alt combinator with 9 branches containing a tag combinator
288 // can make the compilation very slow. Use functions as sub parsers,
289 // or split into multiple alt! parsers if it gets slow
290 named!(moov_type<&[u8], MP4BoxType>,
291 alt!(
292 tag!("mdra") => { |_| MP4BoxType::Mdra } |
293 tag!("dref") => { |_| MP4BoxType::Dref } |
294 tag!("cmov") => { |_| MP4BoxType::Cmov } |
295 tag!("rmra") => { |_| MP4BoxType::Rmra } |
296 tag!("iods") => { |_| MP4BoxType::Iods } |
297 tag!("mvhd") => { |_| MP4BoxType::Mvhd } |
298 tag!("clip") => { |_| MP4BoxType::Clip } |
299 tag!("trak") => { |_| MP4BoxType::Trak } |
300 tag!("udta") => { |_| MP4BoxType::Udta }
301 )
302 );
303
304 named!(box_header<&[u8],MP4BoxHeader>,
305 do_parse!(
306 length: be_u32 >>
307 tag: box_type >>
308 (MP4BoxHeader{ length: length, tag: tag})
309 )
310 );
311
312 named!(moov_header<&[u8],MP4BoxHeader>,
313 do_parse!(
314 length: be_u32 >>
315 tag: moov_type >>
316 (MP4BoxHeader{ length: length, tag: tag})
317 )
318 );
319
320 /*
321 #[derive(Debug,PartialEq,Eq)]
322 enum MP4State {
323 Main,
324 Moov,
325 Mvhd(usize)
326 }
327
328 pub struct MP4Consumer {
329 state: MP4State,
330 moov_bytes: usize,
331 c_state: ConsumerState<(), (), Move>
332 }
333
334 impl MP4Consumer {
335 fn new() -> MP4Consumer {
336 MP4Consumer { state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0)) }
337 }
338
339 fn consume_main(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> {
340 //println!("\nparsing box header:\n{}", input.to_hex(8));
341 match input {
342 Input::Eof(None) => ConsumerState::Done(Move::Consume(0), ()),
343 Input::Empty => ConsumerState::Continue(Move::Consume(0)),
344 Input::Element(sl) | Input::Eof(Some(sl)) => {
345 match box_header(sl) {
346 Ok((i, header)) => {
347 match header.tag {
348 MP4BoxType::Ftyp => {
349 println!("-> FTYP");
350 match filetype_parser(&i[0..(header.length as usize - 8)]) {
351 Ok((rest, filetype_header)) => {
352 println!("filetype header: {:?}", filetype_header);
353 //return ConsumerState::Await(header.length as usize, header.length as usize - 8);
354 return ConsumerState::Continue(Move::Consume(sl.offset(rest)));
355 }
356 Err(Err::Error(a)) => {
357 println!("ftyp parsing error: {:?}", a);
358 assert!(false);
359 return ConsumerState::Error(());
360 },
361 Err(Err::Incomplete(n)) => {
362 println!("ftyp incomplete -> await: {}", sl.len());
363 return ConsumerState::Continue(Move::Await(n));
364 //return ConsumerState::Await(0, input.len() + 100);
365 }
366 }
367 },
368 MP4BoxType::Moov => {
369 println!("-> MOOV");
370 self.state = MP4State::Moov;
371 self.moov_bytes = header.length as usize - 8;
372 return ConsumerState::Continue(Move::Consume(sl.offset(i)));
373 },
374 MP4BoxType::Mdat => println!("-> MDAT"),
375 MP4BoxType::Free => println!("-> FREE"),
376 MP4BoxType::Skip => println!("-> SKIP"),
377 MP4BoxType::Wide => println!("-> WIDE"),
378 MP4BoxType::Unknown => {
379 println!("-> UNKNOWN");
380 println!("bytes:\n{}", (sl).to_hex(8));
381 //return ConsumerState::Continue(Move::Consume(sl.offset(i)));
382 },
383 _ => { println!("invalid"); return ConsumerState::Error(())}
384 }
385 return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64)))
386 },
387 Err(Err::Error(a)) => {
388 println!("mp4 parsing error: {:?}", a);
389 assert!(false);
390 return ConsumerState::Error(());
391 },
392 Err(Err::Incomplete(i)) => {
393 // FIXME: incomplete should send the required size
394 println!("mp4 incomplete -> await: {}", sl.len());
395 return ConsumerState::Continue(Move::Await(i));
396 }
397 }
398 }
399 }
400 }
401
402 fn consume_moov(&mut self, input: Input<&[u8]>) -> ConsumerState<(), (), Move> {
403 //println!("\nparsing moov box(remaining {} bytes):\n{}", self.moov_bytes, input.to_hex(8));
404 match input {
405 Input::Eof(None) => return ConsumerState::Error(()),
406 Input::Empty => return ConsumerState::Continue(Move::Consume(0)),
407 Input::Element(sl) | Input::Eof(Some(sl)) => {
408 if self.moov_bytes == 0 {
409 //println!("finished parsing moov atom, continuing with main parser");
410 self.state = MP4State::Main;
411 return ConsumerState::Continue(Move::Consume(0));
412 }
413 match moov_header(sl) {
414 Ok((i, header)) => {
415 match header.tag {
416 MP4BoxType::Mvhd => {
417 println!("-> MVHD");
418 self.state = MP4State::Mvhd(header.length as usize - 8);
419 // TODO: check for overflow here
420 self.moov_bytes = self.moov_bytes - (sl.len() - i.len());
421 println!("remaining moov_bytes: {}", self.moov_bytes);
422 return ConsumerState::Continue(Move::Consume(sl.offset(i)));
423 },
424 MP4BoxType::Wide => println!("-> WIDE"),
425 MP4BoxType::Mdra => println!("-> MDRA"),
426 MP4BoxType::Dref => println!("-> DREF"),
427 MP4BoxType::Cmov => println!("-> CMOV"),
428 MP4BoxType::Rmra => println!("-> RMRA"),
429 MP4BoxType::Iods => println!("-> IODS"),
430 MP4BoxType::Clip => println!("-> CLIP"),
431 MP4BoxType::Trak => println!("-> TRAK"),
432 MP4BoxType::Udta => println!("-> UDTA"),
433 MP4BoxType::Unknown => println!("-> MOOV UNKNOWN"),
434 _ => { println!("invalid header here: {:?}", header.tag); return ConsumerState::Error(());}
435 };
436 // TODO: check for overflow here
437 self.moov_bytes = self.moov_bytes - header.length as usize;
438 println!("remaining moov_bytes: {}", self.moov_bytes);
439 return ConsumerState::Continue(Move::Seek(SeekFrom::Current((header.length) as i64)))
440 },
441 Err(Err::Error(a)) => {
442 println!("moov parsing error: {:?}", a);
443 println!("data:\n{}", sl.to_hex(8));
444 assert!(false);
445 return ConsumerState::Error(());
446 },
447 Err(Err::Incomplete(i)) => {
448 println!("moov incomplete -> await: {}", sl.len());
449 return ConsumerState::Continue(Move::Await(i));
450 }
451 }
452 }
453 };
454 }
455
456 }
457
458 consumer_from_parser!(MvhdConsumer<MvhdBox>, mvhd_box);
459
460 impl<'a> Consumer<&'a[u8], (), (), Move> for MP4Consumer {
461 fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState<(), (), Move> {
462 match self.state {
463 MP4State::Main => {
464 self.c_state = self.consume_main(input);
465 },
466 MP4State::Moov => {
467 self.c_state = self.consume_moov(input);
468 },
469 MP4State::Mvhd(sz) => {
470 match input {
471 Input::Eof(None) => self.c_state = ConsumerState::Error(()),
472 Input::Empty => self.c_state = ConsumerState::Continue(Move::Consume(0)),
473 Input::Element(sl) | Input::Eof(Some(sl)) => {
474 let mut c = MvhdConsumer{ state:ConsumerState::Continue(Move::Consume(0)) };
475 self.c_state = c.handle(Input::Element(&sl[..sz])).flat_map(|m, _| {
476 self.state = MP4State::Moov;
477 ConsumerState::Continue(m)
478 });
479 println!("found mvhd?: {:?}", c.state());
480 match self.c_state {
481 ConsumerState::Continue(Move::Consume(sz)) => self.moov_bytes = self.moov_bytes - sz,
482 ConsumerState::Continue(Move::Seek(SeekFrom::Current(sz))) => self.moov_bytes = self.moov_bytes - (sz as usize),
483 _ => ()
484 };
485 println!("remaining moov_bytes: {}", self.moov_bytes);
486 }
487 }
488 }
489 };
490 &self.c_state
491 }
492
493 fn state(&self) -> &ConsumerState<(), (), Move> {
494 &self.c_state
495 }
496 }
497
498 #[allow(unused_must_use)]
499 fn explore_mp4_file(filename: &str) {
500 let mut p = FileProducer::new(filename, 400).unwrap();
501 let mut c = MP4Consumer{state: MP4State::Main, moov_bytes: 0, c_state: ConsumerState::Continue(Move::Consume(0))};
502 //c.run(&mut p);
503 while let &ConsumerState::Continue(mv) = p.apply(&mut c) {
504 println!("move: {:?}", mv);
505 }
506 println!("last consumer state: {:?} | last state: {:?}", c.c_state, c.state);
507
508 if let ConsumerState::Done(Move::Consume(0), ()) = c.c_state {
509 println!("consumer state ok");
510 } else {
511 assert!(false, "consumer should have reached Done state");
512 }
513 assert_eq!(c.state, MP4State::Main);
514 assert_eq!(p.state(), FileProducerState::Eof);
515 //assert!(false);
516 }
517
518
519 #[test]
520 fn small_test() {
521 explore_mp4_file("assets/small.mp4");
522 }
523
524
525 #[test]
526 fn big_bunny_test() {
527 explore_mp4_file("assets/bigbuckbunny.mp4");
528 }
529 */
530