nom 0.3.9

A byte oriented, zero copy, parser combinators library
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
From 11d91c27d5d69426877a193cf9dea59df4856ea3 Mon Sep 17 00:00:00 2001
From: Ralph Giles <giles@mozilla.com>
Date: Wed, 10 Jun 2015 12:51:14 -0700
Subject: Bug 1161350 - Import mp4parse v0.0.8 source. r=k17e

Source from https://notabug.org/rillian/mp4parse-rust

diff --git a/media/libstagefright/binding/MP4Metadata.rs b/media/libstagefright/binding/MP4Metadata.rs
new file mode 100644
index 0000000..83b28cb
--- /dev/null
+++ b/media/libstagefright/binding/MP4Metadata.rs
@@ -0,0 +1,389 @@
+// Module for parsing ISO Base Media Format aka video/mp4 streams.
+
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+/// Basic ISO box structure.
+pub struct BoxHeader {
+    /// Four character box type
+pub name: u32,
+    /// Size of the box in bytes
+pub size: u64,
+    /// Offset to the start of the contained data (or header size).
+pub offset: u64,
+}
+
+/// File type box 'ftyp'.
+pub struct FileTypeBox {
+    name: u32,
+    size: u64,
+    major_brand: u32,
+    minor_version: u32,
+    compatible_brands: Vec<u32>,
+}
+
+/// Movie header box 'mvhd'.
+pub struct MovieHeaderBox {
+    pub name: u32,
+    pub size: u64,
+    pub timescale: u32,
+    pub duration: u64,
+    // Ignore other fields.
+}
+
+pub struct TrackHeaderBox {
+    pub name: u32,
+    pub size: u64,
+    pub track_id: u32,
+    pub duration: u64,
+    pub width: u32,
+    pub height: u32,
+}
+
+extern crate byteorder;
+use byteorder::{BigEndian, ReadBytesExt};
+use std::io::{Read, Result, Seek, SeekFrom, Take};
+use std::io::Cursor;
+
+/// Parse a box out of a data buffer.
+pub fn read_box_header<T: ReadBytesExt>(src: &mut T) -> Result<BoxHeader> {
+    let tmp_size = try!(src.read_u32::<BigEndian>());
+    let name = try!(src.read_u32::<BigEndian>());
+    let size = match tmp_size {
+        1 => try!(src.read_u64::<BigEndian>()),
+        _ => tmp_size as u64,
+    };
+    assert!(size >= 8);
+    if tmp_size == 1 {
+        assert!(size >= 16);
+    }
+    let offset = match tmp_size {
+        1 => 4 + 4 + 8,
+        _ => 4 + 4,
+    };
+    assert!(offset <= size);
+    Ok(BoxHeader{
+      name: name,
+      size: size,
+      offset: offset,
+    })
+}
+
+/// Parse the extra header fields for a full box.
+fn read_fullbox_extra<T: ReadBytesExt>(src: &mut T) -> (u8, u32) {
+    let version = src.read_u8().unwrap();
+    let flags_a = src.read_u8().unwrap();
+    let flags_b = src.read_u8().unwrap();
+    let flags_c = src.read_u8().unwrap();
+    (version, (flags_a as u32) << 16 |
+              (flags_b as u32) <<  8 |
+              (flags_c as u32))
+}
+
+/// Skip over the contents of a box.
+pub fn skip_box_content<T: ReadBytesExt + Seek>
+  (src: &mut T, header: &BoxHeader)
+  -> std::io::Result<u64>
+{
+    src.seek(SeekFrom::Current((header.size - header.offset) as i64))
+}
+
+/// Helper to construct a Take over the contents of a box.
+fn limit<'a, T: Read>(f: &'a mut T, h: &BoxHeader) -> Take<&'a mut T> {
+    f.take(h.size - h.offset)
+}
+
+/// Helper to construct a Cursor over the contents of a box.
+fn recurse<T: Read>(f: &mut T, h: &BoxHeader) {
+    println!("{} -- recursing", h);
+    // FIXME: I couldn't figure out how to do this without copying.
+    // We use Seek on the Read we return in skip_box_content, but
+    // that trait isn't implemented for a Take like our limit()
+    // returns. Slurping the buffer and wrapping it in a Cursor
+    // functions as a work around.
+    let buf: Vec<u8> = limit(f, &h)
+        .bytes()
+        .map(|u| u.unwrap())
+        .collect();
+    let mut content = Cursor::new(buf);
+    loop {
+        match read_box(&mut content) {
+            Ok(_) => {},
+            Err(e) => {
+                println!("Error '{:?}' reading box", e.kind());
+                break;
+            },
+        }
+    }
+    println!("{} -- end", h);
+}
+
+/// Read the contents of a box, including sub boxes.
+/// Right now it just prints the box value rather than
+/// returning anything.
+pub fn read_box<T: Read + Seek>(f: &mut T) -> Result<()> {
+    read_box_header(f).and_then(|h| {
+        match &(fourcc_to_string(h.name))[..] {
+            "ftyp" => {
+                let mut content = limit(f, &h);
+                let ftyp = read_ftyp(&mut content, &h).unwrap();
+                println!("{}", ftyp);
+            },
+            "moov" => recurse(f, &h),
+            "mvhd" => {
+                let mut content = limit(f, &h);
+                let mvhd = read_mvhd(&mut content, &h).unwrap();
+                println!("  {}", mvhd);
+            },
+            "trak" => recurse(f, &h),
+            "tkhd" => {
+                let mut content = limit(f, &h);
+                let tkhd = read_tkhd(&mut content, &h).unwrap();
+                println!("  {}", tkhd);
+            },
+            _ => {
+                // Skip the contents of unknown chunks.
+                println!("{} (skipped)", h);
+                skip_box_content(f, &h).unwrap();
+            },
+        };
+        Ok(()) // and_then needs a Result to return.
+    })
+}
+
+/// Entry point for C language callers.
+/// Take a buffer and call read_box() on it.
+#[no_mangle]
+pub unsafe extern fn read_box_from_buffer(buffer: *const u8, size: usize)
+  -> bool {
+    use std::slice;
+    use std::thread;
+
+    // Validate arguments from C.
+    if buffer.is_null() || size < 8 {
+        return false;
+    }
+
+    // Wrap the buffer we've been give in a slice.
+    let b = slice::from_raw_parts(buffer, size);
+    let mut c = Cursor::new(b);
+
+    // Parse in a subthread.
+    let task = thread::spawn(move || {
+        read_box(&mut c).unwrap();
+    });
+    // Catch any panics.
+    task.join().is_ok()
+}
+
+
+/// Parse an ftype box.
+pub fn read_ftyp<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
+  -> Option<FileTypeBox> {
+    let major = src.read_u32::<BigEndian>().unwrap();
+    let minor = src.read_u32::<BigEndian>().unwrap();
+    let brand_count = (head.size - 8 - 8) /4;
+    let mut brands = Vec::new();
+    for _ in 0..brand_count {
+        brands.push(src.read_u32::<BigEndian>().unwrap());
+    }
+    Some(FileTypeBox{
+        name: head.name,
+        size: head.size,
+        major_brand: major,
+        minor_version: minor,
+        compatible_brands: brands,
+    })
+}
+
+/// Parse an mvhd box.
+pub fn read_mvhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
+  -> Option<MovieHeaderBox> {
+    let (version, _) = read_fullbox_extra(src);
+    match version {
+        1 => {
+            // 64 bit creation and modification times.
+            let mut skip: Vec<u8> = vec![0; 16];
+            let r = src.read(&mut skip).unwrap();
+            assert!(r == skip.len());
+        },
+        0 => {
+            // 32 bit creation and modification times.
+            // 64 bit creation and modification times.
+            let mut skip: Vec<u8> = vec![0; 8];
+            let r = src.read(&mut skip).unwrap();
+            assert!(r == skip.len());
+        },
+        _ => panic!("invalid mhdr version"),
+    }
+    let timescale = src.read_u32::<BigEndian>().unwrap();
+    let duration = match version {
+        1 => src.read_u64::<BigEndian>().unwrap(),
+        0 => src.read_u32::<BigEndian>().unwrap() as u64,
+        _ => panic!("invalid mhdr version"),
+    };
+    // Skip remaining fields.
+    let mut skip: Vec<u8> = vec![0; 80];
+    let r = src.read(&mut skip).unwrap();
+    assert!(r == skip.len());
+    Some(MovieHeaderBox {
+        name: head.name,
+        size: head.size,
+        timescale: timescale,
+        duration: duration,
+    })
+}
+
+/// Parse a tkhd box.
+pub fn read_tkhd<T: ReadBytesExt>(src: &mut T, head: &BoxHeader)
+  -> Option<TrackHeaderBox> {
+    let (version, flags) = read_fullbox_extra(src);
+    if flags & 0x1u32 == 0 || flags & 0x2u32 == 0 {
+        // Track is disabled.
+        return None;
+    }
+    match version {
+        1 => {
+            // 64 bit creation and modification times.
+            let mut skip: Vec<u8> = vec![0; 16];
+            let r = src.read(&mut skip).unwrap();
+            assert!(r == skip.len());
+        },
+        0 => {
+            // 32 bit creation and modification times.
+            // 64 bit creation and modification times.
+            let mut skip: Vec<u8> = vec![0; 8];
+            let r = src.read(&mut skip).unwrap();
+            assert!(r == skip.len());
+        },
+        _ => panic!("invalid tkhd version"),
+    }
+    let track_id = src.read_u32::<BigEndian>().unwrap();
+    let _reserved = src.read_u32::<BigEndian>().unwrap();
+    assert!(_reserved == 0);
+    let duration = match version {
+        1 => {
+            src.read_u64::<BigEndian>().unwrap()
+        },
+        0 => src.read_u32::<BigEndian>().unwrap() as u64,
+        _ => panic!("invalid tkhd version"),
+    };
+    let _reserved = src.read_u32::<BigEndian>().unwrap();
+    let _reserved = src.read_u32::<BigEndian>().unwrap();
+    // Skip uninterested fields.
+    let mut skip: Vec<u8> = vec![0; 44];
+    let r = src.read(&mut skip).unwrap();
+    assert!(r == skip.len());
+    let width = src.read_u32::<BigEndian>().unwrap();
+    let height = src.read_u32::<BigEndian>().unwrap();
+    Some(TrackHeaderBox {
+        name: head.name,
+        size: head.size,
+        track_id: track_id,
+        duration: duration,
+        width: width,
+        height: height,
+    })
+}
+
+/// Convert the iso box type or other 4-character value to a string.
+fn fourcc_to_string(name: u32) -> String {
+    let u32_to_vec = |u| {
+        vec!((u >> 24 & 0xffu32) as u8,
+             (u >> 16 & 0xffu32) as u8,
+             (u >>  8 & 0xffu32) as u8,
+             (u & 0xffu32) as u8)
+    };
+    let name_bytes = u32_to_vec(name);
+    String::from_utf8_lossy(&name_bytes).into_owned()
+}
+
+use std::fmt;
+impl fmt::Display for BoxHeader {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "'{}' {} bytes", fourcc_to_string(self.name), self.size)
+    }
+}
+
+impl fmt::Display for FileTypeBox {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let name = fourcc_to_string(self.name);
+        let brand = fourcc_to_string(self.major_brand);
+        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
+            brand, self.minor_version)
+    }
+}
+
+impl fmt::Display for MovieHeaderBox {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let name = fourcc_to_string(self.name);
+        write!(f, "'{}' {} bytes duration {}s", name, self.size,
+            (self.duration as f64)/(self.timescale as f64))
+    }
+}
+
+use std::u16;
+impl fmt::Display for TrackHeaderBox {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let name = fourcc_to_string(self.name);
+        // Dimensions are 16.16 fixed-point.
+        let base = u16::MAX as f64 + 1.0;
+        let width = (self.width as f64) / base;
+        let height = (self.height as f64) / base;
+        write!(f, "'{}' {} bytes duration {} id {} {}x{}",
+            name, self.size, self.duration, self.track_id,
+            width, height)
+    }
+}
+
+#[test]
+fn test_read_box_header() {
+    use std::io::Cursor;
+    use std::io::Write;
+    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
+    write!(&mut test, "test").unwrap(); // box type
+    let mut stream = Cursor::new(test);
+    let parsed = read_box_header(&mut stream).unwrap();
+    assert_eq!(parsed.name, 1952805748);
+    assert_eq!(parsed.size, 8);
+    println!("box {}", parsed);
+}
+
+
+#[test]
+fn test_read_box_header_long() {
+    use std::io::Cursor;
+    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
+    test.extend("long".to_string().into_bytes()); // box type
+    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
+    // Skip generating box content.
+    let mut stream = Cursor::new(test);
+    let parsed = read_box_header(&mut stream).unwrap();
+    assert_eq!(parsed.name, 1819242087);
+    assert_eq!(parsed.size, 4096);
+    println!("box {}", parsed);
+}
+
+#[test]
+fn test_read_ftyp() {
+    use std::io::Cursor;
+    use std::io::Write;
+    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
+    write!(&mut test, "ftyp").unwrap(); // type
+    write!(&mut test, "mp42").unwrap(); // major brand
+    test.extend(vec![0, 0, 0, 0]);      // minor version
+    write!(&mut test, "isom").unwrap(); // compatible brands...
+    write!(&mut test, "mp42").unwrap();
+    assert_eq!(test.len(), 24);
+
+    let mut stream = Cursor::new(test);
+    let header = read_box_header(&mut stream).unwrap();
+    let parsed = read_ftyp(&mut stream, &header).unwrap();
+    assert_eq!(parsed.name, 1718909296);
+    assert_eq!(parsed.size, 24);
+    assert_eq!(parsed.major_brand, 1836069938);
+    assert_eq!(parsed.minor_version, 0);
+    assert_eq!(parsed.compatible_brands.len(), 2);
+    println!("box {}", parsed);
+}
diff --git a/media/libstagefright/moz.build b/media/libstagefright/moz.build
index 7cf1c03..b6fa60f 100644
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -81,6 +81,11 @@ SOURCES += [
     'system/core/libutils/VectorImpl.cpp',
 ]
 
+if CONFIG['MOZ_RUST']:
+    SOURCES += [
+        'binding/MP4Metadata.rs',
+    ]
+
 UNIFIED_SOURCES += [
     'binding/Adts.cpp',
     'binding/AnnexB.cpp',
-- 
2.4.3