1 #![allow(dead_code)]
2
3 #[macro_use]
4 extern crate nom;
5
6 use nom::{
7 error::ErrorKind,
8 number::streaming::{be_f32, be_u16, be_u32, be_u64},
9 Err, IResult, Needed,
10 };
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::new(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::new(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::TooLarge)))
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>275 fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> {
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