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