mov: skip common atoms in video codec extradata
[nihav.git] / nihav-commonfmt / src / demuxers / mov.rs
1 use nihav_core::demuxers::*;
2 use nihav_registry::register::*;
3 use nihav_core::compr::deflate::*;
4
5 macro_rules! mktag {
6 ($a:expr, $b:expr, $c:expr, $d:expr) => ({
7 (($a as u32) << 24) | (($b as u32) << 16) | (($c as u32) << 8) | ($d as u32)
8 });
9 ($arr:expr) => ({
10 (($arr[0] as u32) << 24) | (($arr[1] as u32) << 16) | (($arr[2] as u32) << 8) | ($arr[3] as u32)
11 });
12 }
13
14 trait Skip64 {
15 fn skip64(&mut self, size: u64) -> ByteIOResult<()>;
16 }
17
18 impl<'a> Skip64 for ByteReader<'a> {
19 fn skip64(&mut self, size: u64) -> ByteIOResult<()> {
20 if (size as usize as u64) != size {
21 self.seek(SeekFrom::Current(size as i64))?;
22 } else {
23 self.read_skip(size as usize)?;
24 }
25 Ok(())
26 }
27 }
28
29 fn read_chunk_header(br: &mut ByteReader) -> DemuxerResult<(u32, u64)> {
30 let size = br.read_u32be()?;
31 let ctype = br.read_u32be()?;
32 if size == 0 {
33 Ok((ctype, br.left() as u64))
34 } else if size == 1 {
35 let size64 = br.read_u64be()?;
36 validate!(size64 >= 16);
37 Ok((ctype, size64 - 16))
38 } else {
39 validate!(size >= 8);
40 Ok((ctype, (size as u64) - 8))
41 }
42 }
43
44 fn read_palette(br: &mut ByteReader, size: u64, pal: &mut [u8; 1024]) -> DemuxerResult<u64> {
45 let _seed = br.read_u32be()?;
46 let _flags = br.read_u16be()?;
47 let palsize = (br.read_u16be()? as usize) + 1;
48 validate!(palsize <= 256);
49 validate!((palsize as u64) * 8 + 8 == size);
50 for i in 0..palsize {
51 let a = br.read_u16be()?;
52 let r = br.read_u16be()?;
53 let g = br.read_u16be()?;
54 let b = br.read_u16be()?;
55 pal[i * 4] = (r >> 8) as u8;
56 pal[i * 4 + 1] = (g >> 8) as u8;
57 pal[i * 4 + 2] = (b >> 8) as u8;
58 pal[i * 4 + 3] = (a >> 8) as u8;
59 }
60 Ok(size)
61 }
62
63 struct RootChunkHandler {
64 ctype: u32,
65 parse: fn(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64>,
66 }
67
68 struct TrackChunkHandler {
69 ctype: u32,
70 parse: fn(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64>,
71 }
72
73 const IGNORED_CHUNKS: &[u32] = &[
74 mktag!(b"free"), mktag!(b"skip"), mktag!(b"udta"), mktag!(b"wide")
75 ];
76
77 const ROOT_CHUNK_HANDLERS: &[RootChunkHandler] = &[
78 RootChunkHandler { ctype: mktag!(b"ftyp"), parse: read_ftyp },
79 RootChunkHandler { ctype: mktag!(b"mdat"), parse: read_mdat },
80 RootChunkHandler { ctype: mktag!(b"moov"), parse: read_moov },
81 ];
82
83 fn print_cname(ctype: u32, size: u64, off: u64, depth: u8) {
84 for _ in 0..depth { print!(" "); }
85 let tag = [(ctype >> 24) as u8, (ctype >> 16) as u8, (ctype >> 8) as u8, ctype as u8];
86 let mut printable = true;
87 for &ch in tag.iter() {
88 if ch < 0x20 || ch > 0x7F {
89 printable = false;
90 break;
91 }
92 }
93 if printable {
94 print!(" '{}{}{}{}'", tag[0] as char, tag[1] as char, tag[2] as char, tag[3] as char);
95 } else {
96 print!(" {:08X}", ctype);
97 }
98 println!(" size {} @ {:X}", size, off);
99 }
100
101 macro_rules! read_chunk_list {
102 (root; $name: expr, $fname: ident, $handlers: ident) => {
103 fn $fname(&mut self, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<()> {
104 self.depth += 1;
105 validate!(self.depth < 32);
106 let list_end = self.src.tell() + size;
107 while self.src.tell() < list_end {
108 let ret = read_chunk_header(&mut self.src);
109 if ret.is_err() { break; }
110 let (ctype, size) = ret.unwrap();
111 if self.print_chunks {
112 print_cname(ctype, size, self.src.tell(), self.depth as u8);
113 }
114 if self.src.tell() + size > list_end {
115 break;
116 }
117 if IGNORED_CHUNKS.contains(&ctype) {
118 self.src.skip64(size)?;
119 continue;
120 }
121 let handler = $handlers.iter().find(|x| x.ctype == ctype);
122 let read_size;
123 if let Some(ref handler) = handler {
124 read_size = (handler.parse)(self, strmgr, size)?;
125 } else {
126 println!("skipping unknown chunk {:08X} size {}", ctype, size);
127 read_size = 0;
128 }
129 validate!(read_size <= size);
130 self.src.skip64(size - read_size)?;
131 }
132 self.depth -= 1;
133 validate!(self.src.tell() == list_end);
134 Ok(())
135 }
136 };
137 (track; $name: expr, $fname: ident, $handlers: ident) => {
138 fn $fname(&mut self, br: &mut ByteReader, size: u64) -> DemuxerResult<()> {
139 self.depth += 1;
140 validate!(self.depth < 32);
141 let list_end = br.tell() + size;
142 while br.tell() < list_end {
143 let ret = read_chunk_header(br);
144 if ret.is_err() { break; }
145 let (ctype, size) = ret.unwrap();
146 if self.print_chunks {
147 print_cname(ctype, size, br.tell(), self.depth + 1);
148 }
149 if br.tell() + size > list_end {
150 break;
151 }
152 if IGNORED_CHUNKS.contains(&ctype) {
153 br.skip64(size)?;
154 continue;
155 }
156 let handler = $handlers.iter().find(|x| x.ctype == ctype);
157 let read_size;
158 if let Some(ref handler) = handler {
159 read_size = (handler.parse)(self, br, size)?;
160 } else {
161 read_size = 0;
162 }
163 validate!(read_size <= size);
164 br.skip64(size - read_size)?;
165 }
166 self.depth -= 1;
167 validate!(br.tell() == list_end);
168 Ok(())
169 }
170 }
171 }
172
173 fn skip_chunk(_track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
174 br.skip64(size)?;
175 Ok(size)
176 }
177
178 fn read_ftyp(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
179 dmx.src.skip64(size)?;
180 Ok(size)
181 }
182
183 fn read_mdat(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
184 dmx.mdat_pos = dmx.src.tell();
185 dmx.mdat_size = size;
186 dmx.src.skip64(size)?;
187 Ok(size)
188 }
189
190 fn read_moov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
191 dmx.read_moov(strmgr, size)?;
192 Ok(size)
193 }
194
195 const MOOV_CHUNK_HANDLERS: &[RootChunkHandler] = &[
196 RootChunkHandler { ctype: mktag!(b"mvhd"), parse: read_mvhd },
197 RootChunkHandler { ctype: mktag!(b"cmov"), parse: read_cmov },
198 RootChunkHandler { ctype: mktag!(b"ctab"), parse: read_ctab },
199 RootChunkHandler { ctype: mktag!(b"trak"), parse: read_trak },
200 RootChunkHandler { ctype: mktag!(b"meta"), parse: read_meta },
201 ];
202
203 fn read_mvhd(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
204 const KNOWN_MVHD_SIZE: u64 = 100;
205 let br = &mut dmx.src;
206 validate!(size >= KNOWN_MVHD_SIZE);
207 let version = br.read_byte()?;
208 validate!(version == 0);
209 let _flags = br.read_u24be()?;
210 let _ctime = br.read_u32be()?;
211 let _mtime = br.read_u32be()?;
212 let tscale = br.read_u32be()?;
213 let duration = br.read_u32be()?;
214 let _pref_rate = br.read_u32be()?;
215 let _pref_volume = br.read_u16be()?;
216 br.read_skip(10)?;
217 br.read_skip(36)?; // matrix
218 let _preview_time = br.read_u32be()?;
219 let _preview_duration = br.read_u32be()?;
220 let _poster_time = br.read_u32be()?;
221 let _sel_time = br.read_u32be()?;
222 let _sel_duration = br.read_u32be()?;
223 let _cur_time = br.read_u32be()?;
224 let _next_track_id = br.read_u32be()?;
225 dmx.duration = duration;
226 dmx.tb_den = tscale;
227
228 Ok(KNOWN_MVHD_SIZE)
229 }
230
231 fn read_cmov(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
232 let br = &mut dmx.src;
233 validate!(size > 24);
234 let dcom_size = br.read_u32be()?;
235 let dcom_tag = br.read_tag()?;
236 let compr_type = br.read_tag()?;
237 validate!(&dcom_tag == b"dcom" && dcom_size == 12);
238 if &compr_type != b"zlib" {
239 return Err(DemuxerError::NotImplemented);
240 }
241 let cmvd_size = u64::from(br.read_u32be()?);
242 let cmvd_tag = br.read_tag()?;
243 validate!(&cmvd_tag == b"cmvd" && cmvd_size > 14 && cmvd_size == size - 12);
244 let comp_size = (cmvd_size - 12) as usize;
245 let uncomp_size = br.read_u32be()? as usize;
246 validate!(uncomp_size > 8);
247 let mut sbuf = vec![0; comp_size];
248 let mut dbuf = vec![0; uncomp_size];
249 br.read_buf(sbuf.as_mut_slice())?;
250 let ret = Inflate::uncompress(sbuf.as_slice(), dbuf.as_mut_slice());
251 if ret.is_err() {
252 return Err(DemuxerError::InvalidData);
253 }
254 let len = ret.unwrap();
255 validate!(len == uncomp_size);
256 let mut mr = MemoryReader::new_read(dbuf.as_slice());
257 let mut br = ByteReader::new(&mut mr);
258 let (ctype, csize) = read_chunk_header(&mut br)?;
259 validate!(ctype == mktag!(b"moov"));
260 let mut ddmx = MOVDemuxer::new(&mut br);
261 ddmx.print_chunks = dmx.print_chunks;
262 ddmx.read_moov(strmgr, csize)?;
263 std::mem::swap(&mut dmx.tracks, &mut ddmx.tracks);
264 dmx.duration = ddmx.duration;
265 dmx.tb_den = ddmx.tb_den;
266 std::mem::swap(&mut dmx.pal, &mut ddmx.pal);
267
268 Ok(size)
269 }
270
271 fn read_ctab(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
272 let mut pal = [0; 1024];
273 let size = read_palette(&mut dmx.src, size, &mut pal)?;
274 dmx.pal = Some(Arc::new(pal));
275 Ok(size)
276 }
277
278 fn read_meta(dmx: &mut MOVDemuxer, _strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
279 dmx.src.skip64(size)?;
280 Ok(size)
281 }
282
283 fn read_trak(dmx: &mut MOVDemuxer, strmgr: &mut StreamManager, size: u64) -> DemuxerResult<u64> {
284 let mut track = Track::new(dmx.cur_track as u32, dmx.tb_den);
285 track.print_chunks = dmx.print_chunks;
286 track.read_trak(&mut dmx.src, size)?;
287 validate!(track.tkhd_found && track.stsd_found);
288 validate!(strmgr.get_stream_by_id(track.track_id).is_none());
289 dmx.cur_track += 1;
290 let mut str = None;
291 std::mem::swap(&mut track.stream, &mut str);
292 if let Some(stream) = str {
293 let str_id = strmgr.add_stream(stream).unwrap();
294 track.track_str_id = str_id;
295 }
296 dmx.tracks.push(track);
297 Ok(size)
298 }
299
300 const TRAK_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
301 TrackChunkHandler { ctype: mktag!(b"clip"), parse: skip_chunk },
302 TrackChunkHandler { ctype: mktag!(b"matt"), parse: skip_chunk },
303 TrackChunkHandler { ctype: mktag!(b"edts"), parse: skip_chunk },
304 TrackChunkHandler { ctype: mktag!(b"tref"), parse: skip_chunk },
305 TrackChunkHandler { ctype: mktag!(b"load"), parse: skip_chunk },
306 TrackChunkHandler { ctype: mktag!(b"imap"), parse: skip_chunk },
307 TrackChunkHandler { ctype: mktag!(b"tkhd"), parse: read_tkhd },
308 TrackChunkHandler { ctype: mktag!(b"mdia"), parse: read_mdia },
309 ];
310
311 fn read_tkhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
312 const KNOWN_TKHD_SIZE: u64 = 84;
313 validate!(size >= KNOWN_TKHD_SIZE);
314 let version = br.read_byte()?;
315 validate!(version == 0);
316 let _flags = br.read_u24be()?;
317 let _ctime = br.read_u32be()?;
318 let _mtime = br.read_u32be()?;
319 let track_id = br.read_u32be()?;
320 br.read_skip(4)?;
321 let duration = br.read_u32be()?;
322 br.read_skip(8)?;
323 let _layer = br.read_u16be()?;
324 let _alt_group = br.read_u16be()?;
325 let _volume = br.read_u16be()?;
326 br.read_skip(2)?;
327 br.read_skip(36)?; // matrix
328 let width = br.read_u32be()? as usize;
329 let height = br.read_u32be()? as usize;
330 track.width = width >> 16;
331 track.height = height >> 16;
332 track.track_id = track_id;
333 track.duration = duration;
334
335 track.tkhd_found = true;
336 Ok(KNOWN_TKHD_SIZE)
337 }
338
339 fn read_mdia(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
340 track.stream_type = StreamType::None;
341 track.read_mdia(br, size)?;
342 Ok(size)
343 }
344
345 const MDIA_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
346 TrackChunkHandler { ctype: mktag!(b"mdhd"), parse: read_mdhd },
347 TrackChunkHandler { ctype: mktag!(b"hdlr"), parse: read_hdlr },
348 TrackChunkHandler { ctype: mktag!(b"minf"), parse: read_minf },
349 ];
350
351 fn read_mdhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
352 const KNOWN_MDHD_SIZE: u64 = 24;
353 validate!(size >= KNOWN_MDHD_SIZE);
354 let version = br.read_byte()?;
355 validate!(version == 0);
356 let flags = br.read_u24be()?;
357 validate!(flags == 0);
358 let _ctime = br.read_u32be()?;
359 let _mtime = br.read_u32be()?;
360 track.tb_den = br.read_u32be()?;
361 validate!(track.tb_den != 0);
362 track.duration = br.read_u32be()?;
363 let _language = br.read_u16be()?;
364 let _quality = br.read_u16be()?;
365
366 Ok(KNOWN_MDHD_SIZE)
367 }
368
369 fn read_hdlr(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
370 const KNOWN_HDLR_SIZE: u64 = 24;
371 validate!(size >= KNOWN_HDLR_SIZE);
372 let version = br.read_byte()?;
373 validate!(version == 0);
374 let flags = br.read_u24be()?;
375 validate!(flags == 0);
376 let comp_type = br.read_u32be()?;
377 let comp_subtype = br.read_u32be()?;
378 let _comp_manufacturer = br.read_u32be()?;
379 let _comp_flags = br.read_u32be()?;
380 let _comp_flags_mask = br.read_u32be()?;
381
382 if comp_type == mktag!(b"mhlr") || comp_type == 0 {
383 if comp_subtype == mktag!(b"vide") {
384 track.stream_type = StreamType::Video;
385 } else if comp_subtype == mktag!(b"soun") {
386 track.stream_type = StreamType::Audio;
387 } else {
388 track.stream_type = StreamType::Data;
389 }
390 } else if comp_type == mktag!(b"dhlr") {
391 track.stream_type = StreamType::Data;
392 } else {
393 println!("Unknown stream type");
394 track.stream_type = StreamType::Data;
395 }
396
397 Ok(KNOWN_HDLR_SIZE)
398 }
399
400 fn read_minf(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
401 track.read_minf(br, size)?;
402 Ok(size)
403 }
404
405 const MINF_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
406 TrackChunkHandler { ctype: mktag!(b"hdlr"), parse: skip_chunk },
407 TrackChunkHandler { ctype: mktag!(b"dinf"), parse: skip_chunk },
408 TrackChunkHandler { ctype: mktag!(b"vmhd"), parse: read_vmhd },
409 TrackChunkHandler { ctype: mktag!(b"smhd"), parse: read_smhd },
410 TrackChunkHandler { ctype: mktag!(b"gmhd"), parse: read_gmhd },
411 TrackChunkHandler { ctype: mktag!(b"gmin"), parse: read_gmin },
412 TrackChunkHandler { ctype: mktag!(b"stbl"), parse: read_stbl },
413 ];
414
415 fn read_vmhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
416 const KNOWN_VMHD_SIZE: u64 = 12;
417 validate!(track.stream_type == StreamType::Video);
418 validate!(size >= KNOWN_VMHD_SIZE);
419 let version = br.read_byte()?;
420 validate!(version == 0);
421 let _flags = br.read_u24be()?;
422 br.read_skip(2)?; // graphics mode
423 br.read_skip(6)?; // opcolor
424 Ok(KNOWN_VMHD_SIZE)
425 }
426
427 fn read_smhd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
428 const KNOWN_SMHD_SIZE: u64 = 8;
429 validate!(track.stream_type == StreamType::Audio);
430 validate!(size >= KNOWN_SMHD_SIZE);
431 let version = br.read_byte()?;
432 validate!(version == 0);
433 let _flags = br.read_u24be()?;
434 br.read_skip(2)?; // balance
435 br.read_skip(2)?;
436 Ok(KNOWN_SMHD_SIZE)
437 }
438
439 fn read_gmhd(track: &mut Track, _br: &mut ByteReader, _size: u64) -> DemuxerResult<u64> {
440 validate!(track.stream_type == StreamType::Data);
441 Ok(0)
442 }
443
444 fn read_gmin(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
445 validate!(track.stream_type == StreamType::Data);
446 const KNOWN_GMIN_SIZE: u64 = 16;
447 validate!(size >= KNOWN_GMIN_SIZE);
448 let version = br.read_byte()?;
449 validate!(version == 0);
450 let _flags = br.read_u24be()?;
451 br.read_skip(2)?; // graphics mode
452 br.read_skip(6)?; // opcolor
453 br.read_skip(2)?; // balance
454 br.read_skip(2)?;
455 Ok(KNOWN_GMIN_SIZE)
456 }
457
458 fn read_stbl(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
459 track.read_stbl(br, size)?;
460 Ok(size)
461 }
462
463 const STBL_CHUNK_HANDLERS: &[TrackChunkHandler] = &[
464 TrackChunkHandler { ctype: mktag!(b"stsd"), parse: read_stsd },
465 TrackChunkHandler { ctype: mktag!(b"stts"), parse: read_stts },
466 TrackChunkHandler { ctype: mktag!(b"stss"), parse: read_stss },
467 TrackChunkHandler { ctype: mktag!(b"stsc"), parse: read_stsc },
468 TrackChunkHandler { ctype: mktag!(b"stsz"), parse: read_stsz },
469 TrackChunkHandler { ctype: mktag!(b"stco"), parse: read_stco },
470 TrackChunkHandler { ctype: mktag!(b"stsh"), parse: skip_chunk },
471 TrackChunkHandler { ctype: mktag!(b"ctts"), parse: read_ctts },
472 ];
473
474 fn parse_audio_edata(br: &mut ByteReader, start_pos: u64, size: u64) -> DemuxerResult<Option<Vec<u8>>> {
475 let read_part = br.tell() - start_pos;
476 if read_part + 8 < size {
477 let mut buf = [0; 8];
478 br.peek_buf(&mut buf)?;
479 if &buf[4..8] != b"wave" {
480 let mut buf = vec![0; (size - read_part) as usize];
481 br.read_buf(&mut buf)?;
482 return Ok(Some(buf));
483 }
484
485 let csize = br.read_u32be()? as u64;
486 let ctag = br.read_u32be()?;
487 validate!(read_part + csize <= size);
488 validate!(ctag == mktag!(b"wave"));
489 if csize == 8 {
490 return Ok(None);
491 }
492 let mut buf = [0; 8];
493 br.peek_buf(&mut buf)?;
494 if &buf[4..8] == b"frma" {
495 br.read_skip(12)?;
496 if csize > 20 {
497 let mut buf = vec![0; (csize - 20) as usize];
498 br.read_buf(&mut buf)?;
499 Ok(Some(buf))
500 } else {
501 Ok(None)
502 }
503 } else if csize > 8 {
504 let mut buf = vec![0; (csize as usize) - 8];
505 br.read_buf(&mut buf)?;
506 Ok(Some(buf))
507 } else {
508 Ok(None)
509 }
510 } else {
511 Ok(None)
512 }
513 }
514
515 fn read_stsd(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
516 const KNOWN_STSD_SIZE: u64 = 24;
517 validate!(size >= KNOWN_STSD_SIZE);
518 let start_pos = br.tell();
519 let version = br.read_byte()?;
520 validate!(version == 0);
521 let _flags = br.read_u24be()?;
522 let entries = br.read_u32be()?;
523 validate!(entries > 0);
524 let esize = u64::from(br.read_u32be()?);
525 validate!(esize + 8 <= size);
526 let mut fcc = [0u8; 4];
527 br.read_buf(&mut fcc)?;
528 br.read_skip(6)?;
529 let _data_ref = br.read_u16be()?;
530
531 track.fcc = fcc;
532
533 let codec_info;
534 match track.stream_type {
535 StreamType::Video => {
536 let _ver = br.read_u16be()?;
537 let _revision = br.read_u16le()?;
538 let _vendor = br.read_u32be()?;
539 let _temp_quality = br.read_u32be()?;
540 let _spat_quality = br.read_u32be()?;
541 let width = br.read_u16be()? as usize;
542 let height = br.read_u16be()? as usize;
543 let _hor_res = br.read_u32be()?;
544 let _vert_res = br.read_u32be()?;
545 let data_size = br.read_u32be()?;
546 validate!(data_size == 0);
547 let _frame_count = br.read_u16be()? as usize;
548 let _cname_len = br.read_byte()? as usize;
549 br.read_skip(31)?; // actual compressor name
550 let depth = br.read_u16be()?;
551 let ctable_id = br.read_u16be()?;
552 let grayscale = depth > 0x20 || depth == 1;
553 let depth = if grayscale { depth & 0x1F } else { depth };
554 validate!(depth <= 8 || (ctable_id == 0xFFFF));
555 if ctable_id == 0 {
556 let max_pal_size = start_pos + size - br.tell();
557 let mut pal = [0; 1024];
558 read_palette(br, max_pal_size, &mut pal)?;
559 track.pal = Some(Arc::new(pal));
560 } else if (depth <= 8) && !grayscale {
561 match depth & 0x1F {
562 2 => {
563 let mut pal = [0; 1024];
564 (&mut pal[..4 * 4]).copy_from_slice(&MOV_DEFAULT_PAL_2BIT);
565 track.pal = Some(Arc::new(pal));
566 },
567 4 => {
568 let mut pal = [0; 1024];
569 (&mut pal[..16 * 4]).copy_from_slice(&MOV_DEFAULT_PAL_4BIT);
570 track.pal = Some(Arc::new(pal));
571 },
572 8 => {
573 track.pal = Some(Arc::new(MOV_DEFAULT_PAL_8BIT));
574 },
575 _ => {},
576 };
577 } else if grayscale && ctable_id != 0xFFFF {
578 let mut pal = [0; 1024];
579 let cdepth = depth & 0x1F;
580 let size = 1 << cdepth;
581 for i in 0..size {
582 let mut clr = ((size - 1 - i) as u8) << (8 - cdepth);
583 let mut off = 8 - cdepth;
584 while off >= cdepth {
585 clr |= clr >> (8 - off);
586 off -= cdepth;
587 }
588 if off > 0 {
589 clr |= clr >> (8 - off);
590 }
591 pal[i * 4] = clr;
592 pal[i * 4 + 1] = clr;
593 pal[i * 4 + 2] = clr;
594 }
595 track.pal = Some(Arc::new(pal));
596 }
597 // todo other atoms, put as extradata
598 let cname = if let Some(name) = find_codec_from_mov_video_fourcc(&fcc) {
599 name
600 } else if let Some(name) = find_codec_from_avi_fourcc(&fcc) {
601 name
602 } else {
603 "unknown"
604 };
605 let format = if depth > 8 { RGB24_FORMAT } else { PAL8_FORMAT };
606 let mut vhdr = NAVideoInfo::new(width, height, false, format);
607 vhdr.bits = depth as u8;
608 //skip various common atoms
609 while br.tell() - start_pos + 4 < size {
610 let mut buf = [0u8; 8];
611 br.peek_buf(&mut buf)?;
612 let tsize = read_u32be(&buf).unwrap() as usize;
613 let tag = &buf[4..8];
614 validate!(tsize >= 8);
615 match tag {
616 b"pasp" | b"clap" => {
617 br.read_skip(tsize)?;
618 },
619 _ => break,
620 };
621 }
622 let edata = if br.tell() - start_pos + 4 < size {
623 let edata_size = br.read_u32be()? as usize;
624 validate!(edata_size >= 4);
625 let mut buf = vec![0; edata_size - 4];
626 br.read_buf(buf.as_mut_slice())?;
627 Some(buf)
628 } else {
629 None
630 };
631 codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Video(vhdr), edata);
632 },
633 StreamType::Audio => {
634 let sver = br.read_u16be()?;
635 let _revision = br.read_u16le()?;
636 let _vendor = br.read_u32be()?;
637 let nchannels = br.read_u16be()?;
638 validate!(nchannels <= 64);
639 let sample_size = br.read_u16be()?;
640 validate!(sample_size <= 128);
641 let _compr_id = br.read_u16be()?;
642 let packet_size = br.read_u16be()? as usize;
643 validate!(packet_size == 0);
644 let sample_rate = br.read_u32be()?;
645 validate!(sample_rate > (1 << 16));
646 let cname = if let Some(name) = find_codec_from_mov_audio_fourcc(&fcc) {
647 name
648 } else if let (true, Some(name)) = ((fcc[0] == b'm' && fcc[1] == b's'), find_codec_from_wav_twocc(u16::from(fcc[2]) * 256 + u16::from(fcc[3]))) {
649 name
650 } else {
651 "unknown"
652 };
653 let mut soniton = NASoniton::new(sample_size as u8, SONITON_FLAG_SIGNED | SONITON_FLAG_BE);
654 if &fcc == b"raw " && sample_size == 8 {
655 soniton.signed = false;
656 }
657 let block_align = 1;
658 if sver == 1 {
659 let samples_per_packet = br.read_u32be()?;
660 let _bytes_per_packet = br.read_u32be()?;
661 let bytes_per_frame = br.read_u32be()?;
662 let _bytes_per_sample = br.read_u32be()?;
663 track.bsize = bytes_per_frame as usize;
664 track.frame_samples = samples_per_packet as usize;
665 track.tb_num = samples_per_packet;
666 } else {
667 track.bsize = (sample_size / 8) as usize;
668 }
669 track.tb_den = sample_rate >> 16;
670 track.raw_audio = match &fcc {
671 b"NONE" | b"raw " | b"twos" | b"sowt" |
672 b"in24" | b"in32" | b"fl32" | b"fl64" |
673 b"ima4" | b"ms\x00\x02" | b"ms\x00\x21" |
674 b"alaw" | b"ulaw" |
675 b"MAC3" | b"MAC6" => true,
676 _ => false,
677 };
678 let ahdr = NAAudioInfo::new(sample_rate >> 16, nchannels as u8, soniton, block_align);
679 let edata = parse_audio_edata(br, start_pos, size)?;
680 codec_info = NACodecInfo::new(cname, NACodecTypeInfo::Audio(ahdr), edata);
681 track.channels = nchannels as usize;
682 track.bits = sample_size as usize;
683 },
684 StreamType::None => {
685 return Err(DemuxerError::InvalidData);
686 },
687 _ => {
688 //todo put it all into extradata
689 let edata = None;
690 codec_info = NACodecInfo::new("unknown", NACodecTypeInfo::None, edata);
691 },
692 };
693 let read_size = br.tell() - start_pos;
694 validate!(read_size <= size);
695 track.stream = Some(NAStream::new(track.stream_type, track.track_no, codec_info, track.tb_num, track.tb_den, u64::from(track.duration)));
696 track.stsd_found = true;
697 Ok(read_size)
698 }
699
700 fn read_stts(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
701 validate!(size >= 8);
702 let start_pos = br.tell();
703 let version = br.read_byte()?;
704 validate!(version == 0);
705 let _flags = br.read_u24be()?;
706 let entries = br.read_u32be()? as usize;
707 validate!(entries as u64 <= (size - 8) / 8);
708 if entries == 0 {
709 } else if entries == 1 {
710 let _count = br.read_u32be()?;
711 let tb_num = br.read_u32be()?;
712 validate!(tb_num != 0);
713 track.tb_div = tb_num;
714 if let Some(ref mut stream) = track.stream {
715 let tb_den = stream.tb_den;
716 let (tb_num, tb_den) = reduce_timebase(tb_num * stream.tb_num, tb_den);
717 stream.duration /= u64::from(track.tb_div);
718 stream.tb_num = tb_num;
719 stream.tb_den = tb_den;
720 track.tb_num = tb_num;
721 track.tb_den = tb_den;
722 track.duration /= track.tb_div;
723 }
724 } else {
725 track.time_to_sample.truncate(0);
726 track.time_to_sample.reserve(entries);
727 for _ in 0..entries {
728 let count = br.read_u32be()?;
729 let mult = br.read_u32be()?;
730 track.time_to_sample.push((count, mult));
731 }
732 }
733 let read_size = br.tell() - start_pos;
734 validate!(read_size <= size);
735 Ok(read_size)
736 }
737
738 fn read_stss(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
739 let version = br.read_byte()?;
740 validate!(version == 0);
741 let _flags = br.read_u24be()?;
742 let entries = br.read_u32be()? as usize;
743 validate!(entries < ((std::u32::MAX >> 2) - 8) as usize);
744 validate!((entries * 4 + 8) as u64 == size);
745 track.keyframes = Vec::with_capacity(entries);
746 let mut last_sample_no = 0;
747 for _ in 0..entries {
748 let sample_no = br.read_u32be()?;
749 validate!(sample_no > last_sample_no);
750 track.keyframes.push(sample_no);
751 last_sample_no = sample_no;
752 }
753 Ok(size)
754 }
755
756 fn read_stsc(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
757 let version = br.read_byte()?;
758 validate!(version == 0);
759 let _flags = br.read_u24be()?;
760 let entries = br.read_u32be()? as usize;
761 validate!(entries < ((std::u32::MAX / 12) - 8) as usize);
762 validate!((entries * 12 + 8) as u64 == size);
763 track.sample_map = Vec::with_capacity(entries);
764 let mut last_sample_no = 0;
765 for _i in 0..entries {
766 let sample_no = br.read_u32be()?;
767 validate!(sample_no > last_sample_no);
768 let nsamples = br.read_u32be()?;
769 let _sample_desc = br.read_u32be()?;
770 track.sample_map.push((sample_no, nsamples));
771 last_sample_no = sample_no;
772 }
773 Ok(size)
774 }
775
776 fn read_stsz(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
777 let version = br.read_byte()?;
778 validate!(version == 0);
779 let _flags = br.read_u24be()?;
780 let sample_size = br.read_u32be()?;
781 if sample_size != 0 {
782 track.sample_size = sample_size;
783 if track.sample_size != 1 || track.bsize == 0 {
784 track.bsize = sample_size as usize;
785 }
786 Ok(8)
787 } else {
788 let entries = br.read_u32be()? as usize;
789 validate!((entries * 4 + 12) as u64 == size);
790 track.chunk_sizes = Vec::with_capacity(entries);
791 for _ in 0..entries {
792 let sample_size = br.read_u32be()?;
793 track.chunk_sizes.push(sample_size);
794 }
795 Ok(size)
796 }
797 }
798
799 fn read_stco(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
800 let version = br.read_byte()?;
801 validate!(version == 0);
802 let _flags = br.read_u24be()?;
803 let entries = br.read_u32be()? as usize;
804 validate!((entries * 4 + 8) as u64 == size);
805 track.chunk_offsets = Vec::with_capacity(entries);
806 for _i in 0..entries {
807 let sample_offset = br.read_u32be()?;
808 track.chunk_offsets.push(u64::from(sample_offset));
809 }
810 Ok(size)
811 }
812
813 fn read_ctts(track: &mut Track, br: &mut ByteReader, size: u64) -> DemuxerResult<u64> {
814 validate!(size >= 8);
815 let version = br.read_byte()?;
816 let _flags = br.read_u24be()?;
817 if version > 1 {
818 return Err(DemuxerError::NotImplemented);
819 }
820 let entries = br.read_u32be()? as usize;
821 track.ctts_version = version;
822 track.ctts_map.resize(entries);
823 match version {
824 0 | 1 => {
825 validate!(size == (entries as u64) * 8 + 8);
826 for _ in 0..entries {
827 let samp_count = br.read_u32be()?;
828 let samp_offset = br.read_u32be()?;
829 track.ctts_map.add(samp_count, samp_offset / track.tb_div);
830 }
831 },
832 _ => unreachable!(),
833 };
834 track.ctts_map.reset();
835
836 Ok(size)
837 }
838
839 struct MOVDemuxer<'a> {
840 src: &'a mut ByteReader<'a>,
841 depth: usize,
842 mdat_pos: u64,
843 mdat_size: u64,
844 tracks: Vec<Track>,
845 cur_track: usize,
846 tb_den: u32,
847 duration: u32,
848 pal: Option<Arc<[u8; 1024]>>,
849
850 print_chunks: bool,
851 }
852
853 struct Track {
854 track_id: u32,
855 track_str_id: usize,
856 track_no: u32,
857 tb_num: u32,
858 tb_den: u32,
859 tb_div: u32,
860 raw_audio: bool,
861 raw_apos: u64,
862 duration: u32,
863 depth: u8,
864 tkhd_found: bool,
865 stsd_found: bool,
866 stream_type: StreamType,
867 width: usize,
868 height: usize,
869 channels: usize,
870 bits: usize,
871 bsize: usize,
872 fcc: [u8; 4],
873 keyframes: Vec<u32>,
874 chunk_sizes: Vec<u32>,
875 chunk_offsets: Vec<u64>,
876 time_to_sample: Vec<(u32, u32)>,
877 sample_map: Vec<(u32, u32)>,
878 sample_size: u32,
879 frame_samples: usize,
880 ctts_map: RLESearcher<u32>,
881 ctts_version: u8,
882 stream: Option<NAStream>,
883 cur_chunk: usize,
884 cur_sample: usize,
885 samples_left: usize,
886 last_offset: u64,
887 pal: Option<Arc<[u8; 1024]>>,
888 timesearch: TimeSearcher,
889
890 print_chunks: bool,
891 }
892
893 #[derive(Default)]
894 struct TimeSearcher {
895 idx: usize,
896 base: u64,
897 sbase: u32,
898 cur_len: u32,
899 cur_mul: u32,
900 }
901
902 impl TimeSearcher {
903 fn new() -> Self { Self::default() }
904 fn reset(&mut self) {
905 *self = Self::default();
906 }
907 fn map_time(&mut self, sample: u32, tts: &Vec<(u32, u32)>) -> u64 {
908 if tts.is_empty() {
909 u64::from(sample)
910 } else if sample >= self.sbase {
911 let mut sample = sample - self.sbase;
912 if self.idx == 0 {
913 let (cur_len, cur_mul) = tts[0];
914 self.cur_len = cur_len;
915 self.cur_mul = cur_mul;
916 self.idx += 1;
917 }
918 while self.idx < tts.len() && sample > self.cur_len {
919 sample -= self.cur_len;
920 self.sbase += self.cur_len;
921 self.base += u64::from(self.cur_len) * u64::from(self.cur_mul);
922 self.cur_len = tts[self.idx].0;
923 self.cur_mul = tts[self.idx].1;
924 self.idx += 1;
925 }
926 self.base + u64::from(sample) * u64::from(self.cur_mul)
927 } else {
928 self.reset();
929 self.map_time(sample, tts)
930 }
931 }
932 }
933
934 #[derive(Default)]
935 struct RLESearcher<T> {
936 array: Vec<(u32, T)>,
937 idx: usize,
938 start: u64,
939 next: u64,
940 }
941
942 impl<T:Default+Copy> RLESearcher<T> {
943 fn new() -> Self { Self::default() }
944 fn resize(&mut self, size: usize) {
945 self.array.truncate(0);
946 self.array.reserve(size);
947 }
948 fn add(&mut self, len: u32, val: T) {
949 self.array.push((len, val));
950 }
951 fn reset(&mut self) {
952 self.start = 0;
953 if !self.array.is_empty() {
954 self.idx = 0;
955 self.next = u64::from(self.array[0].0);
956 } else {
957 self.idx = self.array.len();
958 self.next = 0;
959 }
960 }
961 fn map(&mut self, sample: u64) -> Option<T> {
962 if sample < self.start {
963 self.reset();
964 }
965 if self.idx < self.array.len() {
966 if sample < self.next {
967 Some(self.array[self.idx].1)
968 } else {
969 while (self.idx < self.array.len()) && (sample >= self.next) {
970 self.start = self.next;
971 self.idx += 1;
972 if self.idx < self.array.len() {
973 self.next += u64::from(self.array[self.idx].0);
974 }
975 }
976 if self.idx < self.array.len() {
977 Some(self.array[self.idx].1)
978 } else {
979 None
980 }
981 }
982 } else {
983 None
984 }
985 }
986 }
987
988 impl Track {
989 fn new(track_no: u32, tb_den: u32) -> Self {
990 Self {
991 tkhd_found: false,
992 stsd_found: false,
993 track_id: 0,
994 track_str_id: 0,
995 track_no,
996 tb_num: 1,
997 tb_den,
998 tb_div: 1,
999 raw_audio: false,
1000 raw_apos: 0,
1001 duration: 0,
1002 stream_type: StreamType::None,
1003 width: 0,
1004 height: 0,
1005 channels: 0,
1006 bits: 0,
1007 bsize: 0,
1008 fcc: [0; 4],
1009 keyframes: Vec::new(),
1010 chunk_sizes: Vec::new(),
1011 chunk_offsets: Vec::new(),
1012 time_to_sample: Vec::new(),
1013 sample_map: Vec::new(),
1014 sample_size: 0,
1015 frame_samples: 0,
1016 ctts_map: RLESearcher::new(),
1017 ctts_version: 0,
1018 stream: None,
1019 depth: 0,
1020 cur_chunk: 0,
1021 cur_sample: 0,
1022 samples_left: 0,
1023 last_offset: 0,
1024 pal: None,
1025 timesearch: TimeSearcher::new(),
1026
1027 print_chunks: false,
1028 }
1029 }
1030 read_chunk_list!(track; "trak", read_trak, TRAK_CHUNK_HANDLERS);
1031 read_chunk_list!(track; "mdia", read_mdia, MDIA_CHUNK_HANDLERS);
1032 read_chunk_list!(track; "minf", read_minf, MINF_CHUNK_HANDLERS);
1033 read_chunk_list!(track; "stbl", read_stbl, STBL_CHUNK_HANDLERS);
1034 fn fill_seek_index(&self, seek_index: &mut SeekIndex) {
1035 if !self.keyframes.is_empty() {
1036 seek_index.mode = SeekIndexMode::Present;
1037 }
1038 let mut tsearch = TimeSearcher::new();
1039 for kf_time in self.keyframes.iter() {
1040 let pts = tsearch.map_time(*kf_time - 1, &self.time_to_sample);
1041 let time = NATimeInfo::ts_to_time(pts, 1000, self.tb_num, self.tb_den);
1042 seek_index.add_entry(self.track_no as u32, SeekEntry { time, pts: u64::from(*kf_time - 1), pos: 0 });
1043 }
1044 }
1045 fn calculate_chunk_size(&self, nsamp: usize) -> usize {
1046 if nsamp == 0 {
1047 self.bsize
1048 } else {
1049 match &self.fcc {
1050 b"NONE" | b"raw " | b"twos" | b"sowt" => {
1051 (nsamp * self.bits * self.channels + 7) >> 3
1052 },
1053 b"ima4" => {
1054 let nblocks = (nsamp + 63) >> 6;
1055 nblocks * 34 * self.channels
1056 },
1057 b"MAC3" => {
1058 (nsamp + 5) / 6 * 2 * self.channels
1059 },
1060 b"MAC6" => {
1061 (nsamp + 5) / 6 * self.channels
1062 },
1063 b"in24" => nsamp * 3 * self.channels,
1064 b"in32" | b"fl32" => nsamp * 4 * self.channels,
1065 b"fl64" => nsamp * 8 * self.channels,
1066 b"ulaw" | b"alaw" => nsamp,
1067 b"ms\x00\x02" => { //MS ADPCM
1068 ((nsamp - 1) / 2 + 7) * self.channels
1069 },
1070 b"ms\x00\x21" => { //IMA ADPCM
1071 (nsamp / 2 + 4) * self.channels
1072 },
1073 _ => self.bsize,
1074 }
1075 }
1076 }
1077 fn get_next_chunk(&mut self) -> Option<(NATimeInfo, u64, usize)> {
1078 let pts_val = self.timesearch.map_time(self.cur_sample as u32, &self.time_to_sample);
1079 let dts = if let Some(dts_corr) = self.ctts_map.map(self.cur_sample as u64) {
1080 let dts = match self.ctts_version {
1081 0 => pts_val.wrapping_add(u64::from(dts_corr)),
1082 1 => pts_val.wrapping_add(i64::from(dts_corr as i32) as u64),
1083 _ => unimplemented!(),
1084 };
1085 if (dts as i64) < 0 {
1086 None
1087 } else {
1088 Some(dts)
1089 }
1090 } else {
1091 None
1092 };
1093 let mut pts = NATimeInfo::new(Some(pts_val), dts, None, self.tb_num, self.tb_den);
1094 if self.chunk_offsets.len() == self.chunk_sizes.len() { // simple one-to-one mapping
1095 if self.cur_sample >= self.chunk_sizes.len() {
1096 return None;
1097 }
1098 let offset = self.chunk_offsets[self.cur_sample];
1099 let size = self.chunk_sizes[self.cur_sample] as usize;
1100 self.cur_sample += 1;
1101 Some((pts, offset, size))
1102 } else {
1103 if self.samples_left == 0 {
1104 if self.cur_chunk >= self.chunk_offsets.len() {
1105 return None;
1106 }
1107 for (idx, samples) in self.sample_map.iter() {
1108 if *idx as usize <= self.cur_chunk + 1 {
1109 self.samples_left = *samples as usize;
1110 } else {
1111 break;
1112 }
1113 }
1114 self.last_offset = self.chunk_offsets[self.cur_chunk];
1115 self.cur_chunk += 1;
1116 }
1117 let offset = self.last_offset;
1118 let size = self.get_size(self.cur_sample);
1119 self.last_offset += size as u64;
1120 if self.stream_type == StreamType::Video {
1121 self.samples_left -= 1;
1122 } else if self.frame_samples != 0 && self.bsize != 0 {
1123 let nblocks = size / self.bsize;
1124 if self.raw_audio {
1125 pts.pts = Some(self.raw_apos);
1126 pts.duration = Some(nblocks as u64);
1127 self.raw_apos += nblocks as u64;
1128 }
1129 if nblocks > 0 {
1130 let consumed = (nblocks * self.frame_samples).min(self.samples_left);
1131 self.samples_left -= consumed;
1132 } else {
1133 self.samples_left = 0;
1134 }
1135 } else if !self.raw_audio {
1136 self.samples_left -= 1;
1137 } else {
1138 const BLOCK_SAMPLES: usize = 1024 * 6; // should be multiple of 64 and 6 to fit both IMA ADPCM and MACE 6:1 blocks
1139 let max_size = self.calculate_chunk_size(BLOCK_SAMPLES);
1140 let cur_size = self.calculate_chunk_size(self.samples_left);
1141 let add_off = (size - cur_size) as u64;
1142 let dsize = cur_size.min(max_size);
1143 if self.samples_left >= BLOCK_SAMPLES {
1144 self.cur_sample += BLOCK_SAMPLES;
1145 self.samples_left -= BLOCK_SAMPLES;
1146 self.last_offset -= size as u64;
1147 } else {
1148 self.cur_sample += self.samples_left;
1149 self.samples_left = 0;
1150 }
1151 return Some((pts, offset + add_off, dsize));
1152 }
1153 self.cur_sample += 1;
1154 Some((pts, offset, size))
1155 }
1156 }
1157 fn get_size(&self, sample_no: usize) -> usize {
1158 if !self.chunk_sizes.is_empty() {
1159 self.chunk_sizes[sample_no] as usize
1160 } else if !self.sample_map.is_empty() {
1161 let mut nsamp = 0;
1162 for (idx, samples) in self.sample_map.iter() {
1163 if *idx as usize <= self.cur_chunk {
1164 nsamp = *samples;
1165 } else {
1166 break;
1167 }
1168 }
1169 self.calculate_chunk_size(nsamp as usize)
1170 } else {
1171 self.bsize
1172 }
1173 }
1174 fn seek(&mut self, pts: u64, tpoint: NATimePoint) -> DemuxerResult<()> {
1175 self.cur_sample = pts as usize;
1176 self.samples_left = 0;
1177 if self.stream_type == StreamType::Audio {
1178 if let NATimePoint::Milliseconds(ms) = tpoint {
1179 let exp_pts = NATimeInfo::time_to_ts(ms, 1000, self.tb_num, self.tb_den);
1180 if self.raw_audio {
1181 if self.frame_samples != 0 {
1182 self.raw_apos = exp_pts / (self.frame_samples as u64);
1183 let mut apos = 0;
1184 self.cur_sample = 0;
1185 self.cur_chunk = 0;
1186 let mut cmap = self.sample_map.iter();
1187 let mut cur_samps = 0;
1188 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1189 loop {
1190 if self.cur_chunk + 1 == next_idx as usize {
1191 self.samples_left = cur_samps;
1192 cur_samps = next_samples as usize;
1193 if let Some((new_idx, new_samples)) = cmap.next() {
1194 next_idx = *new_idx;
1195 next_samples = *new_samples;
1196 }
1197 }
1198 self.raw_apos = apos;
1199 apos += (cur_samps / self.frame_samples) as u64;
1200 if apos > exp_pts {
1201 if cur_samps == self.frame_samples || apos > exp_pts + 1 {
1202 if self.cur_chunk >= self.chunk_offsets.len() {
1203 return Err(DemuxerError::SeekError);
1204 }
1205 self.last_offset = self.chunk_offsets[self.cur_chunk];
1206 break;
1207 }
1208 }
1209 self.cur_chunk += 1;
1210 }
1211 self.samples_left = cur_samps;
1212 self.cur_chunk += 1;
1213 } else {
1214 self.raw_apos = exp_pts;
1215 self.cur_sample = exp_pts as usize;
1216 let mut csamp = 0;
1217 self.cur_chunk = 0;
1218 let mut cmap = self.sample_map.iter();
1219 let mut cur_samps = 0;
1220 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1221 loop {
1222 if self.cur_chunk + 1 == next_idx as usize {
1223 self.samples_left = cur_samps;
1224 cur_samps = next_samples as usize;
1225 if let Some((new_idx, new_samples)) = cmap.next() {
1226 next_idx = *new_idx;
1227 next_samples = *new_samples;
1228 }
1229 }
1230 csamp += cur_samps;
1231 if csamp > self.cur_sample {
1232 if self.cur_chunk >= self.chunk_offsets.len() {
1233 return Err(DemuxerError::SeekError);
1234 }
1235 self.last_offset = self.chunk_offsets[self.cur_chunk];
1236 break;
1237 }
1238 self.cur_chunk += 1;
1239 }
1240 self.samples_left = csamp - self.cur_sample;
1241 self.cur_chunk += 1;
1242 }
1243 } else {
1244 self.cur_chunk = self.cur_sample;
1245 }
1246 } else {
1247 self.cur_chunk = self.cur_sample;
1248 }
1249 } else if self.chunk_offsets.len() != self.chunk_sizes.len() && !self.sample_map.is_empty() {
1250 let mut csamp = 0;
1251 self.cur_chunk = 0;
1252 let mut cmap = self.sample_map.iter();
1253 let mut cur_samps = 0;
1254 let (mut next_idx, mut next_samples) = cmap.next().unwrap();
1255 loop {
1256 if self.cur_chunk + 1 == next_idx as usize {
1257 self.samples_left = cur_samps;
1258 cur_samps = next_samples as usize;
1259 if let Some((new_idx, new_samples)) = cmap.next() {
1260 next_idx = *new_idx;
1261 next_samples = *new_samples;
1262 }
1263 }
1264 csamp += cur_samps;
1265 if csamp >= self.cur_sample {
1266 if self.cur_chunk >= self.chunk_offsets.len() {
1267 return Err(DemuxerError::SeekError);
1268 }
1269 self.last_offset = self.chunk_offsets[self.cur_chunk];
1270 break;
1271 }
1272 self.cur_chunk += 1;
1273 }
1274 csamp -= cur_samps;
1275 for sample_no in csamp..self.cur_sample {
1276 self.last_offset += self.get_size(sample_no) as u64;
1277 }
1278 self.samples_left = csamp + cur_samps - self.cur_sample;
1279 self.cur_chunk += 1;
1280 }
1281 Ok(())
1282 }
1283 }
1284
1285 impl<'a> DemuxCore<'a> for MOVDemuxer<'a> {
1286 fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
1287 self.read_root(strmgr)?;
1288 validate!(self.mdat_pos > 0);
1289 validate!(!self.tracks.is_empty());
1290 for track in self.tracks.iter() {
1291 track.fill_seek_index(seek_index);
1292 }
1293 self.src.seek(SeekFrom::Start(self.mdat_pos))?;
1294 self.cur_track = 0;
1295 Ok(())
1296 }
1297
1298 fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
1299 if self.tracks.is_empty() {
1300 return Err(DemuxerError::EOF);
1301 }
1302 for _ in 0..self.tracks.len() {
1303 if self.cur_track >= self.tracks.len() {
1304 self.cur_track = 0;
1305 }
1306 let track = &mut self.tracks[self.cur_track];
1307 self.cur_track += 1;
1308 let first = track.cur_sample == 0;
1309 if let Some((pts, offset, size)) = track.get_next_chunk() {
1310 let str = strmgr.get_stream(track.track_str_id);
1311 if str.is_none() { return Err(DemuxerError::InvalidData); }
1312 let stream = str.unwrap();
1313 self.src.seek(SeekFrom::Start(offset))?;
1314 let mut pkt = self.src.read_packet(stream, pts, false, size)?;
1315 if let Some(ref pal) = track.pal {
1316 let side_data = NASideData::Palette(first, pal.clone());
1317 pkt.add_side_data(side_data);
1318 }
1319 return Ok(pkt);
1320 }
1321 }
1322 Err(DemuxerError::EOF)
1323 }
1324
1325 fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
1326 let ret = seek_index.find_pos(time);
1327 if ret.is_none() {
1328 return Err(DemuxerError::SeekError);
1329 }
1330 let seek_info = ret.unwrap();
1331 for track in self.tracks.iter_mut() {
1332 track.seek(seek_info.pts, time)?;
1333 }
1334 Ok(())
1335 }
1336 fn get_duration(&self) -> u64 {
1337 if self.tb_den != 0 {
1338 u64::from(self.duration) * 1000 / u64::from(self.tb_den)
1339 } else {
1340 0
1341 }
1342 }
1343 }
1344
1345 const PRINT_CHUNKS: &str = "print_chunks";
1346
1347 const DEMUXER_OPTIONS: &[NAOptionDefinition] = &[
1348 NAOptionDefinition {
1349 name: PRINT_CHUNKS,
1350 description: "Print parsed file structure",
1351 opt_type: NAOptionDefinitionType::Bool },
1352 ];
1353
1354 impl<'a> NAOptionHandler for MOVDemuxer<'a> {
1355 fn get_supported_options(&self) -> &[NAOptionDefinition] { DEMUXER_OPTIONS }
1356 fn set_options(&mut self, options: &[NAOption]) {
1357 for option in options.iter() {
1358 for opt_def in DEMUXER_OPTIONS.iter() {
1359 if opt_def.check(option).is_ok() {
1360 match (option.name, &option.value) {
1361 (PRINT_CHUNKS, NAValue::Bool(val)) => {
1362 self.print_chunks = *val;
1363 },
1364 _ => {},
1365 }
1366 }
1367 }
1368 }
1369 }
1370 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1371 match name {
1372 PRINT_CHUNKS => Some(NAValue::Bool(self.print_chunks)),
1373 _ => None,
1374 }
1375 }
1376 }
1377
1378 impl<'a> MOVDemuxer<'a> {
1379 fn new(io: &'a mut ByteReader<'a>) -> Self {
1380 MOVDemuxer {
1381 src: io,
1382 depth: 0,
1383 mdat_pos: 0,
1384 mdat_size: 0,
1385 tracks: Vec::with_capacity(2),
1386 cur_track: 0,
1387 tb_den: 0,
1388 duration: 0,
1389 pal: None,
1390
1391 print_chunks: false,
1392 }
1393 }
1394 fn read_root(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<()> {
1395 self.depth = 0;
1396 while self.src.left() != 0 {
1397 let ret = read_chunk_header(&mut self.src);
1398 if ret.is_err() { break; }
1399 let (ctype, size) = ret.unwrap();
1400 if IGNORED_CHUNKS.contains(&ctype) {
1401 self.src.skip64(size)?;
1402 continue;
1403 }
1404 let handler = ROOT_CHUNK_HANDLERS.iter().find(|x| x.ctype == ctype);
1405 let read_size;
1406 if let Some(ref handler) = handler {
1407 read_size = (handler.parse)(self, strmgr, size)?;
1408 } else {
1409 println!("skipping unknown chunk {:08X} size {}", ctype, size);
1410 read_size = 0;
1411 }
1412 validate!(read_size <= size);
1413 self.src.skip64(size - read_size)?;
1414 }
1415 //todo check if all needed chunks are found
1416 Ok(())
1417 }
1418 read_chunk_list!(root; "moov", read_moov, MOOV_CHUNK_HANDLERS);
1419 }
1420
1421 pub struct MOVDemuxerCreator { }
1422
1423 impl DemuxerCreator for MOVDemuxerCreator {
1424 fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
1425 Box::new(MOVDemuxer::new(br))
1426 }
1427 fn get_name(&self) -> &'static str { "mov" }
1428 }
1429
1430 const MOV_DEFAULT_PAL_2BIT: [u8; 4 * 4] = [
1431 0x93, 0x65, 0x5E, 0x00,
1432 0xFF, 0xFF, 0xFF, 0x00,
1433 0xDF, 0xD0, 0xAB, 0x00,
1434 0x00, 0x00, 0x00, 0x00
1435 ];
1436 const MOV_DEFAULT_PAL_4BIT: [u8; 16 * 4] = [
1437 0xFF, 0xFB, 0xFF, 0x00,
1438 0xEF, 0xD9, 0xBB, 0x00,
1439 0xE8, 0xC9, 0xB1, 0x00,
1440 0x93, 0x65, 0x5E, 0x00,
1441 0xFC, 0xDE, 0xE8, 0x00,
1442 0x9D, 0x88, 0x91, 0x00,
1443 0xFF, 0xFF, 0xFF, 0x00,
1444 0xFF, 0xFF, 0xFF, 0x00,
1445 0xFF, 0xFF, 0xFF, 0x00,
1446 0x47, 0x48, 0x37, 0x00,
1447 0x7A, 0x5E, 0x55, 0x00,
1448 0xDF, 0xD0, 0xAB, 0x00,
1449 0xFF, 0xFB, 0xF9, 0x00,
1450 0xE8, 0xCA, 0xC5, 0x00,
1451 0x8A, 0x7C, 0x77, 0x00,
1452 0x00, 0x00, 0x00, 0x00
1453 ];
1454 const MOV_DEFAULT_PAL_8BIT: [u8; 256 * 4] = [
1455 0xFF, 0xFF, 0xFF, 0x00,
1456 0xFF, 0xFF, 0xCC, 0x00,
1457 0xFF, 0xFF, 0x99, 0x00,
1458 0xFF, 0xFF, 0x66, 0x00,
1459 0xFF, 0xFF, 0x33, 0x00,
1460 0xFF, 0xFF, 0x00, 0x00,
1461 0xFF, 0xCC, 0xFF, 0x00,
1462 0xFF, 0xCC, 0xCC, 0x00,
1463 0xFF, 0xCC, 0x99, 0x00,
1464 0xFF, 0xCC, 0x66, 0x00,
1465 0xFF, 0xCC, 0x33, 0x00,
1466 0xFF, 0xCC, 0x00, 0x00,
1467 0xFF, 0x99, 0xFF, 0x00,
1468 0xFF, 0x99, 0xCC, 0x00,
1469 0xFF, 0x99, 0x99, 0x00,
1470 0xFF, 0x99, 0x66, 0x00,
1471 0xFF, 0x99, 0x33, 0x00,
1472 0xFF, 0x99, 0x00, 0x00,
1473 0xFF, 0x66, 0xFF, 0x00,
1474 0xFF, 0x66, 0xCC, 0x00,
1475 0xFF, 0x66, 0x99, 0x00,
1476 0xFF, 0x66, 0x66, 0x00,
1477 0xFF, 0x66, 0x33, 0x00,
1478 0xFF, 0x66, 0x00, 0x00,
1479 0xFF, 0x33, 0xFF, 0x00,
1480 0xFF, 0x33, 0xCC, 0x00,
1481 0xFF, 0x33, 0x99, 0x00,
1482 0xFF, 0x33, 0x66, 0x00,
1483 0xFF, 0x33, 0x33, 0x00,
1484 0xFF, 0x33, 0x00, 0x00,
1485 0xFF, 0x00, 0xFF, 0x00,
1486 0xFF, 0x00, 0xCC, 0x00,
1487 0xFF, 0x00, 0x99, 0x00,
1488 0xFF, 0x00, 0x66, 0x00,
1489 0xFF, 0x00, 0x33, 0x00,
1490 0xFF, 0x00, 0x00, 0x00,
1491 0xCC, 0xFF, 0xFF, 0x00,
1492 0xCC, 0xFF, 0xCC, 0x00,
1493 0xCC, 0xFF, 0x99, 0x00,
1494 0xCC, 0xFF, 0x66, 0x00,
1495 0xCC, 0xFF, 0x33, 0x00,
1496 0xCC, 0xFF, 0x00, 0x00,
1497 0xCC, 0xCC, 0xFF, 0x00,
1498 0xCC, 0xCC, 0xCC, 0x00,
1499 0xCC, 0xCC, 0x99, 0x00,
1500 0xCC, 0xCC, 0x66, 0x00,
1501 0xCC, 0xCC, 0x33, 0x00,
1502 0xCC, 0xCC, 0x00, 0x00,
1503 0xCC, 0x99, 0xFF, 0x00,
1504 0xCC, 0x99, 0xCC, 0x00,
1505 0xCC, 0x99, 0x99, 0x00,
1506 0xCC, 0x99, 0x66, 0x00,
1507 0xCC, 0x99, 0x33, 0x00,
1508 0xCC, 0x99, 0x00, 0x00,
1509 0xCC, 0x66, 0xFF, 0x00,
1510 0xCC, 0x66, 0xCC, 0x00,
1511 0xCC, 0x66, 0x99, 0x00,
1512 0xCC, 0x66, 0x66, 0x00,
1513 0xCC, 0x66, 0x33, 0x00,
1514 0xCC, 0x66, 0x00, 0x00,
1515 0xCC, 0x33, 0xFF, 0x00,
1516 0xCC, 0x33, 0xCC, 0x00,
1517 0xCC, 0x33, 0x99, 0x00,
1518 0xCC, 0x33, 0x66, 0x00,
1519 0xCC, 0x33, 0x33, 0x00,
1520 0xCC, 0x33, 0x00, 0x00,
1521 0xCC, 0x00, 0xFF, 0x00,
1522 0xCC, 0x00, 0xCC, 0x00,
1523 0xCC, 0x00, 0x99, 0x00,
1524 0xCC, 0x00, 0x66, 0x00,
1525 0xCC, 0x00, 0x33, 0x00,
1526 0xCC, 0x00, 0x00, 0x00,
1527 0x99, 0xFF, 0xFF, 0x00,
1528 0x99, 0xFF, 0xCC, 0x00,
1529 0x99, 0xFF, 0x99, 0x00,
1530 0x99, 0xFF, 0x66, 0x00,
1531 0x99, 0xFF, 0x33, 0x00,
1532 0x99, 0xFF, 0x00, 0x00,
1533 0x99, 0xCC, 0xFF, 0x00,
1534 0x99, 0xCC, 0xCC, 0x00,
1535 0x99, 0xCC, 0x99, 0x00,
1536 0x99, 0xCC, 0x66, 0x00,
1537 0x99, 0xCC, 0x33, 0x00,
1538 0x99, 0xCC, 0x00, 0x00,
1539 0x99, 0x99, 0xFF, 0x00,
1540 0x99, 0x99, 0xCC, 0x00,
1541 0x99, 0x99, 0x99, 0x00,
1542 0x99, 0x99, 0x66, 0x00,
1543 0x99, 0x99, 0x33, 0x00,
1544 0x99, 0x99, 0x00, 0x00,
1545 0x99, 0x66, 0xFF, 0x00,
1546 0x99, 0x66, 0xCC, 0x00,
1547 0x99, 0x66, 0x99, 0x00,
1548 0x99, 0x66, 0x66, 0x00,
1549 0x99, 0x66, 0x33, 0x00,
1550 0x99, 0x66, 0x00, 0x00,
1551 0x99, 0x33, 0xFF, 0x00,
1552 0x99, 0x33, 0xCC, 0x00,
1553 0x99, 0x33, 0x99, 0x00,
1554 0x99, 0x33, 0x66, 0x00,
1555 0x99, 0x33, 0x33, 0x00,
1556 0x99, 0x33, 0x00, 0x00,
1557 0x99, 0x00, 0xFF, 0x00,
1558 0x99, 0x00, 0xCC, 0x00,
1559 0x99, 0x00, 0x99, 0x00,
1560 0x99, 0x00, 0x66, 0x00,
1561 0x99, 0x00, 0x33, 0x00,
1562 0x99, 0x00, 0x00, 0x00,
1563 0x66, 0xFF, 0xFF, 0x00,
1564 0x66, 0xFF, 0xCC, 0x00,
1565 0x66, 0xFF, 0x99, 0x00,
1566 0x66, 0xFF, 0x66, 0x00,
1567 0x66, 0xFF, 0x33, 0x00,
1568 0x66, 0xFF, 0x00, 0x00,
1569 0x66, 0xCC, 0xFF, 0x00,
1570 0x66, 0xCC, 0xCC, 0x00,
1571 0x66, 0xCC, 0x99, 0x00,
1572 0x66, 0xCC, 0x66, 0x00,
1573 0x66, 0xCC, 0x33, 0x00,
1574 0x66, 0xCC, 0x00, 0x00,
1575 0x66, 0x99, 0xFF, 0x00,
1576 0x66, 0x99, 0xCC, 0x00,
1577 0x66, 0x99, 0x99, 0x00,
1578 0x66, 0x99, 0x66, 0x00,
1579 0x66, 0x99, 0x33, 0x00,
1580 0x66, 0x99, 0x00, 0x00,
1581 0x66, 0x66, 0xFF, 0x00,
1582 0x66, 0x66, 0xCC, 0x00,
1583 0x66, 0x66, 0x99, 0x00,
1584 0x66, 0x66, 0x66, 0x00,
1585 0x66, 0x66, 0x33, 0x00,
1586 0x66, 0x66, 0x00, 0x00,
1587 0x66, 0x33, 0xFF, 0x00,
1588 0x66, 0x33, 0xCC, 0x00,
1589 0x66, 0x33, 0x99, 0x00,
1590 0x66, 0x33, 0x66, 0x00,
1591 0x66, 0x33, 0x33, 0x00,
1592 0x66, 0x33, 0x00, 0x00,
1593 0x66, 0x00, 0xFF, 0x00,
1594 0x66, 0x00, 0xCC, 0x00,
1595 0x66, 0x00, 0x99, 0x00,
1596 0x66, 0x00, 0x66, 0x00,
1597 0x66, 0x00, 0x33, 0x00,
1598 0x66, 0x00, 0x00, 0x00,
1599 0x33, 0xFF, 0xFF, 0x00,
1600 0x33, 0xFF, 0xCC, 0x00,
1601 0x33, 0xFF, 0x99, 0x00,
1602 0x33, 0xFF, 0x66, 0x00,
1603 0x33, 0xFF, 0x33, 0x00,
1604 0x33, 0xFF, 0x00, 0x00,
1605 0x33, 0xCC, 0xFF, 0x00,
1606 0x33, 0xCC, 0xCC, 0x00,
1607 0x33, 0xCC, 0x99, 0x00,
1608 0x33, 0xCC, 0x66, 0x00,
1609 0x33, 0xCC, 0x33, 0x00,
1610 0x33, 0xCC, 0x00, 0x00,
1611 0x33, 0x99, 0xFF, 0x00,
1612 0x33, 0x99, 0xCC, 0x00,
1613 0x33, 0x99, 0x99, 0x00,
1614 0x33, 0x99, 0x66, 0x00,
1615 0x33, 0x99, 0x33, 0x00,
1616 0x33, 0x99, 0x00, 0x00,
1617 0x33, 0x66, 0xFF, 0x00,
1618 0x33, 0x66, 0xCC, 0x00,
1619 0x33, 0x66, 0x99, 0x00,
1620 0x33, 0x66, 0x66, 0x00,
1621 0x33, 0x66, 0x33, 0x00,
1622 0x33, 0x66, 0x00, 0x00,
1623 0x33, 0x33, 0xFF, 0x00,
1624 0x33, 0x33, 0xCC, 0x00,
1625 0x33, 0x33, 0x99, 0x00,
1626 0x33, 0x33, 0x66, 0x00,
1627 0x33, 0x33, 0x33, 0x00,
1628 0x33, 0x33, 0x00, 0x00,
1629 0x33, 0x00, 0xFF, 0x00,
1630 0x33, 0x00, 0xCC, 0x00,
1631 0x33, 0x00, 0x99, 0x00,
1632 0x33, 0x00, 0x66, 0x00,
1633 0x33, 0x00, 0x33, 0x00,
1634 0x33, 0x00, 0x00, 0x00,
1635 0x00, 0xFF, 0xFF, 0x00,
1636 0x00, 0xFF, 0xCC, 0x00,
1637 0x00, 0xFF, 0x99, 0x00,
1638 0x00, 0xFF, 0x66, 0x00,
1639 0x00, 0xFF, 0x33, 0x00,
1640 0x00, 0xFF, 0x00, 0x00,
1641 0x00, 0xCC, 0xFF, 0x00,
1642 0x00, 0xCC, 0xCC, 0x00,
1643 0x00, 0xCC, 0x99, 0x00,
1644 0x00, 0xCC, 0x66, 0x00,
1645 0x00, 0xCC, 0x33, 0x00,
1646 0x00, 0xCC, 0x00, 0x00,
1647 0x00, 0x99, 0xFF, 0x00,
1648 0x00, 0x99, 0xCC, 0x00,
1649 0x00, 0x99, 0x99, 0x00,
1650 0x00, 0x99, 0x66, 0x00,
1651 0x00, 0x99, 0x33, 0x00,
1652 0x00, 0x99, 0x00, 0x00,
1653 0x00, 0x66, 0xFF, 0x00,
1654 0x00, 0x66, 0xCC, 0x00,
1655 0x00, 0x66, 0x99, 0x00,
1656 0x00, 0x66, 0x66, 0x00,
1657 0x00, 0x66, 0x33, 0x00,
1658 0x00, 0x66, 0x00, 0x00,
1659 0x00, 0x33, 0xFF, 0x00,
1660 0x00, 0x33, 0xCC, 0x00,
1661 0x00, 0x33, 0x99, 0x00,
1662 0x00, 0x33, 0x66, 0x00,
1663 0x00, 0x33, 0x33, 0x00,
1664 0x00, 0x33, 0x00, 0x00,
1665 0x00, 0x00, 0xFF, 0x00,
1666 0x00, 0x00, 0xCC, 0x00,
1667 0x00, 0x00, 0x99, 0x00,
1668 0x00, 0x00, 0x66, 0x00,
1669 0x00, 0x00, 0x33, 0x00,
1670 0xEE, 0x00, 0x00, 0x00,
1671 0xDD, 0x00, 0x00, 0x00,
1672 0xBB, 0x00, 0x00, 0x00,
1673 0xAA, 0x00, 0x00, 0x00,
1674 0x88, 0x00, 0x00, 0x00,
1675 0x77, 0x00, 0x00, 0x00,
1676 0x55, 0x00, 0x00, 0x00,
1677 0x44, 0x00, 0x00, 0x00,
1678 0x22, 0x00, 0x00, 0x00,
1679 0x11, 0x00, 0x00, 0x00,
1680 0x00, 0xEE, 0x00, 0x00,
1681 0x00, 0xDD, 0x00, 0x00,
1682 0x00, 0xBB, 0x00, 0x00,
1683 0x00, 0xAA, 0x00, 0x00,
1684 0x00, 0x88, 0x00, 0x00,
1685 0x00, 0x77, 0x00, 0x00,
1686 0x00, 0x55, 0x00, 0x00,
1687 0x00, 0x44, 0x00, 0x00,
1688 0x00, 0x22, 0x00, 0x00,
1689 0x00, 0x11, 0x00, 0x00,
1690 0x00, 0x00, 0xEE, 0x00,
1691 0x00, 0x00, 0xDD, 0x00,
1692 0x00, 0x00, 0xBB, 0x00,
1693 0x00, 0x00, 0xAA, 0x00,
1694 0x00, 0x00, 0x88, 0x00,
1695 0x00, 0x00, 0x77, 0x00,
1696 0x00, 0x00, 0x55, 0x00,
1697 0x00, 0x00, 0x44, 0x00,
1698 0x00, 0x00, 0x22, 0x00,
1699 0x00, 0x00, 0x11, 0x00,
1700 0xEE, 0xEE, 0xEE, 0x00,
1701 0xDD, 0xDD, 0xDD, 0x00,
1702 0xBB, 0xBB, 0xBB, 0x00,
1703 0xAA, 0xAA, 0xAA, 0x00,
1704 0x88, 0x88, 0x88, 0x00,
1705 0x77, 0x77, 0x77, 0x00,
1706 0x55, 0x55, 0x55, 0x00,
1707 0x44, 0x44, 0x44, 0x00,
1708 0x22, 0x22, 0x22, 0x00,
1709 0x11, 0x11, 0x11, 0x00,
1710 0x00, 0x00, 0x00, 0x00
1711 ];
1712
1713 #[cfg(test)]
1714 mod test {
1715 use super::*;
1716 use std::fs::File;
1717
1718 #[test]
1719 fn test_mov_demux() {
1720 let mut file = File::open("assets/Indeo/cubes.mov").unwrap();
1721 let mut fr = FileReader::new_read(&mut file);
1722 let mut br = ByteReader::new(&mut fr);
1723 let mut dmx = MOVDemuxer::new(&mut br);
1724 let mut sm = StreamManager::new();
1725 let mut si = SeekIndex::new();
1726 dmx.open(&mut sm, &mut si).unwrap();
1727
1728 loop {
1729 let pktres = dmx.get_frame(&mut sm);
1730 if let Err(e) = pktres {
1731 if e == DemuxerError::EOF { break; }
1732 panic!("error");
1733 }
1734 let pkt = pktres.unwrap();
1735 println!("Got {}", pkt);
1736 }
1737 }
1738 }